From 1b3bc64d7388f1099944ffc0f3cb60e2008f36eb Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 09:36:41 +0200 Subject: [PATCH 01/31] feat: initial SR implementation - added SR files - fixed imports and go.mods - in processor.go, init.go, logging.go changed the flow callbacks logic --- .editorconfig | 3 +- .github/workflows/libs/pr.yaml | 198 - .github/workflows/libs/push.yaml | 90 - .github/workflows/{products => }/pr.yaml | 77 +- .github/workflows/{products => }/push.yaml | 16 +- .golangci.yaml | 12 +- .hadolint.yaml | 19 + README.md | 46 + registry/README.md | 221 + registry/cmd/initdb/initdb.go | 56 + registry/cmd/janitorsr-firestore/main.go | 129 + registry/cmd/janitorsr/main.go | 144 + registry/cmd/sr-cli/main.go | 159 + .../cmd/sr-cli/testdata/avro/schema-1.avsc | 62 + .../cmd/sr-cli/testdata/json/schema-1.json | 21 + .../cmd/sr-cli/testdata/json/schema-10.json | 7505 +++++++++++++++++ .../cmd/sr-cli/testdata/json/schema-2.json | 34 + .../cmd/sr-cli/testdata/json/schema-3.json | 41 + .../cmd/sr-cli/testdata/json/schema-4.json | 253 + .../cmd/sr-cli/testdata/json/schema-5.json | 157 + .../cmd/sr-cli/testdata/json/schema-6.json | 546 ++ .../cmd/sr-cli/testdata/json/schema-7.json | 243 + .../cmd/sr-cli/testdata/json/schema-8.json | 57 + .../cmd/sr-cli/testdata/json/schema-9.json | 127 + registry/compatibility/checker.go | 11 + registry/compatibility/checker_test.go | 105 + ...egistry-schema-util-common-2.3.1.Final.jar | Bin 0 -> 18965 bytes ...-registry-schema-util-json-2.3.1.Final.jar | Bin 0 -> 94141 bytes ...istry-schema-util-protobuf-2.3.1.Final.jar | Bin 0 -> 17274 bytes .../kafka-schema-registry-client-7.2.1.jar | Bin 0 -> 193861 bytes .../external/compatibility-checker/pom.xml | 252 + .../syntio/compatibility/CheckerFactory.java | 17 + .../CompatibilityCheckerApplication.java | 15 + .../net/syntio/compatibility/FileTypes.java | 7 + .../net/syntio/compatibility/Message.java | 26 + .../compatibility/checker/AvroChecker.java | 40 + .../syntio/compatibility/checker/Checker.java | 24 + .../checker/CompatibilityChecker.java | 10 + .../compatibility/checker/JsonChecker.java | 15 + .../checker/ProtobufChecker.java | 15 + .../controller/CheckerController.java | 69 + .../compatibility/dto/CheckRequestDto.java | 48 + .../compatibility/dto/CheckResponseDto.java | 22 + registry/compatibility/externalChecker.go | 131 + registry/compatibility/http/http.go | 92 + .../testdata/backward_avro_false/schema1.json | 5 + .../testdata/backward_avro_false/schema2.json | 5 + .../testdata/backward_avro_true/schema1.json | 5 + .../testdata/backward_avro_true/schema2.json | 5 + .../testdata/backward_json_false/schema1.json | 5 + .../testdata/backward_json_false/schema2.json | 5 + .../testdata/backward_json_true/schema1.json | 5 + .../testdata/backward_json_true/schema2.json | 5 + .../testdata/compatible_avro_back1.json | 4 + .../testdata/compatible_json_back1.json | 4 + .../testdata/forward_avro_false/schema1.json | 5 + .../testdata/forward_avro_false/schema2.json | 5 + .../testdata/forward_avro_true/schema1.json | 5 + .../testdata/forward_avro_true/schema2.json | 5 + .../testdata/forward_json_false/schema1.json | 5 + .../testdata/forward_json_false/schema2.json | 5 + .../testdata/forward_json_true/schema1.json | 5 + .../testdata/forward_json_true/schema2.json | 5 + .../testdata/incompatible_avro_back1.json | 4 + .../testdata/incompatible_json_back1.json | 4 + .../docker/compatibility-checker/Dockerfile | 37 + registry/docker/initdb/Dockerfile | 36 + registry/docker/registry-firestore/Dockerfile | 38 + registry/docker/registry/Dockerfile | 39 + registry/docker/validity-checker/Dockerfile | 37 + registry/docs/docs.go | 491 ++ registry/docs/swagger.json | 463 + registry/docs/swagger.yaml | 300 + registry/go.mod | 84 + registry/go.sum | 2125 +++++ registry/internal/config/logger.go | 41 + registry/internal/errcodes/errcodes.go | 24 + .../internal/errtemplates/errtemplates.go | 27 + registry/internal/metrics/metrics.go | 49 + registry/licenses/LICENSE-3RD-PARTY.md | 76 + .../LICENSE-3RD-PARTY.md | 127 + .../validity-checker/LICENSE-3RD-PARTY.md | 128 + registry/registry/cache.go | 92 + registry/registry/cache_test.go | 82 + registry/registry/internal/hashutils/hash.go | 13 + registry/registry/mock.go | 211 + registry/registry/model.go | 65 + registry/registry/repo.go | 29 + .../repository/firestore/firestore.go | 328 + .../registry/repository/firestore/model.go | 87 + registry/registry/repository/postgres/env.go | 58 + registry/registry/repository/postgres/gorm.go | 38 + .../registry/repository/postgres/initdb.go | 21 + .../registry/repository/postgres/model.go | 69 + .../registry/repository/postgres/postgres.go | 291 + .../repository/postgres/postgres_test.go | 54 + registry/registry/schema.go | 448 + registry/registry/schema_test.go | 116 + .../testdata/avro/canonical-schema.avsc | 1 + registry/registry/testdata/avro/schema-1.avsc | 48 + registry/registry/testdata/avro/schema-2.avsc | 39 + .../testdata/json/canonical-schema.json | 1 + registry/registry/testdata/json/schema-1.json | 32 + registry/registry/testdata/json/schema-2.json | 32 + registry/server/handler.go | 887 ++ registry/server/log.go | 44 + registry/server/server.go | 66 + registry/server/util.go | 81 + registry/validity/checker.go | 11 + registry/validity/checker_test.go | 89 + .../apicurio-registry-common-2.2.5.Final.jar | Bin 0 -> 118628 bytes ...-protobuf-schema-utilities-2.2.5.Final.jar | Bin 0 -> 499104 bytes ...-registry-schema-util-avro-2.2.5.Final.jar | Bin 0 -> 11850 bytes ...egistry-schema-util-common-2.2.5.Final.jar | Bin 0 -> 18968 bytes ...-registry-schema-util-json-2.2.5.Final.jar | Bin 0 -> 94144 bytes ...istry-schema-util-protobuf-2.2.5.Final.jar | Bin 0 -> 17277 bytes ...o-registry-schema-util-xml-2.2.5.Final.jar | Bin 0 -> 7496 bytes ...o-registry-schema-util-xsd-2.2.5.Final.jar | Bin 0 -> 5046 bytes .../external/validity-checker/pom.xml | 250 + .../java/net/syntio/validity/Message.java | 25 + .../java/net/syntio/validity/SchemaTypes.java | 9 + .../net/syntio/validity/ValidatorFactory.java | 20 + .../validity/ValidityCheckerApplication.java | 16 + .../net/syntio/validity/checker/Checker.java | 30 + .../controller/CheckerController.java | 44 + .../syntio/validity/dto/CheckRequestDto.java | 16 + .../syntio/validity/dto/CheckResponseDto.java | 22 + registry/validity/externalChecker.go | 139 + registry/validity/http/http.go | 91 + .../validity/testdata/invalid_avro_full1.json | 3 + .../testdata/invalid_avro_syntax1.json | 3 + .../validity/testdata/invalid_json_full1.json | 3 + .../testdata/invalid_json_syntax1.json | 3 + .../validity/testdata/valid_avro_full1.json | 3 + .../validity/testdata/valid_json_syntax1.json | 3 + validator/README.md | 270 + validator/cmd/centralconsumer/main.go | 20 + validator/cmd/pullercleaner/main.go | 20 + validator/config/validator.toml | 60 + validator/docker/csv-validator/Dockerfile | 41 + validator/docker/validator/Dockerfile | 37 + validator/docker/xml-validator/Dockerfile | 28 + validator/go.mod | 115 + validator/go.sum | 918 ++ .../centralconsumer/centralconsumer.go | 463 + .../centralconsumer/centralconsumer_test.go | 185 + .../centralconsumer/testdata/data-1.json | 3 + .../centralconsumer/testdata/data-2.json | 4 + .../centralconsumer/testdata/data-3.json | 5 + .../centralconsumer/testdata/schema-1.json | 21 + .../centralconsumer/testdata/schema-2.json | 22 + .../centralconsumer/testdata/schema-3.json | 22 + validator/internal/config/centralconsumer.go | 67 + validator/internal/config/config.go | 406 + validator/internal/config/logger.go | 40 + validator/internal/config/pullercleaner.go | 50 + validator/internal/errcodes/errcodes.go | 68 + .../internal/errtemplates/errtemplates.go | 88 + .../internal/errtemplates/valtemplates.go | 31 + validator/internal/janitor/cleaner.go | 140 + validator/internal/janitor/encryption.go | 58 + validator/internal/janitor/encryption_test.go | 24 + validator/internal/janitor/error.go | 51 + validator/internal/janitor/error_test.go | 45 + validator/internal/janitor/janitor.go | 202 + validator/internal/janitor/janitor_test.go | 167 + validator/internal/janitor/logging.go | 102 + validator/internal/janitor/logging_test.go | 80 + validator/internal/janitor/metrics.go | 104 + validator/internal/janitor/parse.go | 75 + validator/internal/janitor/processor.go | 225 + validator/internal/janitorctl/init.go | 747 ++ validator/internal/janitorctl/metrics.go | 32 + validator/internal/janitorctl/run.go | 215 + validator/internal/producer/config.go | 216 + validator/internal/producer/load.go | 238 + validator/internal/producer/producer.go | 124 + validator/internal/producer/producer_test.go | 69 + validator/internal/producer/run.go | 175 + .../internal/producer/testdata/data-1.json | 5 + .../internal/producer/testdata/data-2.json | 13 + .../internal/producer/testdata/dataset.csv | 2 + .../internal/producer/testdata/schema-1.json | 21 + .../internal/producer/testdata/schema-2.json | 34 + validator/internal/publisher/mock.go | 21 + .../internal/pullercleaner/pullercleaner.go | 149 + .../pullercleaner/pullercleaner_test.go | 42 + .../registry/apicuriosr/apicuriosr.go | 289 + .../registry/apicuriosr/apicuriosr_test.go | 192 + validator/internal/registry/apicuriosr/dto.go | 20 + validator/internal/registry/cache.go | 69 + validator/internal/registry/cache_test.go | 57 + validator/internal/registry/janitorsr/dto.go | 30 + .../internal/registry/janitorsr/janitorsr.go | 286 + .../registry/janitorsr/janitorsr_test.go | 194 + .../registry/janitorsr/testdata/schema.avsc | 35 + .../registry/janitorsr/testdata/schema.csvs | 5 + .../registry/janitorsr/testdata/schema.json | 52 + .../registry/janitorsr/testdata/schema.xsd | 16 + validator/internal/registry/mock.go | 93 + validator/internal/registry/registry.go | 35 + validator/internal/schemagen/cmd.go | 23 + validator/internal/schemagen/cmd_test.go | 19 + validator/internal/schemagen/csv/csv.go | 49 + validator/internal/schemagen/csv/csv_test.go | 63 + .../schemagen/csv/testdata/data-1.csv | 4 + .../csv/testdata/deadletter-1-data.csv | 6 + .../csv/testdata/deadletter-2-data.csv | 4 + .../schemagen/csv/testdata/schema-1.csvs | 5 + validator/internal/schemagen/json/json.go | 16 + .../schemagen/json/json_schema_gen.py | 22 + .../internal/schemagen/json/json_test.go | 62 + .../json/testdata/deadletter-1-data.json | 5 + validator/internal/schemagen/schemagen.go | 22 + validator/internal/validator/avro/avro.go | 30 + .../internal/validator/avro/avro_test.go | 209 + .../invalid-1-serialization-schema.avsc | 22 + .../testdata/invalid-1-validation-schema.avsc | 35 + .../invalid-2-serialization-schema.avsc | 19 + .../testdata/invalid-2-validation-schema.avsc | 11 + .../invalid-3-serialization-schema.avsc | 19 + .../testdata/invalid-3-validation-schema.avsc | 19 + .../invalid-4-serialization-schema.avsc | 19 + .../testdata/invalid-4-validation-schema.avsc | 11 + .../invalid-5-serialization-schema.avsc | 31 + .../testdata/invalid-5-validation-schema.avsc | 11 + .../invalid-6-serialization-schema.avsc | 15 + .../testdata/invalid-6-validation-schema.avsc | 15 + .../invalid-7-serialization-schema.avsc | 11 + .../testdata/invalid-7-validation-schema.avsc | 15 + .../valid-1-serialization-schema.avsc | 35 + .../testdata/valid-1-validation-schema.avsc | 35 + validator/internal/validator/csv/csv.go | 68 + validator/internal/validator/csv/csv_test.go | 121 + .../csv/testdata/deadletter-1-data.csv | 6 + .../csv/testdata/deadletter-1-schema.csvs | 5 + .../csv/testdata/deadletter-2-data.csv | 4 + .../csv/testdata/deadletter-2-schema.csvs | 5 + .../csv/testdata/deadletter-3-data.csv | 4 + .../csv/testdata/deadletter-3-schema.csvs | 5 + .../validator/csv/testdata/invalid-1-data.csv | 4 + .../csv/testdata/invalid-1-schema.csvs | 5 + .../validator/csv/testdata/invalid-2-data.csv | 4 + .../csv/testdata/invalid-2-schema.csvs | 5 + .../validator/csv/testdata/invalid-3-data.csv | 4 + .../csv/testdata/invalid-3-schema.csvs | 5 + .../validator/csv/testdata/valid-1-data.csv | 4 + .../csv/testdata/valid-1-schema.csvs | 5 + .../validator/csv/testdata/valid-2-data.csv | 4 + .../csv/testdata/valid-2-schema.csvs | 5 + .../validator/csv/testdata/valid-3-data.csv | 4 + .../csv/testdata/valid-3-schema.csvs | 5 + .../validator/csv/testdata/valid-4-data.csv | 4 + .../csv/testdata/valid-4-schema.csvs | 5 + .../external/csv-validator/.gitignore | 33 + .../validator/external/csv-validator/pom.xml | 219 + .../csvvalidator/CsvValidatorApplication.java | 12 + .../controller/ValidatorController.java | 37 + .../dto/ValidationRequestDto.java | 19 + .../dto/ValidatorResponseDto.java | 22 + .../csvvalidator/validator/CsvValidator.java | 21 + .../CsvValidatorApplicationTests.java | 13 + .../external/xml-validator/cloudbuild.yaml | 5 + .../validator/external/xml-validator/main.py | 57 + .../external/xml-validator/requirements.txt | 11 + validator/internal/validator/http.go | 85 + validator/internal/validator/http_test.go | 120 + validator/internal/validator/json/json.go | 133 + .../internal/validator/json/json_test.go | 301 + .../validator/json/testdata/data-1.json | 5 + .../validator/json/testdata/data-2.json | 13 + .../validator/json/testdata/data-3.json | 13 + .../validator/json/testdata/data-4.json | 100 + .../json/testdata/deadletter-1-data.json | 5 + .../json/testdata/deadletter-1-schema.json | 52 + .../json/testdata/deadletter-2-data.json | 6 + .../json/testdata/deadletter-2-schema.json | 50 + .../json/testdata/invalid-1-data.json | 7 + .../json/testdata/invalid-1-schema.json | 72 + .../json/testdata/invalid-2-data.json | 9 + .../json/testdata/invalid-2-schema.json | 72 + .../json/testdata/invalid-3-data.json | 16 + .../json/testdata/invalid-3-schema.json | 72 + .../json/testdata/invalid-4-data.json | 7 + .../json/testdata/invalid-4-schema.json | 74 + .../validator/json/testdata/ref-1-child.json | 48 + .../validator/json/testdata/ref-1.json | 26 + .../validator/json/testdata/ref-2-child.json | 16 + .../validator/json/testdata/ref-2.json | 26 + .../validator/json/testdata/ref-3-child.json | 22 + .../validator/json/testdata/ref-3.json | 21 + .../validator/json/testdata/ref-data-1.json | 10 + .../validator/json/testdata/ref-data-2.json | 4 + .../validator/json/testdata/ref-data-3.json | 7 + .../validator/json/testdata/schema-1.json | 21 + .../validator/json/testdata/schema-2.json | 34 + .../validator/json/testdata/schema-3.json | 41 + .../validator/json/testdata/schema-4.json | 253 + .../validator/json/testdata/valid-1-data.json | 6 + .../json/testdata/valid-1-schema.json | 52 + .../validator/json/testdata/valid-2-data.json | 6 + .../json/testdata/valid-2-schema.json | 52 + .../validator/json/testdata/valid-3-data.json | 6 + .../json/testdata/valid-3-schema.json | 52 + .../validator/json/testdata/valid-4-data.json | 6 + .../json/testdata/valid-4-schema.json | 52 + .../internal/validator/protobuf/protobuf.go | 170 + .../validator/protobuf/protobuf_test.go | 340 + .../validator/protobuf/testdata/invalid2-1.pb | 2 + .../validator/protobuf/testdata/invalid2-2.pb | 0 .../validator/protobuf/testdata/invalid3-1.pb | 6 + .../protobuf/testdata/person/schema3-2.pb.go | 321 + .../protobuf/testdata/schema2-1.proto | 18 + .../protobuf/testdata/schema3-1.proto | 16 + .../protobuf/testdata/schema3-2.proto | 27 + .../protobuf/testdata/testpb2/schema2-1.pb.go | 235 + .../protobuf/testdata/testpb3/schema3-1.pb.go | 236 + .../validator/protobuf/testdata/valid2-1.pb | 3 + .../validator/protobuf/testdata/valid2-2.pb | 3 + .../validator/protobuf/testdata/valid2-3.pb | Bin 0 -> 15 bytes .../validator/protobuf/testdata/valid2-4.pb | 2 + .../validator/protobuf/testdata/valid3-1.pb | 3 + .../validator/protobuf/testdata/valid3-2.pb | 3 + .../validator/protobuf/testdata/valid3-3.pb | Bin 0 -> 15 bytes .../validator/protobuf/testdata/valid3-4.pb | Bin 0 -> 15 bytes .../validator/protobuf/testdata/valid3-5.pb | Bin 0 -> 9 bytes .../validator/protobuf/testdata/valid3-6.pb | Bin 0 -> 8 bytes .../validator/protobuf/testdata/valid3-7.pb | Bin 0 -> 15 bytes .../validator/protobuf/testdata/valid3-8.pb | 6 + validator/internal/validator/validator.go | 37 + .../validator/xml/testdata/data-1.xml | 24 + .../validator/xml/testdata/data-2.xml | 9 + .../validator/xml/testdata/data-3.xml | 7 + .../xml/testdata/deadletter-1-data.xml | 7 + .../xml/testdata/deadletter-1-schema.xsd | 16 + .../xml/testdata/deadletter-2-data.xml | 7 + .../xml/testdata/deadletter-2-schema.xsd | 15 + .../xml/testdata/deadletter-3-data.xml | 8 + .../xml/testdata/deadletter-3-schema.xsd | 16 + .../validator/xml/testdata/invalid-1-data.xml | 9 + .../xml/testdata/invalid-1-schema.xsd | 16 + .../validator/xml/testdata/invalid-2-data.xml | 5 + .../xml/testdata/invalid-2-schema.xsd | 16 + .../validator/xml/testdata/schema-1.xsd | 33 + .../validator/xml/testdata/schema-2.xsd | 16 + .../validator/xml/testdata/schema-3.xsd | 16 + .../validator/xml/testdata/valid-1-data.xml | 7 + .../validator/xml/testdata/valid-1-schema.xsd | 16 + .../validator/xml/testdata/valid-2-data.xml | 7 + .../validator/xml/testdata/valid-2-schema.xsd | 16 + .../validator/xml/testdata/valid-3-data.xml | 7 + .../validator/xml/testdata/valid-3-schema.xsd | 16 + validator/internal/validator/xml/xml.go | 61 + validator/internal/validator/xml/xml_test.go | 128 + validator/licenses/LICENSE-3RD-PARTY.md | 62 + .../csv-validator/LICENSE-3RD-PARTY.md | 84 + .../xml-validator/LICENSE-3RD-PARTY.md | 29 + 357 files changed, 32396 insertions(+), 329 deletions(-) delete mode 100644 .github/workflows/libs/pr.yaml delete mode 100644 .github/workflows/libs/push.yaml rename .github/workflows/{products => }/pr.yaml (79%) rename .github/workflows/{products => }/push.yaml (88%) create mode 100644 .hadolint.yaml create mode 100644 README.md create mode 100644 registry/README.md create mode 100644 registry/cmd/initdb/initdb.go create mode 100644 registry/cmd/janitorsr-firestore/main.go create mode 100644 registry/cmd/janitorsr/main.go create mode 100644 registry/cmd/sr-cli/main.go create mode 100644 registry/cmd/sr-cli/testdata/avro/schema-1.avsc create mode 100644 registry/cmd/sr-cli/testdata/json/schema-1.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-10.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-2.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-3.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-4.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-5.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-6.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-7.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-8.json create mode 100644 registry/cmd/sr-cli/testdata/json/schema-9.json create mode 100644 registry/compatibility/checker.go create mode 100644 registry/compatibility/checker_test.go create mode 100644 registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-common-2.3.1.Final.jar create mode 100644 registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-json-2.3.1.Final.jar create mode 100644 registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-protobuf-2.3.1.Final.jar create mode 100644 registry/compatibility/external/compatibility-checker/lib/kafka-schema-registry-client-7.2.1.jar create mode 100644 registry/compatibility/external/compatibility-checker/pom.xml create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CheckerFactory.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CompatibilityCheckerApplication.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/FileTypes.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/Message.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/AvroChecker.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/Checker.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/CompatibilityChecker.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/JsonChecker.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/ProtobufChecker.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/controller/CheckerController.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckRequestDto.java create mode 100644 registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckResponseDto.java create mode 100644 registry/compatibility/externalChecker.go create mode 100644 registry/compatibility/http/http.go create mode 100644 registry/compatibility/testdata/backward_avro_false/schema1.json create mode 100644 registry/compatibility/testdata/backward_avro_false/schema2.json create mode 100644 registry/compatibility/testdata/backward_avro_true/schema1.json create mode 100644 registry/compatibility/testdata/backward_avro_true/schema2.json create mode 100644 registry/compatibility/testdata/backward_json_false/schema1.json create mode 100644 registry/compatibility/testdata/backward_json_false/schema2.json create mode 100644 registry/compatibility/testdata/backward_json_true/schema1.json create mode 100644 registry/compatibility/testdata/backward_json_true/schema2.json create mode 100644 registry/compatibility/testdata/compatible_avro_back1.json create mode 100644 registry/compatibility/testdata/compatible_json_back1.json create mode 100644 registry/compatibility/testdata/forward_avro_false/schema1.json create mode 100644 registry/compatibility/testdata/forward_avro_false/schema2.json create mode 100644 registry/compatibility/testdata/forward_avro_true/schema1.json create mode 100644 registry/compatibility/testdata/forward_avro_true/schema2.json create mode 100644 registry/compatibility/testdata/forward_json_false/schema1.json create mode 100644 registry/compatibility/testdata/forward_json_false/schema2.json create mode 100644 registry/compatibility/testdata/forward_json_true/schema1.json create mode 100644 registry/compatibility/testdata/forward_json_true/schema2.json create mode 100644 registry/compatibility/testdata/incompatible_avro_back1.json create mode 100644 registry/compatibility/testdata/incompatible_json_back1.json create mode 100644 registry/docker/compatibility-checker/Dockerfile create mode 100644 registry/docker/initdb/Dockerfile create mode 100644 registry/docker/registry-firestore/Dockerfile create mode 100644 registry/docker/registry/Dockerfile create mode 100644 registry/docker/validity-checker/Dockerfile create mode 100644 registry/docs/docs.go create mode 100644 registry/docs/swagger.json create mode 100644 registry/docs/swagger.yaml create mode 100644 registry/go.mod create mode 100644 registry/go.sum create mode 100644 registry/internal/config/logger.go create mode 100644 registry/internal/errcodes/errcodes.go create mode 100644 registry/internal/errtemplates/errtemplates.go create mode 100644 registry/internal/metrics/metrics.go create mode 100644 registry/licenses/LICENSE-3RD-PARTY.md create mode 100644 registry/licenses/compatibility-checker/LICENSE-3RD-PARTY.md create mode 100644 registry/licenses/validity-checker/LICENSE-3RD-PARTY.md create mode 100644 registry/registry/cache.go create mode 100644 registry/registry/cache_test.go create mode 100644 registry/registry/internal/hashutils/hash.go create mode 100644 registry/registry/mock.go create mode 100644 registry/registry/model.go create mode 100644 registry/registry/repo.go create mode 100644 registry/registry/repository/firestore/firestore.go create mode 100644 registry/registry/repository/firestore/model.go create mode 100644 registry/registry/repository/postgres/env.go create mode 100644 registry/registry/repository/postgres/gorm.go create mode 100644 registry/registry/repository/postgres/initdb.go create mode 100644 registry/registry/repository/postgres/model.go create mode 100644 registry/registry/repository/postgres/postgres.go create mode 100644 registry/registry/repository/postgres/postgres_test.go create mode 100644 registry/registry/schema.go create mode 100644 registry/registry/schema_test.go create mode 100644 registry/registry/testdata/avro/canonical-schema.avsc create mode 100644 registry/registry/testdata/avro/schema-1.avsc create mode 100644 registry/registry/testdata/avro/schema-2.avsc create mode 100644 registry/registry/testdata/json/canonical-schema.json create mode 100644 registry/registry/testdata/json/schema-1.json create mode 100644 registry/registry/testdata/json/schema-2.json create mode 100644 registry/server/handler.go create mode 100644 registry/server/log.go create mode 100644 registry/server/server.go create mode 100644 registry/server/util.go create mode 100644 registry/validity/checker.go create mode 100644 registry/validity/checker_test.go create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-common-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-protobuf-schema-utilities-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-avro-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-common-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-json-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-protobuf-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xml-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xsd-2.2.5.Final.jar create mode 100644 registry/validity/external/validity-checker/pom.xml create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/Message.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/SchemaTypes.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidatorFactory.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidityCheckerApplication.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/checker/Checker.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/controller/CheckerController.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckRequestDto.java create mode 100644 registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckResponseDto.java create mode 100644 registry/validity/externalChecker.go create mode 100644 registry/validity/http/http.go create mode 100644 registry/validity/testdata/invalid_avro_full1.json create mode 100644 registry/validity/testdata/invalid_avro_syntax1.json create mode 100644 registry/validity/testdata/invalid_json_full1.json create mode 100644 registry/validity/testdata/invalid_json_syntax1.json create mode 100644 registry/validity/testdata/valid_avro_full1.json create mode 100644 registry/validity/testdata/valid_json_syntax1.json create mode 100644 validator/README.md create mode 100644 validator/cmd/centralconsumer/main.go create mode 100644 validator/cmd/pullercleaner/main.go create mode 100644 validator/config/validator.toml create mode 100644 validator/docker/csv-validator/Dockerfile create mode 100644 validator/docker/validator/Dockerfile create mode 100644 validator/docker/xml-validator/Dockerfile create mode 100644 validator/go.mod create mode 100644 validator/go.sum create mode 100644 validator/internal/centralconsumer/centralconsumer.go create mode 100644 validator/internal/centralconsumer/centralconsumer_test.go create mode 100644 validator/internal/centralconsumer/testdata/data-1.json create mode 100644 validator/internal/centralconsumer/testdata/data-2.json create mode 100644 validator/internal/centralconsumer/testdata/data-3.json create mode 100644 validator/internal/centralconsumer/testdata/schema-1.json create mode 100644 validator/internal/centralconsumer/testdata/schema-2.json create mode 100644 validator/internal/centralconsumer/testdata/schema-3.json create mode 100644 validator/internal/config/centralconsumer.go create mode 100644 validator/internal/config/config.go create mode 100644 validator/internal/config/logger.go create mode 100644 validator/internal/config/pullercleaner.go create mode 100644 validator/internal/errcodes/errcodes.go create mode 100644 validator/internal/errtemplates/errtemplates.go create mode 100644 validator/internal/errtemplates/valtemplates.go create mode 100644 validator/internal/janitor/cleaner.go create mode 100644 validator/internal/janitor/encryption.go create mode 100644 validator/internal/janitor/encryption_test.go create mode 100644 validator/internal/janitor/error.go create mode 100644 validator/internal/janitor/error_test.go create mode 100644 validator/internal/janitor/janitor.go create mode 100644 validator/internal/janitor/janitor_test.go create mode 100644 validator/internal/janitor/logging.go create mode 100644 validator/internal/janitor/logging_test.go create mode 100644 validator/internal/janitor/metrics.go create mode 100644 validator/internal/janitor/parse.go create mode 100644 validator/internal/janitor/processor.go create mode 100644 validator/internal/janitorctl/init.go create mode 100644 validator/internal/janitorctl/metrics.go create mode 100644 validator/internal/janitorctl/run.go create mode 100644 validator/internal/producer/config.go create mode 100644 validator/internal/producer/load.go create mode 100644 validator/internal/producer/producer.go create mode 100644 validator/internal/producer/producer_test.go create mode 100644 validator/internal/producer/run.go create mode 100644 validator/internal/producer/testdata/data-1.json create mode 100644 validator/internal/producer/testdata/data-2.json create mode 100644 validator/internal/producer/testdata/dataset.csv create mode 100644 validator/internal/producer/testdata/schema-1.json create mode 100644 validator/internal/producer/testdata/schema-2.json create mode 100644 validator/internal/publisher/mock.go create mode 100644 validator/internal/pullercleaner/pullercleaner.go create mode 100644 validator/internal/pullercleaner/pullercleaner_test.go create mode 100644 validator/internal/registry/apicuriosr/apicuriosr.go create mode 100644 validator/internal/registry/apicuriosr/apicuriosr_test.go create mode 100644 validator/internal/registry/apicuriosr/dto.go create mode 100644 validator/internal/registry/cache.go create mode 100644 validator/internal/registry/cache_test.go create mode 100644 validator/internal/registry/janitorsr/dto.go create mode 100644 validator/internal/registry/janitorsr/janitorsr.go create mode 100644 validator/internal/registry/janitorsr/janitorsr_test.go create mode 100644 validator/internal/registry/janitorsr/testdata/schema.avsc create mode 100644 validator/internal/registry/janitorsr/testdata/schema.csvs create mode 100644 validator/internal/registry/janitorsr/testdata/schema.json create mode 100644 validator/internal/registry/janitorsr/testdata/schema.xsd create mode 100644 validator/internal/registry/mock.go create mode 100644 validator/internal/registry/registry.go create mode 100644 validator/internal/schemagen/cmd.go create mode 100644 validator/internal/schemagen/cmd_test.go create mode 100644 validator/internal/schemagen/csv/csv.go create mode 100644 validator/internal/schemagen/csv/csv_test.go create mode 100644 validator/internal/schemagen/csv/testdata/data-1.csv create mode 100644 validator/internal/schemagen/csv/testdata/deadletter-1-data.csv create mode 100644 validator/internal/schemagen/csv/testdata/deadletter-2-data.csv create mode 100644 validator/internal/schemagen/csv/testdata/schema-1.csvs create mode 100644 validator/internal/schemagen/json/json.go create mode 100644 validator/internal/schemagen/json/json_schema_gen.py create mode 100644 validator/internal/schemagen/json/json_test.go create mode 100644 validator/internal/schemagen/json/testdata/deadletter-1-data.json create mode 100644 validator/internal/schemagen/schemagen.go create mode 100644 validator/internal/validator/avro/avro.go create mode 100644 validator/internal/validator/avro/avro_test.go create mode 100644 validator/internal/validator/avro/testdata/invalid-1-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-1-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-2-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-2-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-3-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-3-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-4-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-4-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-5-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-5-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-6-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-6-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-7-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/invalid-7-validation-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/valid-1-serialization-schema.avsc create mode 100644 validator/internal/validator/avro/testdata/valid-1-validation-schema.avsc create mode 100644 validator/internal/validator/csv/csv.go create mode 100644 validator/internal/validator/csv/csv_test.go create mode 100644 validator/internal/validator/csv/testdata/deadletter-1-data.csv create mode 100644 validator/internal/validator/csv/testdata/deadletter-1-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/deadletter-2-data.csv create mode 100644 validator/internal/validator/csv/testdata/deadletter-2-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/deadletter-3-data.csv create mode 100644 validator/internal/validator/csv/testdata/deadletter-3-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/invalid-1-data.csv create mode 100644 validator/internal/validator/csv/testdata/invalid-1-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/invalid-2-data.csv create mode 100644 validator/internal/validator/csv/testdata/invalid-2-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/invalid-3-data.csv create mode 100644 validator/internal/validator/csv/testdata/invalid-3-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/valid-1-data.csv create mode 100644 validator/internal/validator/csv/testdata/valid-1-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/valid-2-data.csv create mode 100644 validator/internal/validator/csv/testdata/valid-2-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/valid-3-data.csv create mode 100644 validator/internal/validator/csv/testdata/valid-3-schema.csvs create mode 100644 validator/internal/validator/csv/testdata/valid-4-data.csv create mode 100644 validator/internal/validator/csv/testdata/valid-4-schema.csvs create mode 100644 validator/internal/validator/external/csv-validator/.gitignore create mode 100644 validator/internal/validator/external/csv-validator/pom.xml create mode 100644 validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/CsvValidatorApplication.java create mode 100644 validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/controller/ValidatorController.java create mode 100644 validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidationRequestDto.java create mode 100644 validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidatorResponseDto.java create mode 100644 validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/validator/CsvValidator.java create mode 100644 validator/internal/validator/external/csv-validator/src/test/java/net/syntio/csvvalidator/CsvValidatorApplicationTests.java create mode 100644 validator/internal/validator/external/xml-validator/cloudbuild.yaml create mode 100644 validator/internal/validator/external/xml-validator/main.py create mode 100644 validator/internal/validator/external/xml-validator/requirements.txt create mode 100644 validator/internal/validator/http.go create mode 100644 validator/internal/validator/http_test.go create mode 100644 validator/internal/validator/json/json.go create mode 100644 validator/internal/validator/json/json_test.go create mode 100644 validator/internal/validator/json/testdata/data-1.json create mode 100644 validator/internal/validator/json/testdata/data-2.json create mode 100644 validator/internal/validator/json/testdata/data-3.json create mode 100644 validator/internal/validator/json/testdata/data-4.json create mode 100644 validator/internal/validator/json/testdata/deadletter-1-data.json create mode 100644 validator/internal/validator/json/testdata/deadletter-1-schema.json create mode 100644 validator/internal/validator/json/testdata/deadletter-2-data.json create mode 100644 validator/internal/validator/json/testdata/deadletter-2-schema.json create mode 100644 validator/internal/validator/json/testdata/invalid-1-data.json create mode 100644 validator/internal/validator/json/testdata/invalid-1-schema.json create mode 100644 validator/internal/validator/json/testdata/invalid-2-data.json create mode 100644 validator/internal/validator/json/testdata/invalid-2-schema.json create mode 100644 validator/internal/validator/json/testdata/invalid-3-data.json create mode 100644 validator/internal/validator/json/testdata/invalid-3-schema.json create mode 100644 validator/internal/validator/json/testdata/invalid-4-data.json create mode 100644 validator/internal/validator/json/testdata/invalid-4-schema.json create mode 100644 validator/internal/validator/json/testdata/ref-1-child.json create mode 100644 validator/internal/validator/json/testdata/ref-1.json create mode 100644 validator/internal/validator/json/testdata/ref-2-child.json create mode 100644 validator/internal/validator/json/testdata/ref-2.json create mode 100644 validator/internal/validator/json/testdata/ref-3-child.json create mode 100644 validator/internal/validator/json/testdata/ref-3.json create mode 100644 validator/internal/validator/json/testdata/ref-data-1.json create mode 100644 validator/internal/validator/json/testdata/ref-data-2.json create mode 100644 validator/internal/validator/json/testdata/ref-data-3.json create mode 100644 validator/internal/validator/json/testdata/schema-1.json create mode 100644 validator/internal/validator/json/testdata/schema-2.json create mode 100644 validator/internal/validator/json/testdata/schema-3.json create mode 100644 validator/internal/validator/json/testdata/schema-4.json create mode 100644 validator/internal/validator/json/testdata/valid-1-data.json create mode 100644 validator/internal/validator/json/testdata/valid-1-schema.json create mode 100644 validator/internal/validator/json/testdata/valid-2-data.json create mode 100644 validator/internal/validator/json/testdata/valid-2-schema.json create mode 100644 validator/internal/validator/json/testdata/valid-3-data.json create mode 100644 validator/internal/validator/json/testdata/valid-3-schema.json create mode 100644 validator/internal/validator/json/testdata/valid-4-data.json create mode 100644 validator/internal/validator/json/testdata/valid-4-schema.json create mode 100644 validator/internal/validator/protobuf/protobuf.go create mode 100644 validator/internal/validator/protobuf/protobuf_test.go create mode 100644 validator/internal/validator/protobuf/testdata/invalid2-1.pb create mode 100644 validator/internal/validator/protobuf/testdata/invalid2-2.pb create mode 100644 validator/internal/validator/protobuf/testdata/invalid3-1.pb create mode 100644 validator/internal/validator/protobuf/testdata/person/schema3-2.pb.go create mode 100644 validator/internal/validator/protobuf/testdata/schema2-1.proto create mode 100644 validator/internal/validator/protobuf/testdata/schema3-1.proto create mode 100644 validator/internal/validator/protobuf/testdata/schema3-2.proto create mode 100644 validator/internal/validator/protobuf/testdata/testpb2/schema2-1.pb.go create mode 100644 validator/internal/validator/protobuf/testdata/testpb3/schema3-1.pb.go create mode 100644 validator/internal/validator/protobuf/testdata/valid2-1.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid2-2.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid2-3.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid2-4.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-1.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-2.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-3.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-4.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-5.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-6.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-7.pb create mode 100644 validator/internal/validator/protobuf/testdata/valid3-8.pb create mode 100644 validator/internal/validator/validator.go create mode 100644 validator/internal/validator/xml/testdata/data-1.xml create mode 100644 validator/internal/validator/xml/testdata/data-2.xml create mode 100644 validator/internal/validator/xml/testdata/data-3.xml create mode 100644 validator/internal/validator/xml/testdata/deadletter-1-data.xml create mode 100644 validator/internal/validator/xml/testdata/deadletter-1-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/deadletter-2-data.xml create mode 100644 validator/internal/validator/xml/testdata/deadletter-2-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/deadletter-3-data.xml create mode 100644 validator/internal/validator/xml/testdata/deadletter-3-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/invalid-1-data.xml create mode 100644 validator/internal/validator/xml/testdata/invalid-1-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/invalid-2-data.xml create mode 100644 validator/internal/validator/xml/testdata/invalid-2-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/schema-1.xsd create mode 100644 validator/internal/validator/xml/testdata/schema-2.xsd create mode 100644 validator/internal/validator/xml/testdata/schema-3.xsd create mode 100644 validator/internal/validator/xml/testdata/valid-1-data.xml create mode 100644 validator/internal/validator/xml/testdata/valid-1-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/valid-2-data.xml create mode 100644 validator/internal/validator/xml/testdata/valid-2-schema.xsd create mode 100644 validator/internal/validator/xml/testdata/valid-3-data.xml create mode 100644 validator/internal/validator/xml/testdata/valid-3-schema.xsd create mode 100644 validator/internal/validator/xml/xml.go create mode 100644 validator/internal/validator/xml/xml_test.go create mode 100644 validator/licenses/LICENSE-3RD-PARTY.md create mode 100644 validator/licenses/csv-validator/LICENSE-3RD-PARTY.md create mode 100644 validator/licenses/xml-validator/LICENSE-3RD-PARTY.md diff --git a/.editorconfig b/.editorconfig index 7bb8092..e908007 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,8 +25,6 @@ indent_size = 2 trim_trailing_whitespace = false insert_final_newline = true -eclint_indent_style = unset - [Dockerfile] indent_size = 4 @@ -73,3 +71,4 @@ indent_size = unset [**/LICENSE-3RD-PARTY.md] insert_final_newline = unset + diff --git a/.github/workflows/libs/pr.yaml b/.github/workflows/libs/pr.yaml deleted file mode 100644 index 17e8474..0000000 --- a/.github/workflows/libs/pr.yaml +++ /dev/null @@ -1,198 +0,0 @@ -name: PR CI - -on: - pull_request: - branches: [ develop, main ] - -env: - GO111MODULE: on - GO_VERSION: 1.19 - NODE_VERSION: 22 - LINT_ARGS: -v --timeout 5m0s --out-${NO_FUTURE}format colored-line-number - TEST_ARGS: -v -short -coverprofile=coverage.out - TEST_PATH: ./... - -jobs: - commitlint: - name: Commit Lint Job - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Install commitlint - run: | - npm install --save-dev @commitlint/{cli,config-conventional} - - - name: Validate PR commits with commitlint - run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose - - editor_config_job: - name: Editor Config Job - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Editor Config - run: | - npm install --save-dev editorconfig-checker - ./node_modules/.bin/editorconfig-checker - - lint_job: - name: Go Lint Job - if: ${{ ! contains(github.head_ref, 'release-please--branches--main') }} - runs-on: ubuntu-latest - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Tidy - run: go mod tidy - - - name: Go Lint - uses: golangci/golangci-lint-action@v3 - with: - version: v1.50.0 - args: ${{ env.LINT_ARGS }} - skip-pkg-cache: true - skip-build-cache: true - - licenses_check: - name: 3rd Party Licenses Check - if: ${{ github.event.head_commit.committer.name != 'github-actions[bot]' || ! contains(github.head_ref, 'release-please--branches--main') }} - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Retrieve PR and branch info - run: | - PR_TITLE="chore: update 3rd-party licenses (#${{ github.event.number }})" - - PR_INFO=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - "https://api.github.com/repos/${{ github.repository }}/pulls?state=open" | \ - jq --arg TITLE "$PR_TITLE" '.[] | select(.title == $TITLE) | { number: .number, head: .head.ref }') - - echo "PR_INFO=$PR_INFO" - - PR_NUMBER=$(echo "$PR_INFO" | jq -r .number) - BRANCH_NAME=$(echo "$PR_INFO" | jq -r .head) - - echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV - echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV - echo "BRANCH_NAME=${BRANCH_NAME:-update-third-party-licenses-${{ github.run_id }}}" >> $GITHUB_ENV - echo "PARENT_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # if PR already exists - - name: Pull latest changes to existing branch - if: env.PR_NUMBER != '' - run: | - git fetch origin - git switch ${{ env.BRANCH_NAME }} - git pull origin ${{ env.PARENT_BRANCH }} --no-rebase - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Tidy - run: go mod tidy - - - name: Vendor - run: go mod vendor - - - name: Install Go licenses - run: go install github.com/google/go-licenses@v1.4.0 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pip' - cache-dependency-path: '.github/workflows/requirements.txt' - - - name: Install Python dependencies - run: | - python -m pip install --upgrade pip - pip install -r .github/workflows/requirements.txt - - - name: Run license check - run: | - go-licenses report ./... 2>/dev/null | python .github/workflows/generate_and_check_licenses.py - - - name: Check and Commit changes - run: | - if [ -d "./licenses" ]; then - git add ./licenses - fi - - if ! git diff-index --quiet HEAD; then - git commit -m "chore: update third party licenses" - echo "changes_committed=true" >> $GITHUB_ENV - else - echo "changes_committed=false" >> $GITHUB_ENV - fi - - # This will fail if the incorrect go.mod or go.sum is committed - - name: Push changes - if: env.changes_committed == 'true' - run: | - git diff - - if [[ -z "$PR_NUMBER" ]]; then - git switch -c ${{ env.BRANCH_NAME }} - fi - git push origin HEAD - - - name: Create new PR - if: env.changes_committed == 'true' && env.PR_NUMBER == '' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "Creating a new PR..." - gh pr create --base "${{ env.PARENT_BRANCH }}" --head "update-third-party-licenses-${{ github.run_id }}" --title "${{ env.PR_TITLE }}" --body "This is an automated PR that updates the list of 3rd party licenses." - - test_job: - name: Test Job - if: ${{ github.base_ref == 'main' && ! contains(github.head_ref, 'release-please--branches--main') }} - runs-on: ubuntu-latest - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Tidy - run: go mod tidy - - - name: Go Test - run: go test ${{ env.TEST_ARGS }} ${{ env.TEST_PATH }} diff --git a/.github/workflows/libs/push.yaml b/.github/workflows/libs/push.yaml deleted file mode 100644 index 6c8f3a4..0000000 --- a/.github/workflows/libs/push.yaml +++ /dev/null @@ -1,90 +0,0 @@ -name: PUSH CI - -on: - push: - branches: [ develop, main ] - -env: - GO_VERSION: 1.21 - -jobs: - commitlint: - name: Commit Lint Job - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - - - name: Install commitlint - run: | - npm install --save-dev @commitlint/{cli,config-conventional} - - - name: Validate current commit (last commit) with commitlint - run: npx commitlint --last --verbose - - license_headers: - name: Add License Headers - if: github.event.head_commit.committer.name != 'github-actions[bot]' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Go environment - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Install NWA tool - run: go install github.com/B1NARY-GR0UP/nwa@latest - - - name: Add missing license headers - run: nwa add -c "Syntio Ltd." # WRITE FOLDER PATHS FOR ALL FOLDERS THAT CONTAIN FILES THAT REQUIRE HEADERS eg. ./persistor - - - name: Check and Commit changes - id: check_commit - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - if ! git diff-index --quiet HEAD; then - git commit -m "style: add license headers" - echo "changes_committed=true" >> $GITHUB_ENV - else - echo "changes_committed=false" >> $GITHUB_ENV - echo "All necessary headers present." - fi - - - name: Create a new branch for the PR - if: env.changes_committed == 'true' - run: | - git checkout -b "add-license-headers-${{ github.run_id }}" - git push origin HEAD - - - name: Create Pull Request - if: env.changes_committed == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr create --base ${{ github.ref_name }} --head "add-license-headers-${{ github.run_id }}" --title "style: add license headers" --body "This PR adds license headers to the affected files. Recommendation: Merge this PR using the rebase-merge method" - - release-please: - if: github.ref_name == 'main' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - uses: googleapis/release-please-action@v4 - with: - token: ${{ secrets.RELEASE_PLEASE_TOKEN }} - release-type: simple diff --git a/.github/workflows/products/pr.yaml b/.github/workflows/pr.yaml similarity index 79% rename from .github/workflows/products/pr.yaml rename to .github/workflows/pr.yaml index 7b439b5..12859f1 100644 --- a/.github/workflows/products/pr.yaml +++ b/.github/workflows/pr.yaml @@ -39,9 +39,17 @@ jobs: if: ${{ ! contains(github.head_ref, 'release-please--branches--main') }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - dockerfile: # Add dockerfile paths eg. './persistor/docker/persistor/Dockerfile' - - + dockerfile: + - ./validator/docker/csv-validator/Dockerfile + - ./validator/docker/validator/Dockerfile + - ./validator/docker/xml-validator/Dockerfile + - ./registry/docker/compatibility-checker/Dockerfile + - ./registry/docker/initdb/Dockerfile + - ./registry/docker/registry/Dockerfile + - ./registry/docker/registry-firestore/Dockerfile + - ./registry/docker/validity-checker/Dockerfile steps: - name: Check out code @@ -70,25 +78,17 @@ jobs: npm install --save-dev editorconfig-checker ./node_modules/.bin/editorconfig-checker - # Ensures that java and python code adhere to coding styles and conventions - java_and_python_lint_job: - name: Java and Python lint - if: ${{ ! contains(github.head_ref, 'release-please--branches--main') }} - uses: github/super-linter@v4 - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - VALIDATE_PYTHON_BLACK: true - VALIDATE_JAVA: true - # Ensures that the code adheres to the lint checks defined in .golangci.yaml. lint_job: name: Go lint job for all components if: ${{ ! contains(github.head_ref, 'release-please--branches--main') }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: component: - - # Add file paths eg. './persistor + - ./registry + - ./validator steps: - name: Check out code into the Go module directory uses: actions/checkout@v4 @@ -108,22 +108,23 @@ jobs: go-version: ${{ env.GO_VERSION }} # Add all component folders for monorepos cache-dependency-path: | - /go.sum + ${{ matrix.component }}/go.sum - name: Tidy Go mod for ${{ matrix.component }} if: steps.check_changed_files.outputs.any_changed == 'true' - working-directory: ${{ matrix.component }} - run: go mod tidy + run: | + cd ${{ matrix.component }} + go mod tidy - name: Run Go Lint for ${{ matrix.component }} if: steps.check_changed_files.outputs.any_changed == 'true' - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6 with: version: v1.50.0 - args: ${{ env.LINT_ARGS }} + args: ${{env.LINT_ARGS}} skip-pkg-cache: true skip-build-cache: true - working-directory: ${{ matrix.component }} + working-directory: ${{ matrix.component }} licenses_check: name: 3rd Party Licenses Check @@ -171,7 +172,8 @@ jobs: go-version: ${{ env.GO_VERSION }} # Add all component folders for monorepos cache-dependency-path: | - /go.sum + ./registry/go.sum + ./validator/go.sum - name: Install Go licenses run: go install github.com/google/go-licenses@v1.4.0 @@ -189,18 +191,20 @@ jobs: pip install -r .github/workflows/requirements.txt - name: Run go mod tidy, go mod vendor & license check - # switch to each component folder first e.g. "./persistor" + # switch to each component folder first run: | - cd + cd ./registry + go mod tidy + go mod vendor + go-licenses report ./... 2>/dev/null | python ../.github/workflows/generate_and_check_licenses.py + cd ../validator go mod tidy go mod vendor - go-licenses report ./... 2>/dev/null | python .github/workflows/generate_and_check_licenses.py - cd ../ + go-licenses report ./... 2>/dev/null | python ../.github/workflows/generate_and_check_licenses.py - name: Check and Commit changes - # add licenses for each component run: | - git add ./persistor/licenses ./indexer-api/licenses ./resubmitter-api/licenses + git add ./registry/licenses ./validator/licenses if ! git diff-index --quiet HEAD; then git commit -m "chore: update third party licenses" @@ -237,7 +241,8 @@ jobs: strategy: matrix: component: - - # Add file paths eg. './persistor + - ./registry + - ./validator steps: - name: Check out code into the Go module directory @@ -249,7 +254,7 @@ jobs: go-version: ${{ env.GO_VERSION }} # Add all component folders for monorepos cache-dependency-path: | - /go.sum + ${{ matrix.component }}/go.sum - name: Tidy Go mod for ${{ matrix.component }} working-directory: ${{ matrix.component }} @@ -268,8 +273,20 @@ jobs: strategy: matrix: component: - - dockerfile-path: # Add dockerfile path eg. './persistor/docker/persistor/Dockerfile' - image-name: # Add image name eg. 'persistor-core' + - dockerfile-path: ./validator/docker/csv-validator/Dockerfile + image-name: schema-registry-csv-val + - dockerfile-path: ./validator/docker/validator/Dockerfile + image-name: schema-registry-worker + - dockerfile-path: ./validator/docker/xml-validator/Dockerfile + image-name: schema-registry-xml-val + - dockerfile-path: ./registry/docker/compatibility-checker/Dockerfile + image-name: schema-registry-compatibility + - dockerfile-path: ./registry/docker/initdb/Dockerfile + image-name: schema-registry-initdb + - dockerfile-path: ./registry/docker/registry/Dockerfile + image-name: schema-registry-api + - dockerfile-path: ./registry/docker/validity-checker/Dockerfile + image-name: schema-registry-validity steps: - name: Check out code diff --git a/.github/workflows/products/push.yaml b/.github/workflows/push.yaml similarity index 88% rename from .github/workflows/products/push.yaml rename to .github/workflows/push.yaml index b3e3e5f..de87f20 100644 --- a/.github/workflows/products/push.yaml +++ b/.github/workflows/push.yaml @@ -43,12 +43,16 @@ jobs: uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} + # Add all component folders for monorepos + cache-dependency-path: | + ./registry/go.sum + ./validator/go.sum - name: Install NWA tool run: go install github.com/B1NARY-GR0UP/nwa@latest - name: Add missing license headers - run: nwa add -c "Syntio Ltd." # WRITE FOLDER PATHS FOR ALL FOLDERS THAT CONTAIN FILES THAT REQUIRE HEADERS eg. ./persistor + run: nwa add -c "Syntio Ltd." ./registry ./validator - name: Check and Commit changes id: check_commit @@ -87,8 +91,14 @@ jobs: strategy: matrix: component: - - dockerfile-path: # Add dockerfile path eg. './persistor/docker/persistor/Dockerfile' - image-name: # Add image name eg. 'persistor-core' + - dockerfile-path: ./persistor/docker/persistor/Dockerfile + image-name: persistor-core + - dockerfile-path: ./persistor/docker/indexer/Dockerfile + image-name: persistor-indexer + - dockerfile-path: ./indexer-api/Dockerfile + image-name: persistor-indexer-api + - dockerfile-path: ./resubmitter-api/Dockerfile + image-name: persistor-resubmitter steps: - name: Check out code diff --git a/.golangci.yaml b/.golangci.yaml index 7e64123..3893cb6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -77,7 +77,7 @@ linters: - asciicheck - bidichk - bodyclose - - containedctx + # - containedctx - contextcheck # - cyclop - decorder @@ -99,14 +99,14 @@ linters: - govet - gci # - gochecknoglobals - - gochecknoinits + # - gochecknoinits # - gocognit - goconst # - gocritic # - gocyclo - godot - godox - - goerr113 + # - goerr113 - gofumpt - goheader # - gomnd @@ -129,7 +129,7 @@ linters: - nlreturn - noctx # - nolintlint - - nonamedreturns + # - nonamedreturns - nosprintfhostport # - paralleltest - prealloc @@ -140,7 +140,7 @@ linters: - sqlclosecheck - stylecheck - staticcheck - - tagliatelle + # - tagliatelle - tenv - testpackage - thelper @@ -629,7 +629,7 @@ linters-settings: # shadow: # Whether to be strict about shadowing; can be noisy # false by default - # strict: false + # strict: false # unusedresult: # comma-separated list of functions whose results must be used # (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue, diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000..ad3cb58 --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,19 @@ +# name of threshold level (error | warning | info | style | ignore | none) +failure-threshold: error + +# list of rules you want to ignore +ignored: [ ] + +# override the severity of specific rules by writing the error code into the list +override: + error: [ ] + warning: [ ] + info: [ ] + style: [ ] + +# do not permit labels other than specified in `label-schema` +strict-labels: false + +# hadolint can warn you when images from untrusted repositories are being used in Dockerfiles, +# you can append the trustedRegistries keys to the configuration file +# trustedRegistries: [ ] diff --git a/README.md b/README.md new file mode 100644 index 0000000..77c9b4d --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Schema Registry + +[![Apache 2.0 License](https://img.shields.io/github/license/dataphos/schema-registry)](./LICENSE) +[![GitHub Release](https://img.shields.io/github/v/release/dataphos/schema-registry?sort=semver)](https://github.com/dataphos/schema-registry/releases/latest) + +Schema Registry is a product used for **schema management** and **message validation**. + +Schema management itself consists of 2 steps - *schema registration* and *schema versioning*, while message validation consists of validators that validate messages for the given message schema. The core components are a server with HTTP RESTful interface used to manage the schemas, and lightweight message validators, which verify the schema and validity of the incoming messages. + +It allows developers to define and manage standard schemas for events, share them across the organization, evolve the schemas while preserving compatibility, as well as validate events with the given event schema. For each schema used, the product stores their own versioned history while also providing an easy-to-use RESTful interface to work with them. + +Apart from the general idea of the product, its main features are split across two major components - Registry and Validator. + +The official Schema Registry documentation is available [here](https://docs.dataphos.com/schema_registry/). It contains an in-depth overview of each component, a quickstart setup, detailed deployment instructions, configuration options, usage guides and more, so be sure to check it out for better understanding. + +## Registry +The Registry component represents the main database, called Schema History, which is used for handling schemas, and the REST API on top of the database to enable the other major component, [Validator](#validator), to fetch all the necessary information regarding the schemas. + +## Validator +The Validator component, in essence, does what the title suggests - validates messages. It performs this by retrieving and caching messages schemas from the [Registry](#registry) database, using a message's metadata. + +## Installation +In order to use Schema Registry as a whole with both of its components, the only major requirement from the user is to have a running project on one of the two major cloud providers: GCP or Azure. + +All of the other requirements for the product to fully-function (message broker instance, incoming message type definition, identity and access management of the particular cloud) are further explained and can be analyzed in the [Quickstart section](https://docs.dataphos.com/schema_registry/quickstart/) of its official documentation. + +## Usage +### Registry +- Takes care of everything related to the schemas themselves - registration, updates, retrieval, deletion of an entire schema or its particular version, as well as performing schema checks for validity and compatibility (backwards, forwards and transitively). +- Its REST API provides handles for clients and communicates via HTTP requests. +- With regards to the message schemas themselves, the Schema History database where they get stored in can be anything from a standard SQL database like Oracle or PostgreSQL, to a NoSQL database like Firestore or MongoDB. + +### Validator +- In order for the Validator to work, the message schema needs to be registered in the Schema History database. + - Each of the incoming messages needs to have its metadata enriched with the information of the schema stored in the Schema History database, with the main attributes being the *ID*, the *schema version* and the *message format*. +- Once that scenario is set up, the Validator can then filter incoming messages and route them to the appropriate destination - valid topic for successfully validated messages and dead-letter topic for unsucessfully validated messages. + - The list of supported message brokers can be found in the [Validator section](https://docs.dataphos.com/schema_registry/what-is-schema-registry/#worker) of its official documentation. +- Similarly to the various message brokers, the Validator also enables the use of different protocols for producers and consumers of messages. + - This in turn enables protocol conversion through the system. + - The list of supported protocols can also be found in the [Validator section](https://docs.dataphos.com/schema_registry/what-is-schema-registry/#worker) of its official documentation. + +## Contributing +For all the inquiries regarding contributing to the project, be sure to check out the information in the [CONTRIBUTING.md](CONTRIBUTING.md) file. + +## License +This project is licensed under the [Apache 2.0 License](LICENSE). \ No newline at end of file diff --git a/registry/README.md b/registry/README.md new file mode 100644 index 0000000..07310c0 --- /dev/null +++ b/registry/README.md @@ -0,0 +1,221 @@ +# Dataphos Schema Registry - Registry component + +Repository of the Dataphos Schema Registry API. + + +## Registry + +The Registry, which itself is a database with a REST API on top, is deployed as a deployment on a Kubernetes cluster +which supports the following: +- Schema registration +- Schema updating (adding a new version of an existing schema) +- Retrieval of existing schemas (specified version or latest version) +- Deleting the whole schema or just specified versions of a schema +- Checking for schema validity (syntactically and semantically) +- Checking for schema compatibility (backward, forward, transitive) +- Schema search + + +The main component of the Schema Registry product is entirely independent of the implementation of the data-streaming +platform. It is implemented as a REST API that provides handles (via URL) for clients and communicates via HTTP +requests. + +The worker component communicates with the REST API by sending the HTTP GET request that retrieves a message schema from +the Registry by using the necessary parameters. The message schemas themselves can be stored in any type of database ( +Schema History), whether in tables like in standard SQL databases, such as Oracle or PostgreSQL, or NoSQL databases like +Firestore, MongoDB etc. The component itself has an interface with the database connector that can be easily modified to +work with databases that fit the client’s needs. + + +## Getting Started +### Prerequisites +Schema Registry components run in a Kubernetes environment. This quickstart guide will assume that you have +the ```kubectl``` tool installed and a running Kubernetes cluster on one of the major cloud providers (GCP, Azure) and a +connection with the cluster. + +#### Namespace +Before deploying the Schema Registry, the namespace where the components will be deployed should be created if it +doesn't exist. + +--- +Open a command line tool of your choice and connect to your cluster. Create the namespace where Schema Registry will be +deployed. We will use namespace "dataphos" in this quickstart guide. + +```yaml +kubectl create namespace dataphos +``` + +### Quick Start + +Deploy Schema Registry - registry component using the following script. The required arguments are: + +- the namespace +- Schema History Postgres password + +#### Deployment + +The script is located in the ```./scripts/registry/``` folder. from the content root. To run the script, run the +following command: + +```bash +# "dataphos" is an example of the namespace name +# "p4sSw0rD" is example of the Schema History Postgres password +./sr_registry.sh dataphos p4sSw0rD +``` + +## Usage +Even thought the Schema Registry provides REST API for registering, updating, fetching a schema, fetching all the +versions, fetching the latest, deleting a schema, etc. We will showcase here only the requests to register, update and +fetch a schema. + +### Register a schema + +After the Schema Registry is deployed you will have access to its API endpoint. To register a schema, you have to send a +POST request to the endpoint ```http://schema-registry-svc:8080/schemas``` in whose body you need to provide the name of the +schema, description, schema_type, specification (the schema), compatibility and validity mode. + +``` +{ + "description": "new json schema for testing", + "schema_type": "json", + "specification": "{\r\n \"$id\": \"https://example.com/person.schema.json\",\r\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n }\r\n}\r\n", + "name": "schema json", + "compatibility_mode": "none", + "validity_mode": "none" +} +``` + +or using curl: + +``` +curl -XPOST -H "Content-type: application/json" -d '{ + "description": "new json schema for testing", + "schema_type": "json", + "specification": "{\r\n \"$id\": \"https://example.com/person.schema.json\",\r\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n }\r\n}\r\n", + "name": "schema json", + "compatibility_mode": "none", + "validity_mode": "none" +}' 'http://schema-registry-svc:8080/schemas/' +``` + +The response to the schema registration request will be: + +- STATUS 201 Created + ``` + { + "identification": "32", + "version": "1", + "message": "schema successfully created" + } + ``` + +- STATUS 409 Conflict -> indicating that the schema already exists + ``` + { + "identification": "32", + "version": "1", + "message": "schema already exists at id=32" + } + ``` + +- STATUS 500 Internal Server Error -> indicating a server error, which means that either the request is not correct ( +missing fields) or that the server is down. + ``` + { + "message": "Internal Server Error" + } + ``` + +### Update a schema + +After the Schema Registry is registered you can update it by registering a new version under that schema ID. To update a +schema, you have to send a PUT request to the endpoint ```http://schema-registry-svc:8080/schemas/``` in whose body +you need to provide the description (optional) of the version and the specification (the schema) + +``` +{ + "description": "added field for middle name", + "specification": "{\r\n \"$id\": \"https://example.com/person.schema.json\",\r\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n }\r\n}\r\n" +} +``` + +or using curl: + +``` +curl -XPUT -H "Content-type: application/json" -d '{ + "description": "added field for middle name", + "specification": "{\r\n \"$id\": \"https://example.com/person.schema.json\",\r\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n }\r\n}\r\n" +}' 'http://schema-registry-svc:8080/schemas/' +``` + +The response to the schema updating request will be the same as for registering except when the updating is done +successfully it will be status 200 OK and a new version will be provided. + +``` +{ + "identification": "32", + "version": "2", + "message": "schema successfully updated" +} +``` + +### Fetch a schema version + +To get a schema version and its relevant details, a GET request needs to be made and the endpoint needs to be: + +```http://schema-registry-svc:8080/schemas//versions/``` + +or using curl: + +``` curl -XGET -H "Content-type: application/json" 'http://schema-registry-svc:8080/schemas//versions/' ``` + +The response to the schema registration request will be: + +- STATUS 200 OK + ``` + { + "id": "32", + "version": "1", + "schema_id": "32", + "specification": "ew0KICAiJHNjaGVtYSI6ICJodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSIsDQogICJ0eXBlIjogIm9iamVjdCIsDQogICJ0aXRsZSI6ICJUaGUgUm9vdCBTY2hlbWEiLA0KICAiZGVzY3JpcHRpb24iOiAiVGhlIHJvb3Qgc2NoZW1hIGNvbXByaXNlcyB0aGUgZW50aXJlIEpTT04gZG9jdW1lbnQuIiwNCiAgImRlZmF1bHQiOiB7fSwNCiAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjogdHJ1ZSwNCiAgInJlcXVpcmVkIjogWw0KICAgICJwaG9uZSINCiAgXSwNCiAgInByb3BlcnRpZXMiOiB7DQogICAgInBob25lIjogew0KICAgICAgInR5cGUiOiAiaW50ZWdlciIsDQogICAgICAidGl0bGUiOiAiVGhlIFBob25lIFNjaGVtYSIsDQogICAgICAiZGVzY3JpcHRpb24iOiAiQW4gZXhwbGFuYXRpb24gYWJvdXQgdGhlIHB1cnBvc2Ugb2YgdGhpcyBpbnN0YW5jZS4iLA0KICAgICAgImRlZmF1bHQiOiAiIiwNCiAgICAgICJleGFtcGxlcyI6IFsNCiAgICAgICAgMQ0KICAgICAgXQ0KICAgIH0sDQogICAgInJvb20iOiB7DQogICAgICAidHlwZSI6ICJpbnRlZ2VyIiwNCiAgICAgICJ0aXRsZSI6ICJUaGUgUm9vbSBTY2hlbWEiLA0KICAgICAgImRlc2NyaXB0aW9uIjogIkFuIGV4cGxhbmF0aW9uIGFib3V0IHRoZSBwdXJwb3NlIG9mIHRoaXMgaW5zdGFuY2UuIiwNCiAgICAgICJkZWZhdWx0IjogIiIsDQogICAgICAiZXhhbXBsZXMiOiBbDQogICAgICAgIDEyMw0KICAgICAgXQ0KICAgIH0NCiAgfQ0KfQ==", + "description": "new json schema for testing", + "schema_hash": "72966008fdcec8627a0e43c5d9a247501fc4ab45687dd2929aebf8ef3eb06ccd", + "created_at": "2023-05-09T08:38:54.5515Z", + "autogenerated": false + } + ``` +- STATUS 404 Not Found -> indicating that the wrong schema ID or schema version was provided +- STATUS 500 Internal Server Error -> indicating a server error, which means that either the request is not correct ( +wrong endpoint) or that the server is down. + + +### Other requests + +| Description | Method | URL | Headers | Body | +|:-------------------------------------------------:|--------|:---------------------------------------------------------------:|:----------------------------------:|:---------------------------------:| +| Get all the schemas | GET | http://schema-registry-svc/schemas | Content-Type: application/json | This request does not have a body | +| Get all the schema versions of the specified ID | GET | http://schema-registry-svc/schemas/{id}/versions | Content-Type: application/json | This request does not have a body | +| Get the latest schema version of the specified ID | GET | http://schema-registry-svc/schemas/{id}/versions/latest | Content-Type: application/json | This request does not have a body | +| Get schema specification by id and version | GET | http://schema-registry-svc/schemas/{id}/versions/{version}/spec | Content-Type: application/json
| This request does not have a body | +| Delete the schema under the ID | DELETE | http://schema-registry-svc/schemas/{id} | Content-Type: application/json | This request does not have a body | +| Delete the schema by id and version | DELETE | http://schema-registry-svc/schemas/{id}/versions/{version} | Content-Type: application/json | This request does not have a body | + + +### Schema search +With schema search, users can swiftly locate relevant data schemas using a GET request and URL parameters. +```http://schema-registry-svc/schemas/search``` + 1 or more Query Parameters: + +| Query parameters | Example | +|:----------------------------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------------------------------| +| id | search by id 5
URL: http://schema-registry-svc/schemas/search?id=5 | +| version | search by id 5 and version 2
URL: http://schema-registry-svc/schemas/search?id=5&version=2 | +| type | search by type JSON
URL: http://schema-registry-svc/schemas/search?type=json | +| name | search by name "json_schema_name"
URL: http://schema-registry-svc/schemas/search?name=json_schema_name | +| orderBy name, type, id or version (if sort value is given but orderBy isn’t the default value is id) | +| sort asc or desc (if orderBy value is given but sort isn’t the default value is asc) | +| limit | +| attributes | search by attributes crs and type
URL: http://schema-registry-svc/schemas/search?attributes=crs,type | + + + + diff --git a/registry/cmd/initdb/initdb.go b/registry/cmd/initdb/initdb.go new file mode 100644 index 0000000..6da91d0 --- /dev/null +++ b/registry/cmd/initdb/initdb.go @@ -0,0 +1,56 @@ +package main + +import ( + "runtime/debug" + + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/config" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/repository/postgres" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-logger/standardlogger" +) + +func main() { + labels := logger.Labels{ + "product": "Schema Registry", + "component": "initdb", + } + var Commit = func() string { + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + + return "" + }() + if Commit != "" { + labels["commit"] = Commit + } + + logLevel, logConfigWarnings := config.GetLogLevel() + log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) + + for _, w := range logConfigWarnings { + log.Warn(w) + } + + db, err := postgres.InitializeGormFromEnv() + if err != nil { + log.Fatal(err.Error(), errcodes.DatabaseConnectionInitialization) + return + } + + if postgres.HealthCheck(db) { + log.Warn("database already initialized") + return + } + + if err = postgres.Initdb(db); err != nil { + log.Fatal(err.Error(), errcodes.DatabaseInitialization) + return + } + log.Info("database initialized successfully") +} diff --git a/registry/cmd/janitorsr-firestore/main.go b/registry/cmd/janitorsr-firestore/main.go new file mode 100644 index 0000000..4b19109 --- /dev/null +++ b/registry/cmd/janitorsr-firestore/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "os/signal" + "runtime/debug" + "strconv" + "syscall" + "time" + + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/config" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/repository/firestore" + "github.com/dataphos/aquarium-janitor-standalone-sr/server" + "github.com/dataphos/aquarium-janitor-standalone-sr/validity" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-logger/standardlogger" +) + +const ( + serverPortEnvKey = "SERVER_PORT" +) + +const ( + defaultServerPort = 8080 +) + +func main() { + labels := logger.Labels{ + "product": "Janitor", + "component": "Schema Registry", + } + var Commit = func() string { + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + + return "" + }() + if Commit != "" { + labels["commit"] = Commit + } + + logLevel, logConfigWarnings := config.GetLogLevel() + log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) + + for _, w := range logConfigWarnings { + log.Warn(w) + } + + db, err := firestore.New() + if err != nil { + log.Error(err.Error(), errcodes.DatabaseConnectionInitialization) + return + } + + var port int + portStr := os.Getenv(serverPortEnvKey) + if portStr == "" { + port = defaultServerPort + } else { + port, err = strconv.Atoi(portStr) + if err != nil { + log.Error(errtemplates.ExpectedInt(serverPortEnvKey, portStr).Error(), errcodes.ServerInitialization) + return + } + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + compChecker, globalCompMode, err := compatibility.InitCompatibilityChecker(ctx) + if err != nil { + log.Error(err.Error(), errcodes.ExternalCheckerInitialization) + return + } + log.Info("Successfully connected compatibility checker.") + + valChecker, globalValMode, err := validity.InitExternalValidityChecker(ctx) + if err != nil { + log.Error(err.Error(), errcodes.ExternalCheckerInitialization) + return + } + log.Info("Successfully connected validity checker.") + + srv := http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: server.New(server.NewHandler(registry.New(db, compChecker, valChecker, globalCompMode, globalValMode), log)), + } + + idleConnsClosed := make(chan struct{}) + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) + + <-c + + log.Info("initiating graceful shutdown") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err = srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "graceful shutdown failed").Error(), errcodes.ServerShutdown) + } + close(idleConnsClosed) + }() + + log.Infow("starting server", logger.F{"port": srv.Addr}) + if err = srv.ListenAndServe(); err != nil { + if err != http.ErrServerClosed { + log.Error(errors.Wrap(err, "an error occurred starting or closing server").Error(), errcodes.ServerShutdown) + } + } + + <-idleConnsClosed + + log.Info("shutting down") +} diff --git a/registry/cmd/janitorsr/main.go b/registry/cmd/janitorsr/main.go new file mode 100644 index 0000000..cdf28fc --- /dev/null +++ b/registry/cmd/janitorsr/main.go @@ -0,0 +1,144 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "os/signal" + "runtime/debug" + "strconv" + "syscall" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/config" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/repository/postgres" + "github.com/dataphos/aquarium-janitor-standalone-sr/server" + "github.com/dataphos/aquarium-janitor-standalone-sr/validity" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-logger/standardlogger" +) + +const ( + serverPortEnvKey = "SERVER_PORT" +) + +const ( + defaultServerPort = 8080 +) + +// @title Schema Registry API +// @version 1.0 +func main() { + labels := logger.Labels{ + "product": "Schema Registry", + "component": "registry", + } + var Commit = func() string { + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + + return "" + }() + if Commit != "" { + labels["commit"] = Commit + } + + logLevel, logConfigWarnings := config.GetLogLevel() + log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) + for _, w := range logConfigWarnings { + log.Warn(w) + } + + db, err := postgres.InitializeGormFromEnv() + if err != nil { + log.Error(err.Error(), errcodes.DatabaseConnectionInitialization) + return + } + if !postgres.HealthCheck(db) { + log.Error("database state invalid", errcodes.InvalidDatabaseState) + return + } + + var port int + portStr := os.Getenv(serverPortEnvKey) + if portStr == "" { + port = defaultServerPort + } else { + port, err = strconv.Atoi(portStr) + if err != nil { + log.Error(errtemplates.ExpectedInt(serverPortEnvKey, portStr).Error(), errcodes.ServerInitialization) + return + } + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + compChecker, globalCompMode, err := compatibility.InitCompatibilityChecker(ctx) + if err != nil { + log.Error(err.Error(), errcodes.ExternalCheckerInitialization) + return + } + log.Info("Successfully connected compatibility checker.") + + valChecker, globalValMode, err := validity.InitExternalValidityChecker(ctx) + if err != nil { + log.Error(err.Error(), errcodes.ExternalCheckerInitialization) + return + } + log.Info("Successfully connected validity checker.") + + srv := http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: server.New(server.NewHandler(registry.New(postgres.New(db), compChecker, valChecker, globalCompMode, globalValMode), log)), + } + + idleConnsClosed := make(chan struct{}) + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) + + <-c + + log.Info("initiating graceful shutdown") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err = srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "graceful shutdown failed").Error(), errcodes.ServerShutdown) + } + close(idleConnsClosed) + }() + go func() { + http.Handle("/metrics", promhttp.Handler()) + + log.Infow("starting Prometheus server", logger.F{"port": 2112}) + err1 := http.ListenAndServe(":2112", nil) + if err1 != nil { + log.Error(errors.Wrap(err, "an error occurred starting Prometheus server").Error(), errcodes.ServerShutdown) + } + }() + + log.Infow("starting server", logger.F{"port": srv.Addr}) + if err = srv.ListenAndServe(); err != nil { + if err != http.ErrServerClosed { + log.Error(errors.Wrap(err, "an error occurred starting or closing server").Error(), errcodes.ServerShutdown) + } + } + + <-idleConnsClosed + + log.Info("shutting down") +} diff --git a/registry/cmd/sr-cli/main.go b/registry/cmd/sr-cli/main.go new file mode 100644 index 0000000..4b4c51e --- /dev/null +++ b/registry/cmd/sr-cli/main.go @@ -0,0 +1,159 @@ +package main + +import ( + "context" + "flag" + "log" + "os" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/repository/postgres" + "github.com/dataphos/aquarium-janitor-standalone-sr/validity" +) + +func main() { + registerCommand := flag.NewFlagSet("register", flag.ExitOnError) + updateCommand := flag.NewFlagSet("update", flag.ExitOnError) + + if len(os.Args) < 2 { + log.Fatal("register or update command must be provided") + } + + switch os.Args[1] { + case "register": + registerSchema(registerCommand) + case "update": + updateSchema(updateCommand) + default: + log.Fatal("command not supported") + } +} + +func registerSchema(registerCommand *flag.FlagSet) { + filename := registerCommand.String("f", "", "the json file containing schema specification") + schemaType := registerCommand.String("t", "", "schema type") + name := registerCommand.String("n", "schema-janitor", "schema name") + description := registerCommand.String("d", "description of the schema", "schema description") + publisherId := registerCommand.String("p", "publisherId", "publisher id") + compMode := registerCommand.String("c", "", "compatibility mode") + valMode := registerCommand.String("v", "", "validity mode") + + err := registerCommand.Parse(os.Args[2:]) + if err != nil { + log.Fatal(err) + } + + if *filename == "" { + log.Fatal("filename must be provided") + } + + if *schemaType == "" { + log.Fatal("type must be provided") + } + + if *valMode == "" { + log.Fatal("validity mode must be provided") + } + + if *compMode == "" { + log.Fatal("compatibility mode must be provided") + } + + file, err := os.ReadFile(*filename) + if err != nil { + log.Fatal(err) + } + + schemaRegistrationRequest := registry.SchemaRegistrationRequest{ + Description: *description, + Specification: string(file), + Name: *name, + SchemaType: *schemaType, + PublisherID: *publisherId, + CompatibilityMode: *compMode, + ValidityMode: *valMode, + } + + service := createService() + details, added, err := service.CreateSchema(schemaRegistrationRequest) + + if err != nil { + log.Fatal(err) + } + if !added { + log.Print("schema already exists") + } else { + log.Print("created schema under the id ", details.VersionID) + } +} + +func updateSchema(updateCommand *flag.FlagSet) { + filename := updateCommand.String("f", "", "the json file containing updated schema specification") + description := updateCommand.String("d", "", "updated schema description") + id := updateCommand.String("id", "", "id of the schema") + + err := updateCommand.Parse(os.Args[2:]) + if err != nil { + log.Fatal(err) + } + + if *filename == "" { + log.Fatal("filename must be provided") + } + + if *id == "" { + log.Fatal("id must be provided") + } + + file, err := os.ReadFile(*filename) + if err != nil { + log.Fatal(err) + } + + schemaUpdateRequest := registry.SchemaUpdateRequest{ + Specification: string(file), + } + if *description != "" { + schemaUpdateRequest.Description = *description + } + + service := createService() + details, updated, err := service.UpdateSchema(*id, schemaUpdateRequest) + if err != nil { + log.Fatal(err) + } + if !updated { + log.Print("schema already exists") + } else { + log.Print("schema successfully updated, added version ", details.Version) + } +} + +func createService() *registry.Service { + db, err := postgres.InitializeGormFromEnv() + if err != nil { + log.Fatal(err, errcodes.DatabaseConnectionInitialization) + } + if !postgres.HealthCheck(db) { + log.Fatal("database state invalid", errcodes.InvalidDatabaseState) + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + compChecker, globalCompMode, err := compatibility.InitCompatibilityChecker(ctx) + if err != nil { + log.Fatal(err, errcodes.ExternalCheckerInitialization) + } + + valChecker, globalValMode, err := validity.InitExternalValidityChecker(ctx) + if err != nil { + log.Fatal(err, errcodes.ExternalCheckerInitialization) + } + + service := registry.New(postgres.New(db), compChecker, valChecker, globalCompMode, globalValMode) + return service +} diff --git a/registry/cmd/sr-cli/testdata/avro/schema-1.avsc b/registry/cmd/sr-cli/testdata/avro/schema-1.avsc new file mode 100644 index 0000000..52a3a44 --- /dev/null +++ b/registry/cmd/sr-cli/testdata/avro/schema-1.avsc @@ -0,0 +1,62 @@ +{ + "type": "record", + "name": "mySchema", + "fields": [ + { + "name": "MERCHANT_NAME", + "type": "string" + }, + { + "name": "rows", + "type": { + "type": "array", + "items": { + "type": "record", + "name": "rows", + "fields": [ + { + "name": "AMOUNT", + "type": "string" + }, + { + "name": "CARD_NUMBER", + "type": "string" + }, + { + "name": "CARD_TYPE", + "type": "string" + }, + { + "name": "IS_FRAUD", + "type": "string" + }, + { + "name": "MCC", + "type": "string" + }, + { + "name": "MERCHANT_CITY", + "type": "string" + }, + { + "name": "TRANSACTION_DATE", + "type": "string" + }, + { + "name": "TRANSACTION_ID", + "type": "string" + }, + { + "name": "USE_CHIP", + "type": "string" + }, + { + "name": "YEAR", + "type": "string" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-1.json b/registry/cmd/sr-cli/testdata/json/schema-1.json new file mode 100644 index 0000000..687ae74 --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-1.json @@ -0,0 +1,21 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/registry/cmd/sr-cli/testdata/json/schema-10.json b/registry/cmd/sr-cli/testdata/json/schema-10.json new file mode 100644 index 0000000..67f3ff9 --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-10.json @@ -0,0 +1,7505 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "+1": { + "type": "string" + }, + "-1": { + "type": "string" + }, + "100": { + "type": "string" + }, + "1234": { + "type": "string" + }, + "1st_place_medal": { + "type": "string" + }, + "2nd_place_medal": { + "type": "string" + }, + "3rd_place_medal": { + "type": "string" + }, + "8ball": { + "type": "string" + }, + "a": { + "type": "string" + }, + "ab": { + "type": "string" + }, + "abacus": { + "type": "string" + }, + "abc": { + "type": "string" + }, + "abcd": { + "type": "string" + }, + "accept": { + "type": "string" + }, + "accordion": { + "type": "string" + }, + "adhesive_bandage": { + "type": "string" + }, + "adult": { + "type": "string" + }, + "aerial_tramway": { + "type": "string" + }, + "afghanistan": { + "type": "string" + }, + "airplane": { + "type": "string" + }, + "aland_islands": { + "type": "string" + }, + "alarm_clock": { + "type": "string" + }, + "albania": { + "type": "string" + }, + "alembic": { + "type": "string" + }, + "algeria": { + "type": "string" + }, + "alien": { + "type": "string" + }, + "ambulance": { + "type": "string" + }, + "american_samoa": { + "type": "string" + }, + "amphora": { + "type": "string" + }, + "anatomical_heart": { + "type": "string" + }, + "anchor": { + "type": "string" + }, + "andorra": { + "type": "string" + }, + "angel": { + "type": "string" + }, + "anger": { + "type": "string" + }, + "angola": { + "type": "string" + }, + "angry": { + "type": "string" + }, + "anguilla": { + "type": "string" + }, + "anguished": { + "type": "string" + }, + "ant": { + "type": "string" + }, + "antarctica": { + "type": "string" + }, + "antigua_barbuda": { + "type": "string" + }, + "apple": { + "type": "string" + }, + "aquarius": { + "type": "string" + }, + "argentina": { + "type": "string" + }, + "aries": { + "type": "string" + }, + "armenia": { + "type": "string" + }, + "arrow_backward": { + "type": "string" + }, + "arrow_double_down": { + "type": "string" + }, + "arrow_double_up": { + "type": "string" + }, + "arrow_down": { + "type": "string" + }, + "arrow_down_small": { + "type": "string" + }, + "arrow_forward": { + "type": "string" + }, + "arrow_heading_down": { + "type": "string" + }, + "arrow_heading_up": { + "type": "string" + }, + "arrow_left": { + "type": "string" + }, + "arrow_lower_left": { + "type": "string" + }, + "arrow_lower_right": { + "type": "string" + }, + "arrow_right": { + "type": "string" + }, + "arrow_right_hook": { + "type": "string" + }, + "arrow_up": { + "type": "string" + }, + "arrow_up_down": { + "type": "string" + }, + "arrow_up_small": { + "type": "string" + }, + "arrow_upper_left": { + "type": "string" + }, + "arrow_upper_right": { + "type": "string" + }, + "arrows_clockwise": { + "type": "string" + }, + "arrows_counterclockwise": { + "type": "string" + }, + "art": { + "type": "string" + }, + "articulated_lorry": { + "type": "string" + }, + "artificial_satellite": { + "type": "string" + }, + "artist": { + "type": "string" + }, + "aruba": { + "type": "string" + }, + "ascension_island": { + "type": "string" + }, + "asterisk": { + "type": "string" + }, + "astonished": { + "type": "string" + }, + "astronaut": { + "type": "string" + }, + "athletic_shoe": { + "type": "string" + }, + "atm": { + "type": "string" + }, + "atom": { + "type": "string" + }, + "atom_symbol": { + "type": "string" + }, + "australia": { + "type": "string" + }, + "austria": { + "type": "string" + }, + "auto_rickshaw": { + "type": "string" + }, + "avocado": { + "type": "string" + }, + "axe": { + "type": "string" + }, + "azerbaijan": { + "type": "string" + }, + "b": { + "type": "string" + }, + "baby": { + "type": "string" + }, + "baby_bottle": { + "type": "string" + }, + "baby_chick": { + "type": "string" + }, + "baby_symbol": { + "type": "string" + }, + "back": { + "type": "string" + }, + "bacon": { + "type": "string" + }, + "badger": { + "type": "string" + }, + "badminton": { + "type": "string" + }, + "bagel": { + "type": "string" + }, + "baggage_claim": { + "type": "string" + }, + "baguette_bread": { + "type": "string" + }, + "bahamas": { + "type": "string" + }, + "bahrain": { + "type": "string" + }, + "balance_scale": { + "type": "string" + }, + "bald_man": { + "type": "string" + }, + "bald_woman": { + "type": "string" + }, + "ballet_shoes": { + "type": "string" + }, + "balloon": { + "type": "string" + }, + "ballot_box": { + "type": "string" + }, + "ballot_box_with_check": { + "type": "string" + }, + "bamboo": { + "type": "string" + }, + "banana": { + "type": "string" + }, + "bangbang": { + "type": "string" + }, + "bangladesh": { + "type": "string" + }, + "banjo": { + "type": "string" + }, + "bank": { + "type": "string" + }, + "bar_chart": { + "type": "string" + }, + "barbados": { + "type": "string" + }, + "barber": { + "type": "string" + }, + "baseball": { + "type": "string" + }, + "basecamp": { + "type": "string" + }, + "basecampy": { + "type": "string" + }, + "basket": { + "type": "string" + }, + "basketball": { + "type": "string" + }, + "basketball_man": { + "type": "string" + }, + "basketball_woman": { + "type": "string" + }, + "bat": { + "type": "string" + }, + "bath": { + "type": "string" + }, + "bathtub": { + "type": "string" + }, + "battery": { + "type": "string" + }, + "beach_umbrella": { + "type": "string" + }, + "bear": { + "type": "string" + }, + "bearded_person": { + "type": "string" + }, + "beaver": { + "type": "string" + }, + "bed": { + "type": "string" + }, + "bee": { + "type": "string" + }, + "beer": { + "type": "string" + }, + "beers": { + "type": "string" + }, + "beetle": { + "type": "string" + }, + "beginner": { + "type": "string" + }, + "belarus": { + "type": "string" + }, + "belgium": { + "type": "string" + }, + "belize": { + "type": "string" + }, + "bell": { + "type": "string" + }, + "bell_pepper": { + "type": "string" + }, + "bellhop_bell": { + "type": "string" + }, + "benin": { + "type": "string" + }, + "bento": { + "type": "string" + }, + "bermuda": { + "type": "string" + }, + "beverage_box": { + "type": "string" + }, + "bhutan": { + "type": "string" + }, + "bicyclist": { + "type": "string" + }, + "bike": { + "type": "string" + }, + "biking_man": { + "type": "string" + }, + "biking_woman": { + "type": "string" + }, + "bikini": { + "type": "string" + }, + "billed_cap": { + "type": "string" + }, + "biohazard": { + "type": "string" + }, + "bird": { + "type": "string" + }, + "birthday": { + "type": "string" + }, + "bison": { + "type": "string" + }, + "black_cat": { + "type": "string" + }, + "black_circle": { + "type": "string" + }, + "black_flag": { + "type": "string" + }, + "black_heart": { + "type": "string" + }, + "black_joker": { + "type": "string" + }, + "black_large_square": { + "type": "string" + }, + "black_medium_small_square": { + "type": "string" + }, + "black_medium_square": { + "type": "string" + }, + "black_nib": { + "type": "string" + }, + "black_small_square": { + "type": "string" + }, + "black_square_button": { + "type": "string" + }, + "blond_haired_man": { + "type": "string" + }, + "blond_haired_person": { + "type": "string" + }, + "blond_haired_woman": { + "type": "string" + }, + "blonde_woman": { + "type": "string" + }, + "blossom": { + "type": "string" + }, + "blowfish": { + "type": "string" + }, + "blue_book": { + "type": "string" + }, + "blue_car": { + "type": "string" + }, + "blue_heart": { + "type": "string" + }, + "blue_square": { + "type": "string" + }, + "blueberries": { + "type": "string" + }, + "blush": { + "type": "string" + }, + "boar": { + "type": "string" + }, + "boat": { + "type": "string" + }, + "bolivia": { + "type": "string" + }, + "bomb": { + "type": "string" + }, + "bone": { + "type": "string" + }, + "book": { + "type": "string" + }, + "bookmark": { + "type": "string" + }, + "bookmark_tabs": { + "type": "string" + }, + "books": { + "type": "string" + }, + "boom": { + "type": "string" + }, + "boomerang": { + "type": "string" + }, + "boot": { + "type": "string" + }, + "bosnia_herzegovina": { + "type": "string" + }, + "botswana": { + "type": "string" + }, + "bouncing_ball_man": { + "type": "string" + }, + "bouncing_ball_person": { + "type": "string" + }, + "bouncing_ball_woman": { + "type": "string" + }, + "bouquet": { + "type": "string" + }, + "bouvet_island": { + "type": "string" + }, + "bow": { + "type": "string" + }, + "bow_and_arrow": { + "type": "string" + }, + "bowing_man": { + "type": "string" + }, + "bowing_woman": { + "type": "string" + }, + "bowl_with_spoon": { + "type": "string" + }, + "bowling": { + "type": "string" + }, + "bowtie": { + "type": "string" + }, + "boxing_glove": { + "type": "string" + }, + "boy": { + "type": "string" + }, + "brain": { + "type": "string" + }, + "brazil": { + "type": "string" + }, + "bread": { + "type": "string" + }, + "breast_feeding": { + "type": "string" + }, + "bricks": { + "type": "string" + }, + "bride_with_veil": { + "type": "string" + }, + "bridge_at_night": { + "type": "string" + }, + "briefcase": { + "type": "string" + }, + "british_indian_ocean_territory": { + "type": "string" + }, + "british_virgin_islands": { + "type": "string" + }, + "broccoli": { + "type": "string" + }, + "broken_heart": { + "type": "string" + }, + "broom": { + "type": "string" + }, + "brown_circle": { + "type": "string" + }, + "brown_heart": { + "type": "string" + }, + "brown_square": { + "type": "string" + }, + "brunei": { + "type": "string" + }, + "bubble_tea": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "bug": { + "type": "string" + }, + "building_construction": { + "type": "string" + }, + "bulb": { + "type": "string" + }, + "bulgaria": { + "type": "string" + }, + "bullettrain_front": { + "type": "string" + }, + "bullettrain_side": { + "type": "string" + }, + "burkina_faso": { + "type": "string" + }, + "burrito": { + "type": "string" + }, + "burundi": { + "type": "string" + }, + "bus": { + "type": "string" + }, + "business_suit_levitating": { + "type": "string" + }, + "busstop": { + "type": "string" + }, + "bust_in_silhouette": { + "type": "string" + }, + "busts_in_silhouette": { + "type": "string" + }, + "butter": { + "type": "string" + }, + "butterfly": { + "type": "string" + }, + "cactus": { + "type": "string" + }, + "cake": { + "type": "string" + }, + "calendar": { + "type": "string" + }, + "call_me_hand": { + "type": "string" + }, + "calling": { + "type": "string" + }, + "cambodia": { + "type": "string" + }, + "camel": { + "type": "string" + }, + "camera": { + "type": "string" + }, + "camera_flash": { + "type": "string" + }, + "cameroon": { + "type": "string" + }, + "camping": { + "type": "string" + }, + "canada": { + "type": "string" + }, + "canary_islands": { + "type": "string" + }, + "cancer": { + "type": "string" + }, + "candle": { + "type": "string" + }, + "candy": { + "type": "string" + }, + "canned_food": { + "type": "string" + }, + "canoe": { + "type": "string" + }, + "cape_verde": { + "type": "string" + }, + "capital_abcd": { + "type": "string" + }, + "capricorn": { + "type": "string" + }, + "car": { + "type": "string" + }, + "card_file_box": { + "type": "string" + }, + "card_index": { + "type": "string" + }, + "card_index_dividers": { + "type": "string" + }, + "caribbean_netherlands": { + "type": "string" + }, + "carousel_horse": { + "type": "string" + }, + "carpentry_saw": { + "type": "string" + }, + "carrot": { + "type": "string" + }, + "cartwheeling": { + "type": "string" + }, + "cat": { + "type": "string" + }, + "cat2": { + "type": "string" + }, + "cayman_islands": { + "type": "string" + }, + "cd": { + "type": "string" + }, + "central_african_republic": { + "type": "string" + }, + "ceuta_melilla": { + "type": "string" + }, + "chad": { + "type": "string" + }, + "chains": { + "type": "string" + }, + "chair": { + "type": "string" + }, + "champagne": { + "type": "string" + }, + "chart": { + "type": "string" + }, + "chart_with_downwards_trend": { + "type": "string" + }, + "chart_with_upwards_trend": { + "type": "string" + }, + "checkered_flag": { + "type": "string" + }, + "cheese": { + "type": "string" + }, + "cherries": { + "type": "string" + }, + "cherry_blossom": { + "type": "string" + }, + "chess_pawn": { + "type": "string" + }, + "chestnut": { + "type": "string" + }, + "chicken": { + "type": "string" + }, + "child": { + "type": "string" + }, + "children_crossing": { + "type": "string" + }, + "chile": { + "type": "string" + }, + "chipmunk": { + "type": "string" + }, + "chocolate_bar": { + "type": "string" + }, + "chopsticks": { + "type": "string" + }, + "christmas_island": { + "type": "string" + }, + "christmas_tree": { + "type": "string" + }, + "church": { + "type": "string" + }, + "cinema": { + "type": "string" + }, + "circus_tent": { + "type": "string" + }, + "city_sunrise": { + "type": "string" + }, + "city_sunset": { + "type": "string" + }, + "cityscape": { + "type": "string" + }, + "cl": { + "type": "string" + }, + "clamp": { + "type": "string" + }, + "clap": { + "type": "string" + }, + "clapper": { + "type": "string" + }, + "classical_building": { + "type": "string" + }, + "climbing": { + "type": "string" + }, + "climbing_man": { + "type": "string" + }, + "climbing_woman": { + "type": "string" + }, + "clinking_glasses": { + "type": "string" + }, + "clipboard": { + "type": "string" + }, + "clipperton_island": { + "type": "string" + }, + "clock1": { + "type": "string" + }, + "clock10": { + "type": "string" + }, + "clock1030": { + "type": "string" + }, + "clock11": { + "type": "string" + }, + "clock1130": { + "type": "string" + }, + "clock12": { + "type": "string" + }, + "clock1230": { + "type": "string" + }, + "clock130": { + "type": "string" + }, + "clock2": { + "type": "string" + }, + "clock230": { + "type": "string" + }, + "clock3": { + "type": "string" + }, + "clock330": { + "type": "string" + }, + "clock4": { + "type": "string" + }, + "clock430": { + "type": "string" + }, + "clock5": { + "type": "string" + }, + "clock530": { + "type": "string" + }, + "clock6": { + "type": "string" + }, + "clock630": { + "type": "string" + }, + "clock7": { + "type": "string" + }, + "clock730": { + "type": "string" + }, + "clock8": { + "type": "string" + }, + "clock830": { + "type": "string" + }, + "clock9": { + "type": "string" + }, + "clock930": { + "type": "string" + }, + "closed_book": { + "type": "string" + }, + "closed_lock_with_key": { + "type": "string" + }, + "closed_umbrella": { + "type": "string" + }, + "cloud": { + "type": "string" + }, + "cloud_with_lightning": { + "type": "string" + }, + "cloud_with_lightning_and_rain": { + "type": "string" + }, + "cloud_with_rain": { + "type": "string" + }, + "cloud_with_snow": { + "type": "string" + }, + "clown_face": { + "type": "string" + }, + "clubs": { + "type": "string" + }, + "cn": { + "type": "string" + }, + "coat": { + "type": "string" + }, + "cockroach": { + "type": "string" + }, + "cocktail": { + "type": "string" + }, + "coconut": { + "type": "string" + }, + "cocos_islands": { + "type": "string" + }, + "coffee": { + "type": "string" + }, + "coffin": { + "type": "string" + }, + "coin": { + "type": "string" + }, + "cold_face": { + "type": "string" + }, + "cold_sweat": { + "type": "string" + }, + "collision": { + "type": "string" + }, + "colombia": { + "type": "string" + }, + "comet": { + "type": "string" + }, + "comoros": { + "type": "string" + }, + "compass": { + "type": "string" + }, + "computer": { + "type": "string" + }, + "computer_mouse": { + "type": "string" + }, + "confetti_ball": { + "type": "string" + }, + "confounded": { + "type": "string" + }, + "confused": { + "type": "string" + }, + "congo_brazzaville": { + "type": "string" + }, + "congo_kinshasa": { + "type": "string" + }, + "congratulations": { + "type": "string" + }, + "construction": { + "type": "string" + }, + "construction_worker": { + "type": "string" + }, + "construction_worker_man": { + "type": "string" + }, + "construction_worker_woman": { + "type": "string" + }, + "control_knobs": { + "type": "string" + }, + "convenience_store": { + "type": "string" + }, + "cook": { + "type": "string" + }, + "cook_islands": { + "type": "string" + }, + "cookie": { + "type": "string" + }, + "cool": { + "type": "string" + }, + "cop": { + "type": "string" + }, + "copyright": { + "type": "string" + }, + "corn": { + "type": "string" + }, + "costa_rica": { + "type": "string" + }, + "cote_divoire": { + "type": "string" + }, + "couch_and_lamp": { + "type": "string" + }, + "couple": { + "type": "string" + }, + "couple_with_heart": { + "type": "string" + }, + "couple_with_heart_man_man": { + "type": "string" + }, + "couple_with_heart_woman_man": { + "type": "string" + }, + "couple_with_heart_woman_woman": { + "type": "string" + }, + "couplekiss": { + "type": "string" + }, + "couplekiss_man_man": { + "type": "string" + }, + "couplekiss_man_woman": { + "type": "string" + }, + "couplekiss_woman_woman": { + "type": "string" + }, + "cow": { + "type": "string" + }, + "cow2": { + "type": "string" + }, + "cowboy_hat_face": { + "type": "string" + }, + "crab": { + "type": "string" + }, + "crayon": { + "type": "string" + }, + "credit_card": { + "type": "string" + }, + "crescent_moon": { + "type": "string" + }, + "cricket": { + "type": "string" + }, + "cricket_game": { + "type": "string" + }, + "croatia": { + "type": "string" + }, + "crocodile": { + "type": "string" + }, + "croissant": { + "type": "string" + }, + "crossed_fingers": { + "type": "string" + }, + "crossed_flags": { + "type": "string" + }, + "crossed_swords": { + "type": "string" + }, + "crown": { + "type": "string" + }, + "cry": { + "type": "string" + }, + "crying_cat_face": { + "type": "string" + }, + "crystal_ball": { + "type": "string" + }, + "cuba": { + "type": "string" + }, + "cucumber": { + "type": "string" + }, + "cup_with_straw": { + "type": "string" + }, + "cupcake": { + "type": "string" + }, + "cupid": { + "type": "string" + }, + "curacao": { + "type": "string" + }, + "curling_stone": { + "type": "string" + }, + "curly_haired_man": { + "type": "string" + }, + "curly_haired_woman": { + "type": "string" + }, + "curly_loop": { + "type": "string" + }, + "currency_exchange": { + "type": "string" + }, + "curry": { + "type": "string" + }, + "cursing_face": { + "type": "string" + }, + "custard": { + "type": "string" + }, + "customs": { + "type": "string" + }, + "cut_of_meat": { + "type": "string" + }, + "cyclone": { + "type": "string" + }, + "cyprus": { + "type": "string" + }, + "czech_republic": { + "type": "string" + }, + "dagger": { + "type": "string" + }, + "dancer": { + "type": "string" + }, + "dancers": { + "type": "string" + }, + "dancing_men": { + "type": "string" + }, + "dancing_women": { + "type": "string" + }, + "dango": { + "type": "string" + }, + "dark_sunglasses": { + "type": "string" + }, + "dart": { + "type": "string" + }, + "dash": { + "type": "string" + }, + "date": { + "type": "string" + }, + "de": { + "type": "string" + }, + "deaf_man": { + "type": "string" + }, + "deaf_person": { + "type": "string" + }, + "deaf_woman": { + "type": "string" + }, + "deciduous_tree": { + "type": "string" + }, + "deer": { + "type": "string" + }, + "denmark": { + "type": "string" + }, + "department_store": { + "type": "string" + }, + "derelict_house": { + "type": "string" + }, + "desert": { + "type": "string" + }, + "desert_island": { + "type": "string" + }, + "desktop_computer": { + "type": "string" + }, + "detective": { + "type": "string" + }, + "diamond_shape_with_a_dot_inside": { + "type": "string" + }, + "diamonds": { + "type": "string" + }, + "diego_garcia": { + "type": "string" + }, + "disappointed": { + "type": "string" + }, + "disappointed_relieved": { + "type": "string" + }, + "disguised_face": { + "type": "string" + }, + "diving_mask": { + "type": "string" + }, + "diya_lamp": { + "type": "string" + }, + "dizzy": { + "type": "string" + }, + "dizzy_face": { + "type": "string" + }, + "djibouti": { + "type": "string" + }, + "dna": { + "type": "string" + }, + "do_not_litter": { + "type": "string" + }, + "dodo": { + "type": "string" + }, + "dog": { + "type": "string" + }, + "dog2": { + "type": "string" + }, + "dollar": { + "type": "string" + }, + "dolls": { + "type": "string" + }, + "dolphin": { + "type": "string" + }, + "dominica": { + "type": "string" + }, + "dominican_republic": { + "type": "string" + }, + "door": { + "type": "string" + }, + "doughnut": { + "type": "string" + }, + "dove": { + "type": "string" + }, + "dragon": { + "type": "string" + }, + "dragon_face": { + "type": "string" + }, + "dress": { + "type": "string" + }, + "dromedary_camel": { + "type": "string" + }, + "drooling_face": { + "type": "string" + }, + "drop_of_blood": { + "type": "string" + }, + "droplet": { + "type": "string" + }, + "drum": { + "type": "string" + }, + "duck": { + "type": "string" + }, + "dumpling": { + "type": "string" + }, + "dvd": { + "type": "string" + }, + "e-mail": { + "type": "string" + }, + "eagle": { + "type": "string" + }, + "ear": { + "type": "string" + }, + "ear_of_rice": { + "type": "string" + }, + "ear_with_hearing_aid": { + "type": "string" + }, + "earth_africa": { + "type": "string" + }, + "earth_americas": { + "type": "string" + }, + "earth_asia": { + "type": "string" + }, + "ecuador": { + "type": "string" + }, + "egg": { + "type": "string" + }, + "eggplant": { + "type": "string" + }, + "egypt": { + "type": "string" + }, + "eight": { + "type": "string" + }, + "eight_pointed_black_star": { + "type": "string" + }, + "eight_spoked_asterisk": { + "type": "string" + }, + "eject_button": { + "type": "string" + }, + "el_salvador": { + "type": "string" + }, + "electric_plug": { + "type": "string" + }, + "electron": { + "type": "string" + }, + "elephant": { + "type": "string" + }, + "elevator": { + "type": "string" + }, + "elf": { + "type": "string" + }, + "elf_man": { + "type": "string" + }, + "elf_woman": { + "type": "string" + }, + "email": { + "type": "string" + }, + "end": { + "type": "string" + }, + "england": { + "type": "string" + }, + "envelope": { + "type": "string" + }, + "envelope_with_arrow": { + "type": "string" + }, + "equatorial_guinea": { + "type": "string" + }, + "eritrea": { + "type": "string" + }, + "es": { + "type": "string" + }, + "estonia": { + "type": "string" + }, + "ethiopia": { + "type": "string" + }, + "eu": { + "type": "string" + }, + "euro": { + "type": "string" + }, + "european_castle": { + "type": "string" + }, + "european_post_office": { + "type": "string" + }, + "european_union": { + "type": "string" + }, + "evergreen_tree": { + "type": "string" + }, + "exclamation": { + "type": "string" + }, + "exploding_head": { + "type": "string" + }, + "expressionless": { + "type": "string" + }, + "eye": { + "type": "string" + }, + "eye_speech_bubble": { + "type": "string" + }, + "eyeglasses": { + "type": "string" + }, + "eyes": { + "type": "string" + }, + "face_exhaling": { + "type": "string" + }, + "face_in_clouds": { + "type": "string" + }, + "face_with_head_bandage": { + "type": "string" + }, + "face_with_spiral_eyes": { + "type": "string" + }, + "face_with_thermometer": { + "type": "string" + }, + "facepalm": { + "type": "string" + }, + "facepunch": { + "type": "string" + }, + "factory": { + "type": "string" + }, + "factory_worker": { + "type": "string" + }, + "fairy": { + "type": "string" + }, + "fairy_man": { + "type": "string" + }, + "fairy_woman": { + "type": "string" + }, + "falafel": { + "type": "string" + }, + "falkland_islands": { + "type": "string" + }, + "fallen_leaf": { + "type": "string" + }, + "family": { + "type": "string" + }, + "family_man_boy": { + "type": "string" + }, + "family_man_boy_boy": { + "type": "string" + }, + "family_man_girl": { + "type": "string" + }, + "family_man_girl_boy": { + "type": "string" + }, + "family_man_girl_girl": { + "type": "string" + }, + "family_man_man_boy": { + "type": "string" + }, + "family_man_man_boy_boy": { + "type": "string" + }, + "family_man_man_girl": { + "type": "string" + }, + "family_man_man_girl_boy": { + "type": "string" + }, + "family_man_man_girl_girl": { + "type": "string" + }, + "family_man_woman_boy": { + "type": "string" + }, + "family_man_woman_boy_boy": { + "type": "string" + }, + "family_man_woman_girl": { + "type": "string" + }, + "family_man_woman_girl_boy": { + "type": "string" + }, + "family_man_woman_girl_girl": { + "type": "string" + }, + "family_woman_boy": { + "type": "string" + }, + "family_woman_boy_boy": { + "type": "string" + }, + "family_woman_girl": { + "type": "string" + }, + "family_woman_girl_boy": { + "type": "string" + }, + "family_woman_girl_girl": { + "type": "string" + }, + "family_woman_woman_boy": { + "type": "string" + }, + "family_woman_woman_boy_boy": { + "type": "string" + }, + "family_woman_woman_girl": { + "type": "string" + }, + "family_woman_woman_girl_boy": { + "type": "string" + }, + "family_woman_woman_girl_girl": { + "type": "string" + }, + "farmer": { + "type": "string" + }, + "faroe_islands": { + "type": "string" + }, + "fast_forward": { + "type": "string" + }, + "fax": { + "type": "string" + }, + "fearful": { + "type": "string" + }, + "feather": { + "type": "string" + }, + "feelsgood": { + "type": "string" + }, + "feet": { + "type": "string" + }, + "female_detective": { + "type": "string" + }, + "female_sign": { + "type": "string" + }, + "ferris_wheel": { + "type": "string" + }, + "ferry": { + "type": "string" + }, + "field_hockey": { + "type": "string" + }, + "fiji": { + "type": "string" + }, + "file_cabinet": { + "type": "string" + }, + "file_folder": { + "type": "string" + }, + "film_projector": { + "type": "string" + }, + "film_strip": { + "type": "string" + }, + "finland": { + "type": "string" + }, + "finnadie": { + "type": "string" + }, + "fire": { + "type": "string" + }, + "fire_engine": { + "type": "string" + }, + "fire_extinguisher": { + "type": "string" + }, + "firecracker": { + "type": "string" + }, + "firefighter": { + "type": "string" + }, + "fireworks": { + "type": "string" + }, + "first_quarter_moon": { + "type": "string" + }, + "first_quarter_moon_with_face": { + "type": "string" + }, + "fish": { + "type": "string" + }, + "fish_cake": { + "type": "string" + }, + "fishing_pole_and_fish": { + "type": "string" + }, + "fist": { + "type": "string" + }, + "fist_left": { + "type": "string" + }, + "fist_oncoming": { + "type": "string" + }, + "fist_raised": { + "type": "string" + }, + "fist_right": { + "type": "string" + }, + "five": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "flamingo": { + "type": "string" + }, + "flashlight": { + "type": "string" + }, + "flat_shoe": { + "type": "string" + }, + "flatbread": { + "type": "string" + }, + "fleur_de_lis": { + "type": "string" + }, + "flight_arrival": { + "type": "string" + }, + "flight_departure": { + "type": "string" + }, + "flipper": { + "type": "string" + }, + "floppy_disk": { + "type": "string" + }, + "flower_playing_cards": { + "type": "string" + }, + "flushed": { + "type": "string" + }, + "fly": { + "type": "string" + }, + "flying_disc": { + "type": "string" + }, + "flying_saucer": { + "type": "string" + }, + "fog": { + "type": "string" + }, + "foggy": { + "type": "string" + }, + "fondue": { + "type": "string" + }, + "foot": { + "type": "string" + }, + "football": { + "type": "string" + }, + "footprints": { + "type": "string" + }, + "fork_and_knife": { + "type": "string" + }, + "fortune_cookie": { + "type": "string" + }, + "fountain": { + "type": "string" + }, + "fountain_pen": { + "type": "string" + }, + "four": { + "type": "string" + }, + "four_leaf_clover": { + "type": "string" + }, + "fox_face": { + "type": "string" + }, + "fr": { + "type": "string" + }, + "framed_picture": { + "type": "string" + }, + "free": { + "type": "string" + }, + "french_guiana": { + "type": "string" + }, + "french_polynesia": { + "type": "string" + }, + "french_southern_territories": { + "type": "string" + }, + "fried_egg": { + "type": "string" + }, + "fried_shrimp": { + "type": "string" + }, + "fries": { + "type": "string" + }, + "frog": { + "type": "string" + }, + "frowning": { + "type": "string" + }, + "frowning_face": { + "type": "string" + }, + "frowning_man": { + "type": "string" + }, + "frowning_person": { + "type": "string" + }, + "frowning_woman": { + "type": "string" + }, + "fu": { + "type": "string" + }, + "fuelpump": { + "type": "string" + }, + "full_moon": { + "type": "string" + }, + "full_moon_with_face": { + "type": "string" + }, + "funeral_urn": { + "type": "string" + }, + "gabon": { + "type": "string" + }, + "gambia": { + "type": "string" + }, + "game_die": { + "type": "string" + }, + "garlic": { + "type": "string" + }, + "gb": { + "type": "string" + }, + "gear": { + "type": "string" + }, + "gem": { + "type": "string" + }, + "gemini": { + "type": "string" + }, + "genie": { + "type": "string" + }, + "genie_man": { + "type": "string" + }, + "genie_woman": { + "type": "string" + }, + "georgia": { + "type": "string" + }, + "ghana": { + "type": "string" + }, + "ghost": { + "type": "string" + }, + "gibraltar": { + "type": "string" + }, + "gift": { + "type": "string" + }, + "gift_heart": { + "type": "string" + }, + "giraffe": { + "type": "string" + }, + "girl": { + "type": "string" + }, + "globe_with_meridians": { + "type": "string" + }, + "gloves": { + "type": "string" + }, + "goal_net": { + "type": "string" + }, + "goat": { + "type": "string" + }, + "goberserk": { + "type": "string" + }, + "godmode": { + "type": "string" + }, + "goggles": { + "type": "string" + }, + "golf": { + "type": "string" + }, + "golfing": { + "type": "string" + }, + "golfing_man": { + "type": "string" + }, + "golfing_woman": { + "type": "string" + }, + "gorilla": { + "type": "string" + }, + "grapes": { + "type": "string" + }, + "greece": { + "type": "string" + }, + "green_apple": { + "type": "string" + }, + "green_book": { + "type": "string" + }, + "green_circle": { + "type": "string" + }, + "green_heart": { + "type": "string" + }, + "green_salad": { + "type": "string" + }, + "green_square": { + "type": "string" + }, + "greenland": { + "type": "string" + }, + "grenada": { + "type": "string" + }, + "grey_exclamation": { + "type": "string" + }, + "grey_question": { + "type": "string" + }, + "grimacing": { + "type": "string" + }, + "grin": { + "type": "string" + }, + "grinning": { + "type": "string" + }, + "guadeloupe": { + "type": "string" + }, + "guam": { + "type": "string" + }, + "guard": { + "type": "string" + }, + "guardsman": { + "type": "string" + }, + "guardswoman": { + "type": "string" + }, + "guatemala": { + "type": "string" + }, + "guernsey": { + "type": "string" + }, + "guide_dog": { + "type": "string" + }, + "guinea": { + "type": "string" + }, + "guinea_bissau": { + "type": "string" + }, + "guitar": { + "type": "string" + }, + "gun": { + "type": "string" + }, + "guyana": { + "type": "string" + }, + "haircut": { + "type": "string" + }, + "haircut_man": { + "type": "string" + }, + "haircut_woman": { + "type": "string" + }, + "haiti": { + "type": "string" + }, + "hamburger": { + "type": "string" + }, + "hammer": { + "type": "string" + }, + "hammer_and_pick": { + "type": "string" + }, + "hammer_and_wrench": { + "type": "string" + }, + "hamster": { + "type": "string" + }, + "hand": { + "type": "string" + }, + "hand_over_mouth": { + "type": "string" + }, + "handbag": { + "type": "string" + }, + "handball_person": { + "type": "string" + }, + "handshake": { + "type": "string" + }, + "hankey": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hatched_chick": { + "type": "string" + }, + "hatching_chick": { + "type": "string" + }, + "headphones": { + "type": "string" + }, + "headstone": { + "type": "string" + }, + "health_worker": { + "type": "string" + }, + "hear_no_evil": { + "type": "string" + }, + "heard_mcdonald_islands": { + "type": "string" + }, + "heart": { + "type": "string" + }, + "heart_decoration": { + "type": "string" + }, + "heart_eyes": { + "type": "string" + }, + "heart_eyes_cat": { + "type": "string" + }, + "heart_on_fire": { + "type": "string" + }, + "heartbeat": { + "type": "string" + }, + "heartpulse": { + "type": "string" + }, + "hearts": { + "type": "string" + }, + "heavy_check_mark": { + "type": "string" + }, + "heavy_division_sign": { + "type": "string" + }, + "heavy_dollar_sign": { + "type": "string" + }, + "heavy_exclamation_mark": { + "type": "string" + }, + "heavy_heart_exclamation": { + "type": "string" + }, + "heavy_minus_sign": { + "type": "string" + }, + "heavy_multiplication_x": { + "type": "string" + }, + "heavy_plus_sign": { + "type": "string" + }, + "hedgehog": { + "type": "string" + }, + "helicopter": { + "type": "string" + }, + "herb": { + "type": "string" + }, + "hibiscus": { + "type": "string" + }, + "high_brightness": { + "type": "string" + }, + "high_heel": { + "type": "string" + }, + "hiking_boot": { + "type": "string" + }, + "hindu_temple": { + "type": "string" + }, + "hippopotamus": { + "type": "string" + }, + "hocho": { + "type": "string" + }, + "hole": { + "type": "string" + }, + "honduras": { + "type": "string" + }, + "honey_pot": { + "type": "string" + }, + "honeybee": { + "type": "string" + }, + "hong_kong": { + "type": "string" + }, + "hook": { + "type": "string" + }, + "horse": { + "type": "string" + }, + "horse_racing": { + "type": "string" + }, + "hospital": { + "type": "string" + }, + "hot_face": { + "type": "string" + }, + "hot_pepper": { + "type": "string" + }, + "hotdog": { + "type": "string" + }, + "hotel": { + "type": "string" + }, + "hotsprings": { + "type": "string" + }, + "hourglass": { + "type": "string" + }, + "hourglass_flowing_sand": { + "type": "string" + }, + "house": { + "type": "string" + }, + "house_with_garden": { + "type": "string" + }, + "houses": { + "type": "string" + }, + "hugs": { + "type": "string" + }, + "hungary": { + "type": "string" + }, + "hurtrealbad": { + "type": "string" + }, + "hushed": { + "type": "string" + }, + "hut": { + "type": "string" + }, + "ice_cream": { + "type": "string" + }, + "ice_cube": { + "type": "string" + }, + "ice_hockey": { + "type": "string" + }, + "ice_skate": { + "type": "string" + }, + "icecream": { + "type": "string" + }, + "iceland": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ideograph_advantage": { + "type": "string" + }, + "imp": { + "type": "string" + }, + "inbox_tray": { + "type": "string" + }, + "incoming_envelope": { + "type": "string" + }, + "india": { + "type": "string" + }, + "indonesia": { + "type": "string" + }, + "infinity": { + "type": "string" + }, + "information_desk_person": { + "type": "string" + }, + "information_source": { + "type": "string" + }, + "innocent": { + "type": "string" + }, + "interrobang": { + "type": "string" + }, + "iphone": { + "type": "string" + }, + "iran": { + "type": "string" + }, + "iraq": { + "type": "string" + }, + "ireland": { + "type": "string" + }, + "isle_of_man": { + "type": "string" + }, + "israel": { + "type": "string" + }, + "it": { + "type": "string" + }, + "izakaya_lantern": { + "type": "string" + }, + "jack_o_lantern": { + "type": "string" + }, + "jamaica": { + "type": "string" + }, + "japan": { + "type": "string" + }, + "japanese_castle": { + "type": "string" + }, + "japanese_goblin": { + "type": "string" + }, + "japanese_ogre": { + "type": "string" + }, + "jeans": { + "type": "string" + }, + "jersey": { + "type": "string" + }, + "jigsaw": { + "type": "string" + }, + "jordan": { + "type": "string" + }, + "joy": { + "type": "string" + }, + "joy_cat": { + "type": "string" + }, + "joystick": { + "type": "string" + }, + "jp": { + "type": "string" + }, + "judge": { + "type": "string" + }, + "juggling_person": { + "type": "string" + }, + "kaaba": { + "type": "string" + }, + "kangaroo": { + "type": "string" + }, + "kazakhstan": { + "type": "string" + }, + "kenya": { + "type": "string" + }, + "key": { + "type": "string" + }, + "keyboard": { + "type": "string" + }, + "keycap_ten": { + "type": "string" + }, + "kick_scooter": { + "type": "string" + }, + "kimono": { + "type": "string" + }, + "kiribati": { + "type": "string" + }, + "kiss": { + "type": "string" + }, + "kissing": { + "type": "string" + }, + "kissing_cat": { + "type": "string" + }, + "kissing_closed_eyes": { + "type": "string" + }, + "kissing_heart": { + "type": "string" + }, + "kissing_smiling_eyes": { + "type": "string" + }, + "kite": { + "type": "string" + }, + "kiwi_fruit": { + "type": "string" + }, + "kneeling_man": { + "type": "string" + }, + "kneeling_person": { + "type": "string" + }, + "kneeling_woman": { + "type": "string" + }, + "knife": { + "type": "string" + }, + "knot": { + "type": "string" + }, + "koala": { + "type": "string" + }, + "koko": { + "type": "string" + }, + "kosovo": { + "type": "string" + }, + "kr": { + "type": "string" + }, + "kuwait": { + "type": "string" + }, + "kyrgyzstan": { + "type": "string" + }, + "lab_coat": { + "type": "string" + }, + "label": { + "type": "string" + }, + "lacrosse": { + "type": "string" + }, + "ladder": { + "type": "string" + }, + "lady_beetle": { + "type": "string" + }, + "lantern": { + "type": "string" + }, + "laos": { + "type": "string" + }, + "large_blue_circle": { + "type": "string" + }, + "large_blue_diamond": { + "type": "string" + }, + "large_orange_diamond": { + "type": "string" + }, + "last_quarter_moon": { + "type": "string" + }, + "last_quarter_moon_with_face": { + "type": "string" + }, + "latin_cross": { + "type": "string" + }, + "latvia": { + "type": "string" + }, + "laughing": { + "type": "string" + }, + "leafy_green": { + "type": "string" + }, + "leaves": { + "type": "string" + }, + "lebanon": { + "type": "string" + }, + "ledger": { + "type": "string" + }, + "left_luggage": { + "type": "string" + }, + "left_right_arrow": { + "type": "string" + }, + "left_speech_bubble": { + "type": "string" + }, + "leftwards_arrow_with_hook": { + "type": "string" + }, + "leg": { + "type": "string" + }, + "lemon": { + "type": "string" + }, + "leo": { + "type": "string" + }, + "leopard": { + "type": "string" + }, + "lesotho": { + "type": "string" + }, + "level_slider": { + "type": "string" + }, + "liberia": { + "type": "string" + }, + "libra": { + "type": "string" + }, + "libya": { + "type": "string" + }, + "liechtenstein": { + "type": "string" + }, + "light_rail": { + "type": "string" + }, + "link": { + "type": "string" + }, + "lion": { + "type": "string" + }, + "lips": { + "type": "string" + }, + "lipstick": { + "type": "string" + }, + "lithuania": { + "type": "string" + }, + "lizard": { + "type": "string" + }, + "llama": { + "type": "string" + }, + "lobster": { + "type": "string" + }, + "lock": { + "type": "string" + }, + "lock_with_ink_pen": { + "type": "string" + }, + "lollipop": { + "type": "string" + }, + "long_drum": { + "type": "string" + }, + "loop": { + "type": "string" + }, + "lotion_bottle": { + "type": "string" + }, + "lotus_position": { + "type": "string" + }, + "lotus_position_man": { + "type": "string" + }, + "lotus_position_woman": { + "type": "string" + }, + "loud_sound": { + "type": "string" + }, + "loudspeaker": { + "type": "string" + }, + "love_hotel": { + "type": "string" + }, + "love_letter": { + "type": "string" + }, + "love_you_gesture": { + "type": "string" + }, + "low_brightness": { + "type": "string" + }, + "luggage": { + "type": "string" + }, + "lungs": { + "type": "string" + }, + "luxembourg": { + "type": "string" + }, + "lying_face": { + "type": "string" + }, + "m": { + "type": "string" + }, + "macau": { + "type": "string" + }, + "macedonia": { + "type": "string" + }, + "madagascar": { + "type": "string" + }, + "mag": { + "type": "string" + }, + "mag_right": { + "type": "string" + }, + "mage": { + "type": "string" + }, + "mage_man": { + "type": "string" + }, + "mage_woman": { + "type": "string" + }, + "magic_wand": { + "type": "string" + }, + "magnet": { + "type": "string" + }, + "mahjong": { + "type": "string" + }, + "mailbox": { + "type": "string" + }, + "mailbox_closed": { + "type": "string" + }, + "mailbox_with_mail": { + "type": "string" + }, + "mailbox_with_no_mail": { + "type": "string" + }, + "malawi": { + "type": "string" + }, + "malaysia": { + "type": "string" + }, + "maldives": { + "type": "string" + }, + "male_detective": { + "type": "string" + }, + "male_sign": { + "type": "string" + }, + "mali": { + "type": "string" + }, + "malta": { + "type": "string" + }, + "mammoth": { + "type": "string" + }, + "man": { + "type": "string" + }, + "man_artist": { + "type": "string" + }, + "man_astronaut": { + "type": "string" + }, + "man_beard": { + "type": "string" + }, + "man_cartwheeling": { + "type": "string" + }, + "man_cook": { + "type": "string" + }, + "man_dancing": { + "type": "string" + }, + "man_facepalming": { + "type": "string" + }, + "man_factory_worker": { + "type": "string" + }, + "man_farmer": { + "type": "string" + }, + "man_feeding_baby": { + "type": "string" + }, + "man_firefighter": { + "type": "string" + }, + "man_health_worker": { + "type": "string" + }, + "man_in_manual_wheelchair": { + "type": "string" + }, + "man_in_motorized_wheelchair": { + "type": "string" + }, + "man_in_tuxedo": { + "type": "string" + }, + "man_judge": { + "type": "string" + }, + "man_juggling": { + "type": "string" + }, + "man_mechanic": { + "type": "string" + }, + "man_office_worker": { + "type": "string" + }, + "man_pilot": { + "type": "string" + }, + "man_playing_handball": { + "type": "string" + }, + "man_playing_water_polo": { + "type": "string" + }, + "man_scientist": { + "type": "string" + }, + "man_shrugging": { + "type": "string" + }, + "man_singer": { + "type": "string" + }, + "man_student": { + "type": "string" + }, + "man_teacher": { + "type": "string" + }, + "man_technologist": { + "type": "string" + }, + "man_with_gua_pi_mao": { + "type": "string" + }, + "man_with_probing_cane": { + "type": "string" + }, + "man_with_turban": { + "type": "string" + }, + "man_with_veil": { + "type": "string" + }, + "mandarin": { + "type": "string" + }, + "mango": { + "type": "string" + }, + "mans_shoe": { + "type": "string" + }, + "mantelpiece_clock": { + "type": "string" + }, + "manual_wheelchair": { + "type": "string" + }, + "maple_leaf": { + "type": "string" + }, + "marshall_islands": { + "type": "string" + }, + "martial_arts_uniform": { + "type": "string" + }, + "martinique": { + "type": "string" + }, + "mask": { + "type": "string" + }, + "massage": { + "type": "string" + }, + "massage_man": { + "type": "string" + }, + "massage_woman": { + "type": "string" + }, + "mate": { + "type": "string" + }, + "mauritania": { + "type": "string" + }, + "mauritius": { + "type": "string" + }, + "mayotte": { + "type": "string" + }, + "meat_on_bone": { + "type": "string" + }, + "mechanic": { + "type": "string" + }, + "mechanical_arm": { + "type": "string" + }, + "mechanical_leg": { + "type": "string" + }, + "medal_military": { + "type": "string" + }, + "medal_sports": { + "type": "string" + }, + "medical_symbol": { + "type": "string" + }, + "mega": { + "type": "string" + }, + "melon": { + "type": "string" + }, + "memo": { + "type": "string" + }, + "men_wrestling": { + "type": "string" + }, + "mending_heart": { + "type": "string" + }, + "menorah": { + "type": "string" + }, + "mens": { + "type": "string" + }, + "mermaid": { + "type": "string" + }, + "merman": { + "type": "string" + }, + "merperson": { + "type": "string" + }, + "metal": { + "type": "string" + }, + "metro": { + "type": "string" + }, + "mexico": { + "type": "string" + }, + "microbe": { + "type": "string" + }, + "micronesia": { + "type": "string" + }, + "microphone": { + "type": "string" + }, + "microscope": { + "type": "string" + }, + "middle_finger": { + "type": "string" + }, + "military_helmet": { + "type": "string" + }, + "milk_glass": { + "type": "string" + }, + "milky_way": { + "type": "string" + }, + "minibus": { + "type": "string" + }, + "minidisc": { + "type": "string" + }, + "mirror": { + "type": "string" + }, + "mobile_phone_off": { + "type": "string" + }, + "moldova": { + "type": "string" + }, + "monaco": { + "type": "string" + }, + "money_mouth_face": { + "type": "string" + }, + "money_with_wings": { + "type": "string" + }, + "moneybag": { + "type": "string" + }, + "mongolia": { + "type": "string" + }, + "monkey": { + "type": "string" + }, + "monkey_face": { + "type": "string" + }, + "monocle_face": { + "type": "string" + }, + "monorail": { + "type": "string" + }, + "montenegro": { + "type": "string" + }, + "montserrat": { + "type": "string" + }, + "moon": { + "type": "string" + }, + "moon_cake": { + "type": "string" + }, + "morocco": { + "type": "string" + }, + "mortar_board": { + "type": "string" + }, + "mosque": { + "type": "string" + }, + "mosquito": { + "type": "string" + }, + "motor_boat": { + "type": "string" + }, + "motor_scooter": { + "type": "string" + }, + "motorcycle": { + "type": "string" + }, + "motorized_wheelchair": { + "type": "string" + }, + "motorway": { + "type": "string" + }, + "mount_fuji": { + "type": "string" + }, + "mountain": { + "type": "string" + }, + "mountain_bicyclist": { + "type": "string" + }, + "mountain_biking_man": { + "type": "string" + }, + "mountain_biking_woman": { + "type": "string" + }, + "mountain_cableway": { + "type": "string" + }, + "mountain_railway": { + "type": "string" + }, + "mountain_snow": { + "type": "string" + }, + "mouse": { + "type": "string" + }, + "mouse2": { + "type": "string" + }, + "mouse_trap": { + "type": "string" + }, + "movie_camera": { + "type": "string" + }, + "moyai": { + "type": "string" + }, + "mozambique": { + "type": "string" + }, + "mrs_claus": { + "type": "string" + }, + "muscle": { + "type": "string" + }, + "mushroom": { + "type": "string" + }, + "musical_keyboard": { + "type": "string" + }, + "musical_note": { + "type": "string" + }, + "musical_score": { + "type": "string" + }, + "mute": { + "type": "string" + }, + "mx_claus": { + "type": "string" + }, + "myanmar": { + "type": "string" + }, + "nail_care": { + "type": "string" + }, + "name_badge": { + "type": "string" + }, + "namibia": { + "type": "string" + }, + "national_park": { + "type": "string" + }, + "nauru": { + "type": "string" + }, + "nauseated_face": { + "type": "string" + }, + "nazar_amulet": { + "type": "string" + }, + "neckbeard": { + "type": "string" + }, + "necktie": { + "type": "string" + }, + "negative_squared_cross_mark": { + "type": "string" + }, + "nepal": { + "type": "string" + }, + "nerd_face": { + "type": "string" + }, + "nesting_dolls": { + "type": "string" + }, + "netherlands": { + "type": "string" + }, + "neutral_face": { + "type": "string" + }, + "new": { + "type": "string" + }, + "new_caledonia": { + "type": "string" + }, + "new_moon": { + "type": "string" + }, + "new_moon_with_face": { + "type": "string" + }, + "new_zealand": { + "type": "string" + }, + "newspaper": { + "type": "string" + }, + "newspaper_roll": { + "type": "string" + }, + "next_track_button": { + "type": "string" + }, + "ng": { + "type": "string" + }, + "ng_man": { + "type": "string" + }, + "ng_woman": { + "type": "string" + }, + "nicaragua": { + "type": "string" + }, + "niger": { + "type": "string" + }, + "nigeria": { + "type": "string" + }, + "night_with_stars": { + "type": "string" + }, + "nine": { + "type": "string" + }, + "ninja": { + "type": "string" + }, + "niue": { + "type": "string" + }, + "no_bell": { + "type": "string" + }, + "no_bicycles": { + "type": "string" + }, + "no_entry": { + "type": "string" + }, + "no_entry_sign": { + "type": "string" + }, + "no_good": { + "type": "string" + }, + "no_good_man": { + "type": "string" + }, + "no_good_woman": { + "type": "string" + }, + "no_mobile_phones": { + "type": "string" + }, + "no_mouth": { + "type": "string" + }, + "no_pedestrians": { + "type": "string" + }, + "no_smoking": { + "type": "string" + }, + "non-potable_water": { + "type": "string" + }, + "norfolk_island": { + "type": "string" + }, + "north_korea": { + "type": "string" + }, + "northern_mariana_islands": { + "type": "string" + }, + "norway": { + "type": "string" + }, + "nose": { + "type": "string" + }, + "notebook": { + "type": "string" + }, + "notebook_with_decorative_cover": { + "type": "string" + }, + "notes": { + "type": "string" + }, + "nut_and_bolt": { + "type": "string" + }, + "o": { + "type": "string" + }, + "o2": { + "type": "string" + }, + "ocean": { + "type": "string" + }, + "octocat": { + "type": "string" + }, + "octopus": { + "type": "string" + }, + "oden": { + "type": "string" + }, + "office": { + "type": "string" + }, + "office_worker": { + "type": "string" + }, + "oil_drum": { + "type": "string" + }, + "ok": { + "type": "string" + }, + "ok_hand": { + "type": "string" + }, + "ok_man": { + "type": "string" + }, + "ok_person": { + "type": "string" + }, + "ok_woman": { + "type": "string" + }, + "old_key": { + "type": "string" + }, + "older_adult": { + "type": "string" + }, + "older_man": { + "type": "string" + }, + "older_woman": { + "type": "string" + }, + "olive": { + "type": "string" + }, + "om": { + "type": "string" + }, + "oman": { + "type": "string" + }, + "on": { + "type": "string" + }, + "oncoming_automobile": { + "type": "string" + }, + "oncoming_bus": { + "type": "string" + }, + "oncoming_police_car": { + "type": "string" + }, + "oncoming_taxi": { + "type": "string" + }, + "one": { + "type": "string" + }, + "one_piece_swimsuit": { + "type": "string" + }, + "onion": { + "type": "string" + }, + "open_book": { + "type": "string" + }, + "open_file_folder": { + "type": "string" + }, + "open_hands": { + "type": "string" + }, + "open_mouth": { + "type": "string" + }, + "open_umbrella": { + "type": "string" + }, + "ophiuchus": { + "type": "string" + }, + "orange": { + "type": "string" + }, + "orange_book": { + "type": "string" + }, + "orange_circle": { + "type": "string" + }, + "orange_heart": { + "type": "string" + }, + "orange_square": { + "type": "string" + }, + "orangutan": { + "type": "string" + }, + "orthodox_cross": { + "type": "string" + }, + "otter": { + "type": "string" + }, + "outbox_tray": { + "type": "string" + }, + "owl": { + "type": "string" + }, + "ox": { + "type": "string" + }, + "oyster": { + "type": "string" + }, + "package": { + "type": "string" + }, + "page_facing_up": { + "type": "string" + }, + "page_with_curl": { + "type": "string" + }, + "pager": { + "type": "string" + }, + "paintbrush": { + "type": "string" + }, + "pakistan": { + "type": "string" + }, + "palau": { + "type": "string" + }, + "palestinian_territories": { + "type": "string" + }, + "palm_tree": { + "type": "string" + }, + "palms_up_together": { + "type": "string" + }, + "panama": { + "type": "string" + }, + "pancakes": { + "type": "string" + }, + "panda_face": { + "type": "string" + }, + "paperclip": { + "type": "string" + }, + "paperclips": { + "type": "string" + }, + "papua_new_guinea": { + "type": "string" + }, + "parachute": { + "type": "string" + }, + "paraguay": { + "type": "string" + }, + "parasol_on_ground": { + "type": "string" + }, + "parking": { + "type": "string" + }, + "parrot": { + "type": "string" + }, + "part_alternation_mark": { + "type": "string" + }, + "partly_sunny": { + "type": "string" + }, + "partying_face": { + "type": "string" + }, + "passenger_ship": { + "type": "string" + }, + "passport_control": { + "type": "string" + }, + "pause_button": { + "type": "string" + }, + "paw_prints": { + "type": "string" + }, + "peace_symbol": { + "type": "string" + }, + "peach": { + "type": "string" + }, + "peacock": { + "type": "string" + }, + "peanuts": { + "type": "string" + }, + "pear": { + "type": "string" + }, + "pen": { + "type": "string" + }, + "pencil": { + "type": "string" + }, + "pencil2": { + "type": "string" + }, + "penguin": { + "type": "string" + }, + "pensive": { + "type": "string" + }, + "people_holding_hands": { + "type": "string" + }, + "people_hugging": { + "type": "string" + }, + "performing_arts": { + "type": "string" + }, + "persevere": { + "type": "string" + }, + "person_bald": { + "type": "string" + }, + "person_curly_hair": { + "type": "string" + }, + "person_feeding_baby": { + "type": "string" + }, + "person_fencing": { + "type": "string" + }, + "person_in_manual_wheelchair": { + "type": "string" + }, + "person_in_motorized_wheelchair": { + "type": "string" + }, + "person_in_tuxedo": { + "type": "string" + }, + "person_red_hair": { + "type": "string" + }, + "person_white_hair": { + "type": "string" + }, + "person_with_probing_cane": { + "type": "string" + }, + "person_with_turban": { + "type": "string" + }, + "person_with_veil": { + "type": "string" + }, + "peru": { + "type": "string" + }, + "petri_dish": { + "type": "string" + }, + "philippines": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "pick": { + "type": "string" + }, + "pickup_truck": { + "type": "string" + }, + "pie": { + "type": "string" + }, + "pig": { + "type": "string" + }, + "pig2": { + "type": "string" + }, + "pig_nose": { + "type": "string" + }, + "pill": { + "type": "string" + }, + "pilot": { + "type": "string" + }, + "pinata": { + "type": "string" + }, + "pinched_fingers": { + "type": "string" + }, + "pinching_hand": { + "type": "string" + }, + "pineapple": { + "type": "string" + }, + "ping_pong": { + "type": "string" + }, + "pirate_flag": { + "type": "string" + }, + "pisces": { + "type": "string" + }, + "pitcairn_islands": { + "type": "string" + }, + "pizza": { + "type": "string" + }, + "placard": { + "type": "string" + }, + "place_of_worship": { + "type": "string" + }, + "plate_with_cutlery": { + "type": "string" + }, + "play_or_pause_button": { + "type": "string" + }, + "pleading_face": { + "type": "string" + }, + "plunger": { + "type": "string" + }, + "point_down": { + "type": "string" + }, + "point_left": { + "type": "string" + }, + "point_right": { + "type": "string" + }, + "point_up": { + "type": "string" + }, + "point_up_2": { + "type": "string" + }, + "poland": { + "type": "string" + }, + "polar_bear": { + "type": "string" + }, + "police_car": { + "type": "string" + }, + "police_officer": { + "type": "string" + }, + "policeman": { + "type": "string" + }, + "policewoman": { + "type": "string" + }, + "poodle": { + "type": "string" + }, + "poop": { + "type": "string" + }, + "popcorn": { + "type": "string" + }, + "portugal": { + "type": "string" + }, + "post_office": { + "type": "string" + }, + "postal_horn": { + "type": "string" + }, + "postbox": { + "type": "string" + }, + "potable_water": { + "type": "string" + }, + "potato": { + "type": "string" + }, + "potted_plant": { + "type": "string" + }, + "pouch": { + "type": "string" + }, + "poultry_leg": { + "type": "string" + }, + "pound": { + "type": "string" + }, + "pout": { + "type": "string" + }, + "pouting_cat": { + "type": "string" + }, + "pouting_face": { + "type": "string" + }, + "pouting_man": { + "type": "string" + }, + "pouting_woman": { + "type": "string" + }, + "pray": { + "type": "string" + }, + "prayer_beads": { + "type": "string" + }, + "pregnant_woman": { + "type": "string" + }, + "pretzel": { + "type": "string" + }, + "previous_track_button": { + "type": "string" + }, + "prince": { + "type": "string" + }, + "princess": { + "type": "string" + }, + "printer": { + "type": "string" + }, + "probing_cane": { + "type": "string" + }, + "puerto_rico": { + "type": "string" + }, + "punch": { + "type": "string" + }, + "purple_circle": { + "type": "string" + }, + "purple_heart": { + "type": "string" + }, + "purple_square": { + "type": "string" + }, + "purse": { + "type": "string" + }, + "pushpin": { + "type": "string" + }, + "put_litter_in_its_place": { + "type": "string" + }, + "qatar": { + "type": "string" + }, + "question": { + "type": "string" + }, + "rabbit": { + "type": "string" + }, + "rabbit2": { + "type": "string" + }, + "raccoon": { + "type": "string" + }, + "racehorse": { + "type": "string" + }, + "racing_car": { + "type": "string" + }, + "radio": { + "type": "string" + }, + "radio_button": { + "type": "string" + }, + "radioactive": { + "type": "string" + }, + "rage": { + "type": "string" + }, + "rage1": { + "type": "string" + }, + "rage2": { + "type": "string" + }, + "rage3": { + "type": "string" + }, + "rage4": { + "type": "string" + }, + "railway_car": { + "type": "string" + }, + "railway_track": { + "type": "string" + }, + "rainbow": { + "type": "string" + }, + "rainbow_flag": { + "type": "string" + }, + "raised_back_of_hand": { + "type": "string" + }, + "raised_eyebrow": { + "type": "string" + }, + "raised_hand": { + "type": "string" + }, + "raised_hand_with_fingers_splayed": { + "type": "string" + }, + "raised_hands": { + "type": "string" + }, + "raising_hand": { + "type": "string" + }, + "raising_hand_man": { + "type": "string" + }, + "raising_hand_woman": { + "type": "string" + }, + "ram": { + "type": "string" + }, + "ramen": { + "type": "string" + }, + "rat": { + "type": "string" + }, + "razor": { + "type": "string" + }, + "receipt": { + "type": "string" + }, + "record_button": { + "type": "string" + }, + "recycle": { + "type": "string" + }, + "red_car": { + "type": "string" + }, + "red_circle": { + "type": "string" + }, + "red_envelope": { + "type": "string" + }, + "red_haired_man": { + "type": "string" + }, + "red_haired_woman": { + "type": "string" + }, + "red_square": { + "type": "string" + }, + "registered": { + "type": "string" + }, + "relaxed": { + "type": "string" + }, + "relieved": { + "type": "string" + }, + "reminder_ribbon": { + "type": "string" + }, + "repeat": { + "type": "string" + }, + "repeat_one": { + "type": "string" + }, + "rescue_worker_helmet": { + "type": "string" + }, + "restroom": { + "type": "string" + }, + "reunion": { + "type": "string" + }, + "revolving_hearts": { + "type": "string" + }, + "rewind": { + "type": "string" + }, + "rhinoceros": { + "type": "string" + }, + "ribbon": { + "type": "string" + }, + "rice": { + "type": "string" + }, + "rice_ball": { + "type": "string" + }, + "rice_cracker": { + "type": "string" + }, + "rice_scene": { + "type": "string" + }, + "right_anger_bubble": { + "type": "string" + }, + "ring": { + "type": "string" + }, + "ringed_planet": { + "type": "string" + }, + "robot": { + "type": "string" + }, + "rock": { + "type": "string" + }, + "rocket": { + "type": "string" + }, + "rofl": { + "type": "string" + }, + "roll_eyes": { + "type": "string" + }, + "roll_of_paper": { + "type": "string" + }, + "roller_coaster": { + "type": "string" + }, + "roller_skate": { + "type": "string" + }, + "romania": { + "type": "string" + }, + "rooster": { + "type": "string" + }, + "rose": { + "type": "string" + }, + "rosette": { + "type": "string" + }, + "rotating_light": { + "type": "string" + }, + "round_pushpin": { + "type": "string" + }, + "rowboat": { + "type": "string" + }, + "rowing_man": { + "type": "string" + }, + "rowing_woman": { + "type": "string" + }, + "ru": { + "type": "string" + }, + "rugby_football": { + "type": "string" + }, + "runner": { + "type": "string" + }, + "running": { + "type": "string" + }, + "running_man": { + "type": "string" + }, + "running_shirt_with_sash": { + "type": "string" + }, + "running_woman": { + "type": "string" + }, + "rwanda": { + "type": "string" + }, + "sa": { + "type": "string" + }, + "safety_pin": { + "type": "string" + }, + "safety_vest": { + "type": "string" + }, + "sagittarius": { + "type": "string" + }, + "sailboat": { + "type": "string" + }, + "sake": { + "type": "string" + }, + "salt": { + "type": "string" + }, + "samoa": { + "type": "string" + }, + "san_marino": { + "type": "string" + }, + "sandal": { + "type": "string" + }, + "sandwich": { + "type": "string" + }, + "santa": { + "type": "string" + }, + "sao_tome_principe": { + "type": "string" + }, + "sari": { + "type": "string" + }, + "sassy_man": { + "type": "string" + }, + "sassy_woman": { + "type": "string" + }, + "satellite": { + "type": "string" + }, + "satisfied": { + "type": "string" + }, + "saudi_arabia": { + "type": "string" + }, + "sauna_man": { + "type": "string" + }, + "sauna_person": { + "type": "string" + }, + "sauna_woman": { + "type": "string" + }, + "sauropod": { + "type": "string" + }, + "saxophone": { + "type": "string" + }, + "scarf": { + "type": "string" + }, + "school": { + "type": "string" + }, + "school_satchel": { + "type": "string" + }, + "scientist": { + "type": "string" + }, + "scissors": { + "type": "string" + }, + "scorpion": { + "type": "string" + }, + "scorpius": { + "type": "string" + }, + "scotland": { + "type": "string" + }, + "scream": { + "type": "string" + }, + "scream_cat": { + "type": "string" + }, + "screwdriver": { + "type": "string" + }, + "scroll": { + "type": "string" + }, + "seal": { + "type": "string" + }, + "seat": { + "type": "string" + }, + "secret": { + "type": "string" + }, + "see_no_evil": { + "type": "string" + }, + "seedling": { + "type": "string" + }, + "selfie": { + "type": "string" + }, + "senegal": { + "type": "string" + }, + "serbia": { + "type": "string" + }, + "service_dog": { + "type": "string" + }, + "seven": { + "type": "string" + }, + "sewing_needle": { + "type": "string" + }, + "seychelles": { + "type": "string" + }, + "shallow_pan_of_food": { + "type": "string" + }, + "shamrock": { + "type": "string" + }, + "shark": { + "type": "string" + }, + "shaved_ice": { + "type": "string" + }, + "sheep": { + "type": "string" + }, + "shell": { + "type": "string" + }, + "shield": { + "type": "string" + }, + "shinto_shrine": { + "type": "string" + }, + "ship": { + "type": "string" + }, + "shipit": { + "type": "string" + }, + "shirt": { + "type": "string" + }, + "shit": { + "type": "string" + }, + "shoe": { + "type": "string" + }, + "shopping": { + "type": "string" + }, + "shopping_cart": { + "type": "string" + }, + "shorts": { + "type": "string" + }, + "shower": { + "type": "string" + }, + "shrimp": { + "type": "string" + }, + "shrug": { + "type": "string" + }, + "shushing_face": { + "type": "string" + }, + "sierra_leone": { + "type": "string" + }, + "signal_strength": { + "type": "string" + }, + "singapore": { + "type": "string" + }, + "singer": { + "type": "string" + }, + "sint_maarten": { + "type": "string" + }, + "six": { + "type": "string" + }, + "six_pointed_star": { + "type": "string" + }, + "skateboard": { + "type": "string" + }, + "ski": { + "type": "string" + }, + "skier": { + "type": "string" + }, + "skull": { + "type": "string" + }, + "skull_and_crossbones": { + "type": "string" + }, + "skunk": { + "type": "string" + }, + "sled": { + "type": "string" + }, + "sleeping": { + "type": "string" + }, + "sleeping_bed": { + "type": "string" + }, + "sleepy": { + "type": "string" + }, + "slightly_frowning_face": { + "type": "string" + }, + "slightly_smiling_face": { + "type": "string" + }, + "slot_machine": { + "type": "string" + }, + "sloth": { + "type": "string" + }, + "slovakia": { + "type": "string" + }, + "slovenia": { + "type": "string" + }, + "small_airplane": { + "type": "string" + }, + "small_blue_diamond": { + "type": "string" + }, + "small_orange_diamond": { + "type": "string" + }, + "small_red_triangle": { + "type": "string" + }, + "small_red_triangle_down": { + "type": "string" + }, + "smile": { + "type": "string" + }, + "smile_cat": { + "type": "string" + }, + "smiley": { + "type": "string" + }, + "smiley_cat": { + "type": "string" + }, + "smiling_face_with_tear": { + "type": "string" + }, + "smiling_face_with_three_hearts": { + "type": "string" + }, + "smiling_imp": { + "type": "string" + }, + "smirk": { + "type": "string" + }, + "smirk_cat": { + "type": "string" + }, + "smoking": { + "type": "string" + }, + "snail": { + "type": "string" + }, + "snake": { + "type": "string" + }, + "sneezing_face": { + "type": "string" + }, + "snowboarder": { + "type": "string" + }, + "snowflake": { + "type": "string" + }, + "snowman": { + "type": "string" + }, + "snowman_with_snow": { + "type": "string" + }, + "soap": { + "type": "string" + }, + "sob": { + "type": "string" + }, + "soccer": { + "type": "string" + }, + "socks": { + "type": "string" + }, + "softball": { + "type": "string" + }, + "solomon_islands": { + "type": "string" + }, + "somalia": { + "type": "string" + }, + "soon": { + "type": "string" + }, + "sos": { + "type": "string" + }, + "sound": { + "type": "string" + }, + "south_africa": { + "type": "string" + }, + "south_georgia_south_sandwich_islands": { + "type": "string" + }, + "south_sudan": { + "type": "string" + }, + "space_invader": { + "type": "string" + }, + "spades": { + "type": "string" + }, + "spaghetti": { + "type": "string" + }, + "sparkle": { + "type": "string" + }, + "sparkler": { + "type": "string" + }, + "sparkles": { + "type": "string" + }, + "sparkling_heart": { + "type": "string" + }, + "speak_no_evil": { + "type": "string" + }, + "speaker": { + "type": "string" + }, + "speaking_head": { + "type": "string" + }, + "speech_balloon": { + "type": "string" + }, + "speedboat": { + "type": "string" + }, + "spider": { + "type": "string" + }, + "spider_web": { + "type": "string" + }, + "spiral_calendar": { + "type": "string" + }, + "spiral_notepad": { + "type": "string" + }, + "sponge": { + "type": "string" + }, + "spoon": { + "type": "string" + }, + "squid": { + "type": "string" + }, + "sri_lanka": { + "type": "string" + }, + "st_barthelemy": { + "type": "string" + }, + "st_helena": { + "type": "string" + }, + "st_kitts_nevis": { + "type": "string" + }, + "st_lucia": { + "type": "string" + }, + "st_martin": { + "type": "string" + }, + "st_pierre_miquelon": { + "type": "string" + }, + "st_vincent_grenadines": { + "type": "string" + }, + "stadium": { + "type": "string" + }, + "standing_man": { + "type": "string" + }, + "standing_person": { + "type": "string" + }, + "standing_woman": { + "type": "string" + }, + "star": { + "type": "string" + }, + "star2": { + "type": "string" + }, + "star_and_crescent": { + "type": "string" + }, + "star_of_david": { + "type": "string" + }, + "star_struck": { + "type": "string" + }, + "stars": { + "type": "string" + }, + "station": { + "type": "string" + }, + "statue_of_liberty": { + "type": "string" + }, + "steam_locomotive": { + "type": "string" + }, + "stethoscope": { + "type": "string" + }, + "stew": { + "type": "string" + }, + "stop_button": { + "type": "string" + }, + "stop_sign": { + "type": "string" + }, + "stopwatch": { + "type": "string" + }, + "straight_ruler": { + "type": "string" + }, + "strawberry": { + "type": "string" + }, + "stuck_out_tongue": { + "type": "string" + }, + "stuck_out_tongue_closed_eyes": { + "type": "string" + }, + "stuck_out_tongue_winking_eye": { + "type": "string" + }, + "student": { + "type": "string" + }, + "studio_microphone": { + "type": "string" + }, + "stuffed_flatbread": { + "type": "string" + }, + "sudan": { + "type": "string" + }, + "sun_behind_large_cloud": { + "type": "string" + }, + "sun_behind_rain_cloud": { + "type": "string" + }, + "sun_behind_small_cloud": { + "type": "string" + }, + "sun_with_face": { + "type": "string" + }, + "sunflower": { + "type": "string" + }, + "sunglasses": { + "type": "string" + }, + "sunny": { + "type": "string" + }, + "sunrise": { + "type": "string" + }, + "sunrise_over_mountains": { + "type": "string" + }, + "superhero": { + "type": "string" + }, + "superhero_man": { + "type": "string" + }, + "superhero_woman": { + "type": "string" + }, + "supervillain": { + "type": "string" + }, + "supervillain_man": { + "type": "string" + }, + "supervillain_woman": { + "type": "string" + }, + "surfer": { + "type": "string" + }, + "surfing_man": { + "type": "string" + }, + "surfing_woman": { + "type": "string" + }, + "suriname": { + "type": "string" + }, + "sushi": { + "type": "string" + }, + "suspect": { + "type": "string" + }, + "suspension_railway": { + "type": "string" + }, + "svalbard_jan_mayen": { + "type": "string" + }, + "swan": { + "type": "string" + }, + "swaziland": { + "type": "string" + }, + "sweat": { + "type": "string" + }, + "sweat_drops": { + "type": "string" + }, + "sweat_smile": { + "type": "string" + }, + "sweden": { + "type": "string" + }, + "sweet_potato": { + "type": "string" + }, + "swim_brief": { + "type": "string" + }, + "swimmer": { + "type": "string" + }, + "swimming_man": { + "type": "string" + }, + "swimming_woman": { + "type": "string" + }, + "switzerland": { + "type": "string" + }, + "symbols": { + "type": "string" + }, + "synagogue": { + "type": "string" + }, + "syria": { + "type": "string" + }, + "syringe": { + "type": "string" + }, + "t-rex": { + "type": "string" + }, + "taco": { + "type": "string" + }, + "tada": { + "type": "string" + }, + "taiwan": { + "type": "string" + }, + "tajikistan": { + "type": "string" + }, + "takeout_box": { + "type": "string" + }, + "tamale": { + "type": "string" + }, + "tanabata_tree": { + "type": "string" + }, + "tangerine": { + "type": "string" + }, + "tanzania": { + "type": "string" + }, + "taurus": { + "type": "string" + }, + "taxi": { + "type": "string" + }, + "tea": { + "type": "string" + }, + "teacher": { + "type": "string" + }, + "teapot": { + "type": "string" + }, + "technologist": { + "type": "string" + }, + "teddy_bear": { + "type": "string" + }, + "telephone": { + "type": "string" + }, + "telephone_receiver": { + "type": "string" + }, + "telescope": { + "type": "string" + }, + "tennis": { + "type": "string" + }, + "tent": { + "type": "string" + }, + "test_tube": { + "type": "string" + }, + "thailand": { + "type": "string" + }, + "thermometer": { + "type": "string" + }, + "thinking": { + "type": "string" + }, + "thong_sandal": { + "type": "string" + }, + "thought_balloon": { + "type": "string" + }, + "thread": { + "type": "string" + }, + "three": { + "type": "string" + }, + "thumbsdown": { + "type": "string" + }, + "thumbsup": { + "type": "string" + }, + "ticket": { + "type": "string" + }, + "tickets": { + "type": "string" + }, + "tiger": { + "type": "string" + }, + "tiger2": { + "type": "string" + }, + "timer_clock": { + "type": "string" + }, + "timor_leste": { + "type": "string" + }, + "tipping_hand_man": { + "type": "string" + }, + "tipping_hand_person": { + "type": "string" + }, + "tipping_hand_woman": { + "type": "string" + }, + "tired_face": { + "type": "string" + }, + "tm": { + "type": "string" + }, + "togo": { + "type": "string" + }, + "toilet": { + "type": "string" + }, + "tokelau": { + "type": "string" + }, + "tokyo_tower": { + "type": "string" + }, + "tomato": { + "type": "string" + }, + "tonga": { + "type": "string" + }, + "tongue": { + "type": "string" + }, + "toolbox": { + "type": "string" + }, + "tooth": { + "type": "string" + }, + "toothbrush": { + "type": "string" + }, + "top": { + "type": "string" + }, + "tophat": { + "type": "string" + }, + "tornado": { + "type": "string" + }, + "tr": { + "type": "string" + }, + "trackball": { + "type": "string" + }, + "tractor": { + "type": "string" + }, + "traffic_light": { + "type": "string" + }, + "train": { + "type": "string" + }, + "train2": { + "type": "string" + }, + "tram": { + "type": "string" + }, + "transgender_flag": { + "type": "string" + }, + "transgender_symbol": { + "type": "string" + }, + "triangular_flag_on_post": { + "type": "string" + }, + "triangular_ruler": { + "type": "string" + }, + "trident": { + "type": "string" + }, + "trinidad_tobago": { + "type": "string" + }, + "tristan_da_cunha": { + "type": "string" + }, + "triumph": { + "type": "string" + }, + "trolleybus": { + "type": "string" + }, + "trollface": { + "type": "string" + }, + "trophy": { + "type": "string" + }, + "tropical_drink": { + "type": "string" + }, + "tropical_fish": { + "type": "string" + }, + "truck": { + "type": "string" + }, + "trumpet": { + "type": "string" + }, + "tshirt": { + "type": "string" + }, + "tulip": { + "type": "string" + }, + "tumbler_glass": { + "type": "string" + }, + "tunisia": { + "type": "string" + }, + "turkey": { + "type": "string" + }, + "turkmenistan": { + "type": "string" + }, + "turks_caicos_islands": { + "type": "string" + }, + "turtle": { + "type": "string" + }, + "tuvalu": { + "type": "string" + }, + "tv": { + "type": "string" + }, + "twisted_rightwards_arrows": { + "type": "string" + }, + "two": { + "type": "string" + }, + "two_hearts": { + "type": "string" + }, + "two_men_holding_hands": { + "type": "string" + }, + "two_women_holding_hands": { + "type": "string" + }, + "u5272": { + "type": "string" + }, + "u5408": { + "type": "string" + }, + "u55b6": { + "type": "string" + }, + "u6307": { + "type": "string" + }, + "u6708": { + "type": "string" + }, + "u6709": { + "type": "string" + }, + "u6e80": { + "type": "string" + }, + "u7121": { + "type": "string" + }, + "u7533": { + "type": "string" + }, + "u7981": { + "type": "string" + }, + "u7a7a": { + "type": "string" + }, + "uganda": { + "type": "string" + }, + "uk": { + "type": "string" + }, + "ukraine": { + "type": "string" + }, + "umbrella": { + "type": "string" + }, + "unamused": { + "type": "string" + }, + "underage": { + "type": "string" + }, + "unicorn": { + "type": "string" + }, + "united_arab_emirates": { + "type": "string" + }, + "united_nations": { + "type": "string" + }, + "unlock": { + "type": "string" + }, + "up": { + "type": "string" + }, + "upside_down_face": { + "type": "string" + }, + "uruguay": { + "type": "string" + }, + "us": { + "type": "string" + }, + "us_outlying_islands": { + "type": "string" + }, + "us_virgin_islands": { + "type": "string" + }, + "uzbekistan": { + "type": "string" + }, + "v": { + "type": "string" + }, + "vampire": { + "type": "string" + }, + "vampire_man": { + "type": "string" + }, + "vampire_woman": { + "type": "string" + }, + "vanuatu": { + "type": "string" + }, + "vatican_city": { + "type": "string" + }, + "venezuela": { + "type": "string" + }, + "vertical_traffic_light": { + "type": "string" + }, + "vhs": { + "type": "string" + }, + "vibration_mode": { + "type": "string" + }, + "video_camera": { + "type": "string" + }, + "video_game": { + "type": "string" + }, + "vietnam": { + "type": "string" + }, + "violin": { + "type": "string" + }, + "virgo": { + "type": "string" + }, + "volcano": { + "type": "string" + }, + "volleyball": { + "type": "string" + }, + "vomiting_face": { + "type": "string" + }, + "vs": { + "type": "string" + }, + "vulcan_salute": { + "type": "string" + }, + "waffle": { + "type": "string" + }, + "wales": { + "type": "string" + }, + "walking": { + "type": "string" + }, + "walking_man": { + "type": "string" + }, + "walking_woman": { + "type": "string" + }, + "wallis_futuna": { + "type": "string" + }, + "waning_crescent_moon": { + "type": "string" + }, + "waning_gibbous_moon": { + "type": "string" + }, + "warning": { + "type": "string" + }, + "wastebasket": { + "type": "string" + }, + "watch": { + "type": "string" + }, + "water_buffalo": { + "type": "string" + }, + "water_polo": { + "type": "string" + }, + "watermelon": { + "type": "string" + }, + "wave": { + "type": "string" + }, + "wavy_dash": { + "type": "string" + }, + "waxing_crescent_moon": { + "type": "string" + }, + "waxing_gibbous_moon": { + "type": "string" + }, + "wc": { + "type": "string" + }, + "weary": { + "type": "string" + }, + "wedding": { + "type": "string" + }, + "weight_lifting": { + "type": "string" + }, + "weight_lifting_man": { + "type": "string" + }, + "weight_lifting_woman": { + "type": "string" + }, + "western_sahara": { + "type": "string" + }, + "whale": { + "type": "string" + }, + "whale2": { + "type": "string" + }, + "wheel_of_dharma": { + "type": "string" + }, + "wheelchair": { + "type": "string" + }, + "white_check_mark": { + "type": "string" + }, + "white_circle": { + "type": "string" + }, + "white_flag": { + "type": "string" + }, + "white_flower": { + "type": "string" + }, + "white_haired_man": { + "type": "string" + }, + "white_haired_woman": { + "type": "string" + }, + "white_heart": { + "type": "string" + }, + "white_large_square": { + "type": "string" + }, + "white_medium_small_square": { + "type": "string" + }, + "white_medium_square": { + "type": "string" + }, + "white_small_square": { + "type": "string" + }, + "white_square_button": { + "type": "string" + }, + "wilted_flower": { + "type": "string" + }, + "wind_chime": { + "type": "string" + }, + "wind_face": { + "type": "string" + }, + "window": { + "type": "string" + }, + "wine_glass": { + "type": "string" + }, + "wink": { + "type": "string" + }, + "wolf": { + "type": "string" + }, + "woman": { + "type": "string" + }, + "woman_artist": { + "type": "string" + }, + "woman_astronaut": { + "type": "string" + }, + "woman_beard": { + "type": "string" + }, + "woman_cartwheeling": { + "type": "string" + }, + "woman_cook": { + "type": "string" + }, + "woman_dancing": { + "type": "string" + }, + "woman_facepalming": { + "type": "string" + }, + "woman_factory_worker": { + "type": "string" + }, + "woman_farmer": { + "type": "string" + }, + "woman_feeding_baby": { + "type": "string" + }, + "woman_firefighter": { + "type": "string" + }, + "woman_health_worker": { + "type": "string" + }, + "woman_in_manual_wheelchair": { + "type": "string" + }, + "woman_in_motorized_wheelchair": { + "type": "string" + }, + "woman_in_tuxedo": { + "type": "string" + }, + "woman_judge": { + "type": "string" + }, + "woman_juggling": { + "type": "string" + }, + "woman_mechanic": { + "type": "string" + }, + "woman_office_worker": { + "type": "string" + }, + "woman_pilot": { + "type": "string" + }, + "woman_playing_handball": { + "type": "string" + }, + "woman_playing_water_polo": { + "type": "string" + }, + "woman_scientist": { + "type": "string" + }, + "woman_shrugging": { + "type": "string" + }, + "woman_singer": { + "type": "string" + }, + "woman_student": { + "type": "string" + }, + "woman_teacher": { + "type": "string" + }, + "woman_technologist": { + "type": "string" + }, + "woman_with_headscarf": { + "type": "string" + }, + "woman_with_probing_cane": { + "type": "string" + }, + "woman_with_turban": { + "type": "string" + }, + "woman_with_veil": { + "type": "string" + }, + "womans_clothes": { + "type": "string" + }, + "womans_hat": { + "type": "string" + }, + "women_wrestling": { + "type": "string" + }, + "womens": { + "type": "string" + }, + "wood": { + "type": "string" + }, + "woozy_face": { + "type": "string" + }, + "world_map": { + "type": "string" + }, + "worm": { + "type": "string" + }, + "worried": { + "type": "string" + }, + "wrench": { + "type": "string" + }, + "wrestling": { + "type": "string" + }, + "writing_hand": { + "type": "string" + }, + "x": { + "type": "string" + }, + "yarn": { + "type": "string" + }, + "yawning_face": { + "type": "string" + }, + "yellow_circle": { + "type": "string" + }, + "yellow_heart": { + "type": "string" + }, + "yellow_square": { + "type": "string" + }, + "yemen": { + "type": "string" + }, + "yen": { + "type": "string" + }, + "yin_yang": { + "type": "string" + }, + "yo_yo": { + "type": "string" + }, + "yum": { + "type": "string" + }, + "zambia": { + "type": "string" + }, + "zany_face": { + "type": "string" + }, + "zap": { + "type": "string" + }, + "zebra": { + "type": "string" + }, + "zero": { + "type": "string" + }, + "zimbabwe": { + "type": "string" + }, + "zipper_mouth_face": { + "type": "string" + }, + "zombie": { + "type": "string" + }, + "zombie_man": { + "type": "string" + }, + "zombie_woman": { + "type": "string" + }, + "zzz": { + "type": "string" + } + }, + "required": [ + "+1", + "-1", + "100", + "1234", + "1st_place_medal", + "2nd_place_medal", + "3rd_place_medal", + "8ball", + "a", + "ab", + "abacus", + "abc", + "abcd", + "accept", + "accordion", + "adhesive_bandage", + "adult", + "aerial_tramway", + "afghanistan", + "airplane", + "aland_islands", + "alarm_clock", + "albania", + "alembic", + "algeria", + "alien", + "ambulance", + "american_samoa", + "amphora", + "anatomical_heart", + "anchor", + "andorra", + "angel", + "anger", + "angola", + "angry", + "anguilla", + "anguished", + "ant", + "antarctica", + "antigua_barbuda", + "apple", + "aquarius", + "argentina", + "aries", + "armenia", + "arrow_backward", + "arrow_double_down", + "arrow_double_up", + "arrow_down", + "arrow_down_small", + "arrow_forward", + "arrow_heading_down", + "arrow_heading_up", + "arrow_left", + "arrow_lower_left", + "arrow_lower_right", + "arrow_right", + "arrow_right_hook", + "arrow_up", + "arrow_up_down", + "arrow_up_small", + "arrow_upper_left", + "arrow_upper_right", + "arrows_clockwise", + "arrows_counterclockwise", + "art", + "articulated_lorry", + "artificial_satellite", + "artist", + "aruba", + "ascension_island", + "asterisk", + "astonished", + "astronaut", + "athletic_shoe", + "atm", + "atom", + "atom_symbol", + "australia", + "austria", + "auto_rickshaw", + "avocado", + "axe", + "azerbaijan", + "b", + "baby", + "baby_bottle", + "baby_chick", + "baby_symbol", + "back", + "bacon", + "badger", + "badminton", + "bagel", + "baggage_claim", + "baguette_bread", + "bahamas", + "bahrain", + "balance_scale", + "bald_man", + "bald_woman", + "ballet_shoes", + "balloon", + "ballot_box", + "ballot_box_with_check", + "bamboo", + "banana", + "bangbang", + "bangladesh", + "banjo", + "bank", + "bar_chart", + "barbados", + "barber", + "baseball", + "basecamp", + "basecampy", + "basket", + "basketball", + "basketball_man", + "basketball_woman", + "bat", + "bath", + "bathtub", + "battery", + "beach_umbrella", + "bear", + "bearded_person", + "beaver", + "bed", + "bee", + "beer", + "beers", + "beetle", + "beginner", + "belarus", + "belgium", + "belize", + "bell", + "bell_pepper", + "bellhop_bell", + "benin", + "bento", + "bermuda", + "beverage_box", + "bhutan", + "bicyclist", + "bike", + "biking_man", + "biking_woman", + "bikini", + "billed_cap", + "biohazard", + "bird", + "birthday", + "bison", + "black_cat", + "black_circle", + "black_flag", + "black_heart", + "black_joker", + "black_large_square", + "black_medium_small_square", + "black_medium_square", + "black_nib", + "black_small_square", + "black_square_button", + "blond_haired_man", + "blond_haired_person", + "blond_haired_woman", + "blonde_woman", + "blossom", + "blowfish", + "blue_book", + "blue_car", + "blue_heart", + "blue_square", + "blueberries", + "blush", + "boar", + "boat", + "bolivia", + "bomb", + "bone", + "book", + "bookmark", + "bookmark_tabs", + "books", + "boom", + "boomerang", + "boot", + "bosnia_herzegovina", + "botswana", + "bouncing_ball_man", + "bouncing_ball_person", + "bouncing_ball_woman", + "bouquet", + "bouvet_island", + "bow", + "bow_and_arrow", + "bowing_man", + "bowing_woman", + "bowl_with_spoon", + "bowling", + "bowtie", + "boxing_glove", + "boy", + "brain", + "brazil", + "bread", + "breast_feeding", + "bricks", + "bride_with_veil", + "bridge_at_night", + "briefcase", + "british_indian_ocean_territory", + "british_virgin_islands", + "broccoli", + "broken_heart", + "broom", + "brown_circle", + "brown_heart", + "brown_square", + "brunei", + "bubble_tea", + "bucket", + "bug", + "building_construction", + "bulb", + "bulgaria", + "bullettrain_front", + "bullettrain_side", + "burkina_faso", + "burrito", + "burundi", + "bus", + "business_suit_levitating", + "busstop", + "bust_in_silhouette", + "busts_in_silhouette", + "butter", + "butterfly", + "cactus", + "cake", + "calendar", + "call_me_hand", + "calling", + "cambodia", + "camel", + "camera", + "camera_flash", + "cameroon", + "camping", + "canada", + "canary_islands", + "cancer", + "candle", + "candy", + "canned_food", + "canoe", + "cape_verde", + "capital_abcd", + "capricorn", + "car", + "card_file_box", + "card_index", + "card_index_dividers", + "caribbean_netherlands", + "carousel_horse", + "carpentry_saw", + "carrot", + "cartwheeling", + "cat", + "cat2", + "cayman_islands", + "cd", + "central_african_republic", + "ceuta_melilla", + "chad", + "chains", + "chair", + "champagne", + "chart", + "chart_with_downwards_trend", + "chart_with_upwards_trend", + "checkered_flag", + "cheese", + "cherries", + "cherry_blossom", + "chess_pawn", + "chestnut", + "chicken", + "child", + "children_crossing", + "chile", + "chipmunk", + "chocolate_bar", + "chopsticks", + "christmas_island", + "christmas_tree", + "church", + "cinema", + "circus_tent", + "city_sunrise", + "city_sunset", + "cityscape", + "cl", + "clamp", + "clap", + "clapper", + "classical_building", + "climbing", + "climbing_man", + "climbing_woman", + "clinking_glasses", + "clipboard", + "clipperton_island", + "clock1", + "clock10", + "clock1030", + "clock11", + "clock1130", + "clock12", + "clock1230", + "clock130", + "clock2", + "clock230", + "clock3", + "clock330", + "clock4", + "clock430", + "clock5", + "clock530", + "clock6", + "clock630", + "clock7", + "clock730", + "clock8", + "clock830", + "clock9", + "clock930", + "closed_book", + "closed_lock_with_key", + "closed_umbrella", + "cloud", + "cloud_with_lightning", + "cloud_with_lightning_and_rain", + "cloud_with_rain", + "cloud_with_snow", + "clown_face", + "clubs", + "cn", + "coat", + "cockroach", + "cocktail", + "coconut", + "cocos_islands", + "coffee", + "coffin", + "coin", + "cold_face", + "cold_sweat", + "collision", + "colombia", + "comet", + "comoros", + "compass", + "computer", + "computer_mouse", + "confetti_ball", + "confounded", + "confused", + "congo_brazzaville", + "congo_kinshasa", + "congratulations", + "construction", + "construction_worker", + "construction_worker_man", + "construction_worker_woman", + "control_knobs", + "convenience_store", + "cook", + "cook_islands", + "cookie", + "cool", + "cop", + "copyright", + "corn", + "costa_rica", + "cote_divoire", + "couch_and_lamp", + "couple", + "couple_with_heart", + "couple_with_heart_man_man", + "couple_with_heart_woman_man", + "couple_with_heart_woman_woman", + "couplekiss", + "couplekiss_man_man", + "couplekiss_man_woman", + "couplekiss_woman_woman", + "cow", + "cow2", + "cowboy_hat_face", + "crab", + "crayon", + "credit_card", + "crescent_moon", + "cricket", + "cricket_game", + "croatia", + "crocodile", + "croissant", + "crossed_fingers", + "crossed_flags", + "crossed_swords", + "crown", + "cry", + "crying_cat_face", + "crystal_ball", + "cuba", + "cucumber", + "cup_with_straw", + "cupcake", + "cupid", + "curacao", + "curling_stone", + "curly_haired_man", + "curly_haired_woman", + "curly_loop", + "currency_exchange", + "curry", + "cursing_face", + "custard", + "customs", + "cut_of_meat", + "cyclone", + "cyprus", + "czech_republic", + "dagger", + "dancer", + "dancers", + "dancing_men", + "dancing_women", + "dango", + "dark_sunglasses", + "dart", + "dash", + "date", + "de", + "deaf_man", + "deaf_person", + "deaf_woman", + "deciduous_tree", + "deer", + "denmark", + "department_store", + "derelict_house", + "desert", + "desert_island", + "desktop_computer", + "detective", + "diamond_shape_with_a_dot_inside", + "diamonds", + "diego_garcia", + "disappointed", + "disappointed_relieved", + "disguised_face", + "diving_mask", + "diya_lamp", + "dizzy", + "dizzy_face", + "djibouti", + "dna", + "do_not_litter", + "dodo", + "dog", + "dog2", + "dollar", + "dolls", + "dolphin", + "dominica", + "dominican_republic", + "door", + "doughnut", + "dove", + "dragon", + "dragon_face", + "dress", + "dromedary_camel", + "drooling_face", + "drop_of_blood", + "droplet", + "drum", + "duck", + "dumpling", + "dvd", + "e-mail", + "eagle", + "ear", + "ear_of_rice", + "ear_with_hearing_aid", + "earth_africa", + "earth_americas", + "earth_asia", + "ecuador", + "egg", + "eggplant", + "egypt", + "eight", + "eight_pointed_black_star", + "eight_spoked_asterisk", + "eject_button", + "el_salvador", + "electric_plug", + "electron", + "elephant", + "elevator", + "elf", + "elf_man", + "elf_woman", + "email", + "end", + "england", + "envelope", + "envelope_with_arrow", + "equatorial_guinea", + "eritrea", + "es", + "estonia", + "ethiopia", + "eu", + "euro", + "european_castle", + "european_post_office", + "european_union", + "evergreen_tree", + "exclamation", + "exploding_head", + "expressionless", + "eye", + "eye_speech_bubble", + "eyeglasses", + "eyes", + "face_exhaling", + "face_in_clouds", + "face_with_head_bandage", + "face_with_spiral_eyes", + "face_with_thermometer", + "facepalm", + "facepunch", + "factory", + "factory_worker", + "fairy", + "fairy_man", + "fairy_woman", + "falafel", + "falkland_islands", + "fallen_leaf", + "family", + "family_man_boy", + "family_man_boy_boy", + "family_man_girl", + "family_man_girl_boy", + "family_man_girl_girl", + "family_man_man_boy", + "family_man_man_boy_boy", + "family_man_man_girl", + "family_man_man_girl_boy", + "family_man_man_girl_girl", + "family_man_woman_boy", + "family_man_woman_boy_boy", + "family_man_woman_girl", + "family_man_woman_girl_boy", + "family_man_woman_girl_girl", + "family_woman_boy", + "family_woman_boy_boy", + "family_woman_girl", + "family_woman_girl_boy", + "family_woman_girl_girl", + "family_woman_woman_boy", + "family_woman_woman_boy_boy", + "family_woman_woman_girl", + "family_woman_woman_girl_boy", + "family_woman_woman_girl_girl", + "farmer", + "faroe_islands", + "fast_forward", + "fax", + "fearful", + "feather", + "feelsgood", + "feet", + "female_detective", + "female_sign", + "ferris_wheel", + "ferry", + "field_hockey", + "fiji", + "file_cabinet", + "file_folder", + "film_projector", + "film_strip", + "finland", + "finnadie", + "fire", + "fire_engine", + "fire_extinguisher", + "firecracker", + "firefighter", + "fireworks", + "first_quarter_moon", + "first_quarter_moon_with_face", + "fish", + "fish_cake", + "fishing_pole_and_fish", + "fist", + "fist_left", + "fist_oncoming", + "fist_raised", + "fist_right", + "five", + "flags", + "flamingo", + "flashlight", + "flat_shoe", + "flatbread", + "fleur_de_lis", + "flight_arrival", + "flight_departure", + "flipper", + "floppy_disk", + "flower_playing_cards", + "flushed", + "fly", + "flying_disc", + "flying_saucer", + "fog", + "foggy", + "fondue", + "foot", + "football", + "footprints", + "fork_and_knife", + "fortune_cookie", + "fountain", + "fountain_pen", + "four", + "four_leaf_clover", + "fox_face", + "fr", + "framed_picture", + "free", + "french_guiana", + "french_polynesia", + "french_southern_territories", + "fried_egg", + "fried_shrimp", + "fries", + "frog", + "frowning", + "frowning_face", + "frowning_man", + "frowning_person", + "frowning_woman", + "fu", + "fuelpump", + "full_moon", + "full_moon_with_face", + "funeral_urn", + "gabon", + "gambia", + "game_die", + "garlic", + "gb", + "gear", + "gem", + "gemini", + "genie", + "genie_man", + "genie_woman", + "georgia", + "ghana", + "ghost", + "gibraltar", + "gift", + "gift_heart", + "giraffe", + "girl", + "globe_with_meridians", + "gloves", + "goal_net", + "goat", + "goberserk", + "godmode", + "goggles", + "golf", + "golfing", + "golfing_man", + "golfing_woman", + "gorilla", + "grapes", + "greece", + "green_apple", + "green_book", + "green_circle", + "green_heart", + "green_salad", + "green_square", + "greenland", + "grenada", + "grey_exclamation", + "grey_question", + "grimacing", + "grin", + "grinning", + "guadeloupe", + "guam", + "guard", + "guardsman", + "guardswoman", + "guatemala", + "guernsey", + "guide_dog", + "guinea", + "guinea_bissau", + "guitar", + "gun", + "guyana", + "haircut", + "haircut_man", + "haircut_woman", + "haiti", + "hamburger", + "hammer", + "hammer_and_pick", + "hammer_and_wrench", + "hamster", + "hand", + "hand_over_mouth", + "handbag", + "handball_person", + "handshake", + "hankey", + "hash", + "hatched_chick", + "hatching_chick", + "headphones", + "headstone", + "health_worker", + "hear_no_evil", + "heard_mcdonald_islands", + "heart", + "heart_decoration", + "heart_eyes", + "heart_eyes_cat", + "heart_on_fire", + "heartbeat", + "heartpulse", + "hearts", + "heavy_check_mark", + "heavy_division_sign", + "heavy_dollar_sign", + "heavy_exclamation_mark", + "heavy_heart_exclamation", + "heavy_minus_sign", + "heavy_multiplication_x", + "heavy_plus_sign", + "hedgehog", + "helicopter", + "herb", + "hibiscus", + "high_brightness", + "high_heel", + "hiking_boot", + "hindu_temple", + "hippopotamus", + "hocho", + "hole", + "honduras", + "honey_pot", + "honeybee", + "hong_kong", + "hook", + "horse", + "horse_racing", + "hospital", + "hot_face", + "hot_pepper", + "hotdog", + "hotel", + "hotsprings", + "hourglass", + "hourglass_flowing_sand", + "house", + "house_with_garden", + "houses", + "hugs", + "hungary", + "hurtrealbad", + "hushed", + "hut", + "ice_cream", + "ice_cube", + "ice_hockey", + "ice_skate", + "icecream", + "iceland", + "id", + "ideograph_advantage", + "imp", + "inbox_tray", + "incoming_envelope", + "india", + "indonesia", + "infinity", + "information_desk_person", + "information_source", + "innocent", + "interrobang", + "iphone", + "iran", + "iraq", + "ireland", + "isle_of_man", + "israel", + "it", + "izakaya_lantern", + "jack_o_lantern", + "jamaica", + "japan", + "japanese_castle", + "japanese_goblin", + "japanese_ogre", + "jeans", + "jersey", + "jigsaw", + "jordan", + "joy", + "joy_cat", + "joystick", + "jp", + "judge", + "juggling_person", + "kaaba", + "kangaroo", + "kazakhstan", + "kenya", + "key", + "keyboard", + "keycap_ten", + "kick_scooter", + "kimono", + "kiribati", + "kiss", + "kissing", + "kissing_cat", + "kissing_closed_eyes", + "kissing_heart", + "kissing_smiling_eyes", + "kite", + "kiwi_fruit", + "kneeling_man", + "kneeling_person", + "kneeling_woman", + "knife", + "knot", + "koala", + "koko", + "kosovo", + "kr", + "kuwait", + "kyrgyzstan", + "lab_coat", + "label", + "lacrosse", + "ladder", + "lady_beetle", + "lantern", + "laos", + "large_blue_circle", + "large_blue_diamond", + "large_orange_diamond", + "last_quarter_moon", + "last_quarter_moon_with_face", + "latin_cross", + "latvia", + "laughing", + "leafy_green", + "leaves", + "lebanon", + "ledger", + "left_luggage", + "left_right_arrow", + "left_speech_bubble", + "leftwards_arrow_with_hook", + "leg", + "lemon", + "leo", + "leopard", + "lesotho", + "level_slider", + "liberia", + "libra", + "libya", + "liechtenstein", + "light_rail", + "link", + "lion", + "lips", + "lipstick", + "lithuania", + "lizard", + "llama", + "lobster", + "lock", + "lock_with_ink_pen", + "lollipop", + "long_drum", + "loop", + "lotion_bottle", + "lotus_position", + "lotus_position_man", + "lotus_position_woman", + "loud_sound", + "loudspeaker", + "love_hotel", + "love_letter", + "love_you_gesture", + "low_brightness", + "luggage", + "lungs", + "luxembourg", + "lying_face", + "m", + "macau", + "macedonia", + "madagascar", + "mag", + "mag_right", + "mage", + "mage_man", + "mage_woman", + "magic_wand", + "magnet", + "mahjong", + "mailbox", + "mailbox_closed", + "mailbox_with_mail", + "mailbox_with_no_mail", + "malawi", + "malaysia", + "maldives", + "male_detective", + "male_sign", + "mali", + "malta", + "mammoth", + "man", + "man_artist", + "man_astronaut", + "man_beard", + "man_cartwheeling", + "man_cook", + "man_dancing", + "man_facepalming", + "man_factory_worker", + "man_farmer", + "man_feeding_baby", + "man_firefighter", + "man_health_worker", + "man_in_manual_wheelchair", + "man_in_motorized_wheelchair", + "man_in_tuxedo", + "man_judge", + "man_juggling", + "man_mechanic", + "man_office_worker", + "man_pilot", + "man_playing_handball", + "man_playing_water_polo", + "man_scientist", + "man_shrugging", + "man_singer", + "man_student", + "man_teacher", + "man_technologist", + "man_with_gua_pi_mao", + "man_with_probing_cane", + "man_with_turban", + "man_with_veil", + "mandarin", + "mango", + "mans_shoe", + "mantelpiece_clock", + "manual_wheelchair", + "maple_leaf", + "marshall_islands", + "martial_arts_uniform", + "martinique", + "mask", + "massage", + "massage_man", + "massage_woman", + "mate", + "mauritania", + "mauritius", + "mayotte", + "meat_on_bone", + "mechanic", + "mechanical_arm", + "mechanical_leg", + "medal_military", + "medal_sports", + "medical_symbol", + "mega", + "melon", + "memo", + "men_wrestling", + "mending_heart", + "menorah", + "mens", + "mermaid", + "merman", + "merperson", + "metal", + "metro", + "mexico", + "microbe", + "micronesia", + "microphone", + "microscope", + "middle_finger", + "military_helmet", + "milk_glass", + "milky_way", + "minibus", + "minidisc", + "mirror", + "mobile_phone_off", + "moldova", + "monaco", + "money_mouth_face", + "money_with_wings", + "moneybag", + "mongolia", + "monkey", + "monkey_face", + "monocle_face", + "monorail", + "montenegro", + "montserrat", + "moon", + "moon_cake", + "morocco", + "mortar_board", + "mosque", + "mosquito", + "motor_boat", + "motor_scooter", + "motorcycle", + "motorized_wheelchair", + "motorway", + "mount_fuji", + "mountain", + "mountain_bicyclist", + "mountain_biking_man", + "mountain_biking_woman", + "mountain_cableway", + "mountain_railway", + "mountain_snow", + "mouse", + "mouse2", + "mouse_trap", + "movie_camera", + "moyai", + "mozambique", + "mrs_claus", + "muscle", + "mushroom", + "musical_keyboard", + "musical_note", + "musical_score", + "mute", + "mx_claus", + "myanmar", + "nail_care", + "name_badge", + "namibia", + "national_park", + "nauru", + "nauseated_face", + "nazar_amulet", + "neckbeard", + "necktie", + "negative_squared_cross_mark", + "nepal", + "nerd_face", + "nesting_dolls", + "netherlands", + "neutral_face", + "new", + "new_caledonia", + "new_moon", + "new_moon_with_face", + "new_zealand", + "newspaper", + "newspaper_roll", + "next_track_button", + "ng", + "ng_man", + "ng_woman", + "nicaragua", + "niger", + "nigeria", + "night_with_stars", + "nine", + "ninja", + "niue", + "no_bell", + "no_bicycles", + "no_entry", + "no_entry_sign", + "no_good", + "no_good_man", + "no_good_woman", + "no_mobile_phones", + "no_mouth", + "no_pedestrians", + "no_smoking", + "non-potable_water", + "norfolk_island", + "north_korea", + "northern_mariana_islands", + "norway", + "nose", + "notebook", + "notebook_with_decorative_cover", + "notes", + "nut_and_bolt", + "o", + "o2", + "ocean", + "octocat", + "octopus", + "oden", + "office", + "office_worker", + "oil_drum", + "ok", + "ok_hand", + "ok_man", + "ok_person", + "ok_woman", + "old_key", + "older_adult", + "older_man", + "older_woman", + "olive", + "om", + "oman", + "on", + "oncoming_automobile", + "oncoming_bus", + "oncoming_police_car", + "oncoming_taxi", + "one", + "one_piece_swimsuit", + "onion", + "open_book", + "open_file_folder", + "open_hands", + "open_mouth", + "open_umbrella", + "ophiuchus", + "orange", + "orange_book", + "orange_circle", + "orange_heart", + "orange_square", + "orangutan", + "orthodox_cross", + "otter", + "outbox_tray", + "owl", + "ox", + "oyster", + "package", + "page_facing_up", + "page_with_curl", + "pager", + "paintbrush", + "pakistan", + "palau", + "palestinian_territories", + "palm_tree", + "palms_up_together", + "panama", + "pancakes", + "panda_face", + "paperclip", + "paperclips", + "papua_new_guinea", + "parachute", + "paraguay", + "parasol_on_ground", + "parking", + "parrot", + "part_alternation_mark", + "partly_sunny", + "partying_face", + "passenger_ship", + "passport_control", + "pause_button", + "paw_prints", + "peace_symbol", + "peach", + "peacock", + "peanuts", + "pear", + "pen", + "pencil", + "pencil2", + "penguin", + "pensive", + "people_holding_hands", + "people_hugging", + "performing_arts", + "persevere", + "person_bald", + "person_curly_hair", + "person_feeding_baby", + "person_fencing", + "person_in_manual_wheelchair", + "person_in_motorized_wheelchair", + "person_in_tuxedo", + "person_red_hair", + "person_white_hair", + "person_with_probing_cane", + "person_with_turban", + "person_with_veil", + "peru", + "petri_dish", + "philippines", + "phone", + "pick", + "pickup_truck", + "pie", + "pig", + "pig2", + "pig_nose", + "pill", + "pilot", + "pinata", + "pinched_fingers", + "pinching_hand", + "pineapple", + "ping_pong", + "pirate_flag", + "pisces", + "pitcairn_islands", + "pizza", + "placard", + "place_of_worship", + "plate_with_cutlery", + "play_or_pause_button", + "pleading_face", + "plunger", + "point_down", + "point_left", + "point_right", + "point_up", + "point_up_2", + "poland", + "polar_bear", + "police_car", + "police_officer", + "policeman", + "policewoman", + "poodle", + "poop", + "popcorn", + "portugal", + "post_office", + "postal_horn", + "postbox", + "potable_water", + "potato", + "potted_plant", + "pouch", + "poultry_leg", + "pound", + "pout", + "pouting_cat", + "pouting_face", + "pouting_man", + "pouting_woman", + "pray", + "prayer_beads", + "pregnant_woman", + "pretzel", + "previous_track_button", + "prince", + "princess", + "printer", + "probing_cane", + "puerto_rico", + "punch", + "purple_circle", + "purple_heart", + "purple_square", + "purse", + "pushpin", + "put_litter_in_its_place", + "qatar", + "question", + "rabbit", + "rabbit2", + "raccoon", + "racehorse", + "racing_car", + "radio", + "radio_button", + "radioactive", + "rage", + "rage1", + "rage2", + "rage3", + "rage4", + "railway_car", + "railway_track", + "rainbow", + "rainbow_flag", + "raised_back_of_hand", + "raised_eyebrow", + "raised_hand", + "raised_hand_with_fingers_splayed", + "raised_hands", + "raising_hand", + "raising_hand_man", + "raising_hand_woman", + "ram", + "ramen", + "rat", + "razor", + "receipt", + "record_button", + "recycle", + "red_car", + "red_circle", + "red_envelope", + "red_haired_man", + "red_haired_woman", + "red_square", + "registered", + "relaxed", + "relieved", + "reminder_ribbon", + "repeat", + "repeat_one", + "rescue_worker_helmet", + "restroom", + "reunion", + "revolving_hearts", + "rewind", + "rhinoceros", + "ribbon", + "rice", + "rice_ball", + "rice_cracker", + "rice_scene", + "right_anger_bubble", + "ring", + "ringed_planet", + "robot", + "rock", + "rocket", + "rofl", + "roll_eyes", + "roll_of_paper", + "roller_coaster", + "roller_skate", + "romania", + "rooster", + "rose", + "rosette", + "rotating_light", + "round_pushpin", + "rowboat", + "rowing_man", + "rowing_woman", + "ru", + "rugby_football", + "runner", + "running", + "running_man", + "running_shirt_with_sash", + "running_woman", + "rwanda", + "sa", + "safety_pin", + "safety_vest", + "sagittarius", + "sailboat", + "sake", + "salt", + "samoa", + "san_marino", + "sandal", + "sandwich", + "santa", + "sao_tome_principe", + "sari", + "sassy_man", + "sassy_woman", + "satellite", + "satisfied", + "saudi_arabia", + "sauna_man", + "sauna_person", + "sauna_woman", + "sauropod", + "saxophone", + "scarf", + "school", + "school_satchel", + "scientist", + "scissors", + "scorpion", + "scorpius", + "scotland", + "scream", + "scream_cat", + "screwdriver", + "scroll", + "seal", + "seat", + "secret", + "see_no_evil", + "seedling", + "selfie", + "senegal", + "serbia", + "service_dog", + "seven", + "sewing_needle", + "seychelles", + "shallow_pan_of_food", + "shamrock", + "shark", + "shaved_ice", + "sheep", + "shell", + "shield", + "shinto_shrine", + "ship", + "shipit", + "shirt", + "shit", + "shoe", + "shopping", + "shopping_cart", + "shorts", + "shower", + "shrimp", + "shrug", + "shushing_face", + "sierra_leone", + "signal_strength", + "singapore", + "singer", + "sint_maarten", + "six", + "six_pointed_star", + "skateboard", + "ski", + "skier", + "skull", + "skull_and_crossbones", + "skunk", + "sled", + "sleeping", + "sleeping_bed", + "sleepy", + "slightly_frowning_face", + "slightly_smiling_face", + "slot_machine", + "sloth", + "slovakia", + "slovenia", + "small_airplane", + "small_blue_diamond", + "small_orange_diamond", + "small_red_triangle", + "small_red_triangle_down", + "smile", + "smile_cat", + "smiley", + "smiley_cat", + "smiling_face_with_tear", + "smiling_face_with_three_hearts", + "smiling_imp", + "smirk", + "smirk_cat", + "smoking", + "snail", + "snake", + "sneezing_face", + "snowboarder", + "snowflake", + "snowman", + "snowman_with_snow", + "soap", + "sob", + "soccer", + "socks", + "softball", + "solomon_islands", + "somalia", + "soon", + "sos", + "sound", + "south_africa", + "south_georgia_south_sandwich_islands", + "south_sudan", + "space_invader", + "spades", + "spaghetti", + "sparkle", + "sparkler", + "sparkles", + "sparkling_heart", + "speak_no_evil", + "speaker", + "speaking_head", + "speech_balloon", + "speedboat", + "spider", + "spider_web", + "spiral_calendar", + "spiral_notepad", + "sponge", + "spoon", + "squid", + "sri_lanka", + "st_barthelemy", + "st_helena", + "st_kitts_nevis", + "st_lucia", + "st_martin", + "st_pierre_miquelon", + "st_vincent_grenadines", + "stadium", + "standing_man", + "standing_person", + "standing_woman", + "star", + "star2", + "star_and_crescent", + "star_of_david", + "star_struck", + "stars", + "station", + "statue_of_liberty", + "steam_locomotive", + "stethoscope", + "stew", + "stop_button", + "stop_sign", + "stopwatch", + "straight_ruler", + "strawberry", + "stuck_out_tongue", + "stuck_out_tongue_closed_eyes", + "stuck_out_tongue_winking_eye", + "student", + "studio_microphone", + "stuffed_flatbread", + "sudan", + "sun_behind_large_cloud", + "sun_behind_rain_cloud", + "sun_behind_small_cloud", + "sun_with_face", + "sunflower", + "sunglasses", + "sunny", + "sunrise", + "sunrise_over_mountains", + "superhero", + "superhero_man", + "superhero_woman", + "supervillain", + "supervillain_man", + "supervillain_woman", + "surfer", + "surfing_man", + "surfing_woman", + "suriname", + "sushi", + "suspect", + "suspension_railway", + "svalbard_jan_mayen", + "swan", + "swaziland", + "sweat", + "sweat_drops", + "sweat_smile", + "sweden", + "sweet_potato", + "swim_brief", + "swimmer", + "swimming_man", + "swimming_woman", + "switzerland", + "symbols", + "synagogue", + "syria", + "syringe", + "t-rex", + "taco", + "tada", + "taiwan", + "tajikistan", + "takeout_box", + "tamale", + "tanabata_tree", + "tangerine", + "tanzania", + "taurus", + "taxi", + "tea", + "teacher", + "teapot", + "technologist", + "teddy_bear", + "telephone", + "telephone_receiver", + "telescope", + "tennis", + "tent", + "test_tube", + "thailand", + "thermometer", + "thinking", + "thong_sandal", + "thought_balloon", + "thread", + "three", + "thumbsdown", + "thumbsup", + "ticket", + "tickets", + "tiger", + "tiger2", + "timer_clock", + "timor_leste", + "tipping_hand_man", + "tipping_hand_person", + "tipping_hand_woman", + "tired_face", + "tm", + "togo", + "toilet", + "tokelau", + "tokyo_tower", + "tomato", + "tonga", + "tongue", + "toolbox", + "tooth", + "toothbrush", + "top", + "tophat", + "tornado", + "tr", + "trackball", + "tractor", + "traffic_light", + "train", + "train2", + "tram", + "transgender_flag", + "transgender_symbol", + "triangular_flag_on_post", + "triangular_ruler", + "trident", + "trinidad_tobago", + "tristan_da_cunha", + "triumph", + "trolleybus", + "trollface", + "trophy", + "tropical_drink", + "tropical_fish", + "truck", + "trumpet", + "tshirt", + "tulip", + "tumbler_glass", + "tunisia", + "turkey", + "turkmenistan", + "turks_caicos_islands", + "turtle", + "tuvalu", + "tv", + "twisted_rightwards_arrows", + "two", + "two_hearts", + "two_men_holding_hands", + "two_women_holding_hands", + "u5272", + "u5408", + "u55b6", + "u6307", + "u6708", + "u6709", + "u6e80", + "u7121", + "u7533", + "u7981", + "u7a7a", + "uganda", + "uk", + "ukraine", + "umbrella", + "unamused", + "underage", + "unicorn", + "united_arab_emirates", + "united_nations", + "unlock", + "up", + "upside_down_face", + "uruguay", + "us", + "us_outlying_islands", + "us_virgin_islands", + "uzbekistan", + "v", + "vampire", + "vampire_man", + "vampire_woman", + "vanuatu", + "vatican_city", + "venezuela", + "vertical_traffic_light", + "vhs", + "vibration_mode", + "video_camera", + "video_game", + "vietnam", + "violin", + "virgo", + "volcano", + "volleyball", + "vomiting_face", + "vs", + "vulcan_salute", + "waffle", + "wales", + "walking", + "walking_man", + "walking_woman", + "wallis_futuna", + "waning_crescent_moon", + "waning_gibbous_moon", + "warning", + "wastebasket", + "watch", + "water_buffalo", + "water_polo", + "watermelon", + "wave", + "wavy_dash", + "waxing_crescent_moon", + "waxing_gibbous_moon", + "wc", + "weary", + "wedding", + "weight_lifting", + "weight_lifting_man", + "weight_lifting_woman", + "western_sahara", + "whale", + "whale2", + "wheel_of_dharma", + "wheelchair", + "white_check_mark", + "white_circle", + "white_flag", + "white_flower", + "white_haired_man", + "white_haired_woman", + "white_heart", + "white_large_square", + "white_medium_small_square", + "white_medium_square", + "white_small_square", + "white_square_button", + "wilted_flower", + "wind_chime", + "wind_face", + "window", + "wine_glass", + "wink", + "wolf", + "woman", + "woman_artist", + "woman_astronaut", + "woman_beard", + "woman_cartwheeling", + "woman_cook", + "woman_dancing", + "woman_facepalming", + "woman_factory_worker", + "woman_farmer", + "woman_feeding_baby", + "woman_firefighter", + "woman_health_worker", + "woman_in_manual_wheelchair", + "woman_in_motorized_wheelchair", + "woman_in_tuxedo", + "woman_judge", + "woman_juggling", + "woman_mechanic", + "woman_office_worker", + "woman_pilot", + "woman_playing_handball", + "woman_playing_water_polo", + "woman_scientist", + "woman_shrugging", + "woman_singer", + "woman_student", + "woman_teacher", + "woman_technologist", + "woman_with_headscarf", + "woman_with_probing_cane", + "woman_with_turban", + "woman_with_veil", + "womans_clothes", + "womans_hat", + "women_wrestling", + "womens", + "wood", + "woozy_face", + "world_map", + "worm", + "worried", + "wrench", + "wrestling", + "writing_hand", + "x", + "yarn", + "yawning_face", + "yellow_circle", + "yellow_heart", + "yellow_square", + "yemen", + "yen", + "yin_yang", + "yo_yo", + "yum", + "zambia", + "zany_face", + "zap", + "zebra", + "zero", + "zimbabwe", + "zipper_mouth_face", + "zombie", + "zombie_man", + "zombie_woman", + "zzz" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-2.json b/registry/cmd/sr-cli/testdata/json/schema-2.json new file mode 100644 index 0000000..72ab606 --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-2.json @@ -0,0 +1,34 @@ +{ + "$id": "https://example.com/arrays.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a person, company, organization, or place", + "type": "object", + "properties": { + "fruits": { + "type": "array", + "items": { + "type": "string" + } + }, + "vegetables": { + "type": "array", + "items": { "$ref": "#/$defs/veggie" } + } + }, + "$defs": { + "veggie": { + "type": "object", + "required": [ "veggieName", "veggieLike" ], + "properties": { + "veggieName": { + "type": "string", + "description": "The name of the vegetable." + }, + "veggieLike": { + "type": "boolean", + "description": "Do I like this vegetable?" + } + } + } + } +} diff --git a/registry/cmd/sr-cli/testdata/json/schema-3.json b/registry/cmd/sr-cli/testdata/json/schema-3.json new file mode 100644 index 0000000..3a8ad3f --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-3.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$id": "https://example.com/employee.schema.json", + "title": "Record of employee", + "description": "This document records the details of an employee", + "type": "object", + "properties": { + "id": { + "description": "A unique identifier for an employee", + "type": "number" + }, + "name": { + "description": "Full name of the employee", + "type": "string" + }, + "age": { + "description": "Age of the employee", + "type": "number" + }, + "hobbies": { + "description": "Hobbies of the employee", + "type": "object", + "properties": { + "indoor": { + "type": "array", + "items": { + "description": "List of indoor hobbies", + "type": "string" + } + }, + "outdoor": { + "type": "array", + "items": { + "description": "List of outdoor hobbies", + "type": "string" + } + } + } + } + } +} diff --git a/registry/cmd/sr-cli/testdata/json/schema-4.json b/registry/cmd/sr-cli/testdata/json/schema-4.json new file mode 100644 index 0000000..f46f61d --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-4.json @@ -0,0 +1,253 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "web-app": { + "type": "object", + "properties": { + "servlet": { + "type": "array", + "items": { + "type": "object", + "properties": { + "servlet-name": { + "type": "string" + }, + "servlet-class": { + "type": "string" + }, + "init-param": { + "type": "object", + "properties": { + "configGlossary:installationAt": { + "type": "string" + }, + "configGlossary:adminEmail": { + "type": "string" + }, + "configGlossary:poweredBy": { + "type": "string" + }, + "configGlossary:poweredByIcon": { + "type": "string" + }, + "configGlossary:staticPath": { + "type": "string" + }, + "templateProcessorClass": { + "type": "string" + }, + "templateLoaderClass": { + "type": "string" + }, + "templatePath": { + "type": "string" + }, + "templateOverridePath": { + "type": "string" + }, + "defaultListTemplate": { + "type": "string" + }, + "defaultFileTemplate": { + "type": "string" + }, + "useJSP": { + "type": "boolean" + }, + "jspListTemplate": { + "type": "string" + }, + "jspFileTemplate": { + "type": "string" + }, + "cachePackageTagsTrack": { + "type": "integer" + }, + "cachePackageTagsStore": { + "type": "integer" + }, + "cachePackageTagsRefresh": { + "type": "integer" + }, + "cacheTemplatesTrack": { + "type": "integer" + }, + "cacheTemplatesStore": { + "type": "integer" + }, + "cacheTemplatesRefresh": { + "type": "integer" + }, + "cachePagesTrack": { + "type": "integer" + }, + "cachePagesStore": { + "type": "integer" + }, + "cachePagesRefresh": { + "type": "integer" + }, + "cachePagesDirtyRead": { + "type": "integer" + }, + "searchEngineListTemplate": { + "type": "string" + }, + "searchEngineFileTemplate": { + "type": "string" + }, + "searchEngineRobotsDb": { + "type": "string" + }, + "useDataStore": { + "type": "boolean" + }, + "dataStoreClass": { + "type": "string" + }, + "redirectionClass": { + "type": "string" + }, + "dataStoreName": { + "type": "string" + }, + "dataStoreDriver": { + "type": "string" + }, + "dataStoreUrl": { + "type": "string" + }, + "dataStoreUser": { + "type": "string" + }, + "dataStorePassword": { + "type": "string" + }, + "dataStoreTestQuery": { + "type": "string" + }, + "dataStoreLogFile": { + "type": "string" + }, + "dataStoreInitConns": { + "type": "integer" + }, + "dataStoreMaxConns": { + "type": "integer" + }, + "dataStoreConnUsageLimit": { + "type": "integer" + }, + "dataStoreLogLevel": { + "type": "string" + }, + "maxUrlLength": { + "type": "integer" + }, + "mailHost": { + "type": "string" + }, + "mailHostOverride": { + "type": "string" + }, + "log": { + "type": "integer" + }, + "logLocation": { + "type": "string" + }, + "logMaxSize": { + "type": "string" + }, + "dataLog": { + "type": "integer" + }, + "dataLogLocation": { + "type": "string" + }, + "dataLogMaxSize": { + "type": "string" + }, + "removePageCache": { + "type": "string" + }, + "removeTemplateCache": { + "type": "string" + }, + "fileTransferFolder": { + "type": "string" + }, + "lookInContext": { + "type": "integer" + }, + "adminGroupID": { + "type": "integer" + }, + "betaServer": { + "type": "boolean" + } + } + } + }, + "required": [ + "servlet-class", + "servlet-name" + ] + } + }, + "servlet-mapping": { + "type": "object", + "properties": { + "cofaxCDS": { + "type": "string" + }, + "cofaxEmail": { + "type": "string" + }, + "cofaxAdmin": { + "type": "string" + }, + "fileServlet": { + "type": "string" + }, + "cofaxTools": { + "type": "string" + } + }, + "required": [ + "cofaxAdmin", + "cofaxCDS", + "cofaxEmail", + "cofaxTools", + "fileServlet" + ] + }, + "taglib": { + "type": "object", + "properties": { + "taglib-uri": { + "type": "string" + }, + "taglib-location": { + "type": "string" + } + }, + "required": [ + "taglib-location", + "taglib-uri" + ] + } + }, + "required": [ + "servlet", + "servlet-mapping", + "taglib" + ] + } + }, + "required": [ + "web-app" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-5.json b/registry/cmd/sr-cli/testdata/json/schema-5.json new file mode 100644 index 0000000..628a55f --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-5.json @@ -0,0 +1,157 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "GroupDefinitions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Type": { + "type": "string" + }, + "Key": { + "type": "string" + } + }, + "required": [ + "Key", + "Type" + ] + } + }, + "ResultsByTime": { + "type": "array", + "items": { + "type": "object", + "properties": { + "TimePeriod": { + "type": "object", + "properties": { + "Start": { + "type": "string" + }, + "End": { + "type": "string" + } + }, + "required": [ + "End", + "Start" + ] + }, + "Total": { + "type": "object" + }, + "Groups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "Metrics": { + "type": "object", + "properties": { + "UnblendedCost": { + "type": "object", + "properties": { + "Amount": { + "type": "string" + }, + "Unit": { + "type": "string" + } + }, + "required": [ + "Amount", + "Unit" + ] + } + }, + "required": [ + "UnblendedCost" + ] + } + }, + "required": [ + "Keys", + "Metrics" + ] + } + }, + "Estimated": { + "type": "boolean" + } + }, + "required": [ + "Estimated", + "Groups", + "TimePeriod", + "Total" + ] + } + }, + "ResponseMetadata": { + "type": "object", + "properties": { + "RequestId": { + "type": "string" + }, + "HTTPStatusCode": { + "type": "integer" + }, + "HTTPHeaders": { + "type": "object", + "properties": { + "date": { + "type": "string" + }, + "content-type": { + "type": "string" + }, + "content-length": { + "type": "string" + }, + "connection": { + "type": "string" + }, + "x-amzn-requestid": { + "type": "string" + }, + "cache-control": { + "type": "string" + } + }, + "required": [ + "cache-control", + "connection", + "content-length", + "content-type", + "date", + "x-amzn-requestid" + ] + }, + "RetryAttempts": { + "type": "integer" + } + }, + "required": [ + "HTTPHeaders", + "HTTPStatusCode", + "RequestId", + "RetryAttempts" + ] + } + }, + "required": [ + "GroupDefinitions", + "ResponseMetadata", + "ResultsByTime" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-6.json b/registry/cmd/sr-cli/testdata/json/schema-6.json new file mode 100644 index 0000000..e711952 --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-6.json @@ -0,0 +1,546 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "servers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "created": { + "type": "string" + }, + "public_net": { + "type": "object", + "properties": { + "ipv4": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "blocked": { + "type": "boolean" + }, + "dns_ptr": { + "type": "string" + } + }, + "required": [ + "blocked", + "dns_ptr", + "ip" + ] + }, + "ipv6": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "blocked": { + "type": "boolean" + }, + "dns_ptr": { + "type": "array" + } + }, + "required": [ + "blocked", + "dns_ptr", + "ip" + ] + }, + "floating_ips": { + "type": "array" + }, + "firewalls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status" + ] + } + } + }, + "required": [ + "firewalls", + "floating_ips", + "ipv4", + "ipv6" + ] + }, + "private_net": { + "type": "array", + "items": { + "type": "object", + "properties": { + "network": { + "type": "integer" + }, + "ip": { + "type": "string" + }, + "alias_ips": { + "type": "array" + }, + "mac_address": { + "type": "string" + } + }, + "required": [ + "alias_ips", + "ip", + "mac_address", + "network" + ] + } + }, + "server_type": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "cores": { + "type": "integer" + }, + "memory": { + "type": "number" + }, + "disk": { + "type": "integer" + }, + "deprecated": { + "type": [ + "boolean", + "null" + ] + }, + "prices": { + "type": "array", + "items": { + "type": "object", + "properties": { + "location": { + "type": "string" + }, + "price_hourly": { + "type": "object", + "properties": { + "net": { + "type": "string" + }, + "gross": { + "type": "string" + } + }, + "required": [ + "gross", + "net" + ] + }, + "price_monthly": { + "type": "object", + "properties": { + "net": { + "type": "string" + }, + "gross": { + "type": "string" + } + }, + "required": [ + "gross", + "net" + ] + } + }, + "required": [ + "location", + "price_hourly", + "price_monthly" + ] + } + }, + "storage_type": { + "type": "string" + }, + "cpu_type": { + "type": "string" + } + }, + "required": [ + "cores", + "cpu_type", + "deprecated", + "description", + "disk", + "id", + "memory", + "name", + "prices", + "storage_type" + ] + }, + "datacenter": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "location": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "country": { + "type": "string" + }, + "city": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "network_zone": { + "type": "string" + } + }, + "required": [ + "city", + "country", + "description", + "id", + "latitude", + "longitude", + "name", + "network_zone" + ] + }, + "server_types": { + "type": "object", + "properties": { + "supported": { + "type": "array", + "items": { + "type": "integer" + } + }, + "available": { + "type": "array", + "items": { + "type": "integer" + } + }, + "available_for_migration": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "required": [ + "available", + "available_for_migration", + "supported" + ] + } + }, + "required": [ + "description", + "id", + "location", + "name", + "server_types" + ] + }, + "image": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "status": { + "type": "string" + }, + "name": { + "type": [ + "null", + "string" + ] + }, + "description": { + "type": "string" + }, + "image_size": { + "type": [ + "null", + "number" + ] + }, + "disk_size": { + "type": "integer" + }, + "created": { + "type": "string" + }, + "created_from": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + } + ] + }, + "bound_to": { + "type": "null" + }, + "os_flavor": { + "type": "string" + }, + "os_version": { + "type": [ + "null", + "string" + ] + }, + "rapid_deploy": { + "type": "boolean" + }, + "protection": { + "type": "object", + "properties": { + "delete": { + "type": "boolean" + } + }, + "required": [ + "delete" + ] + }, + "deprecated": { + "type": "null" + }, + "labels": { + "type": "object" + }, + "deleted": { + "type": "null" + } + }, + "required": [ + "bound_to", + "created", + "created_from", + "deleted", + "deprecated", + "description", + "disk_size", + "id", + "image_size", + "labels", + "name", + "os_flavor", + "os_version", + "protection", + "rapid_deploy", + "status", + "type" + ] + } + ] + }, + "iso": { + "type": "null" + }, + "rescue_enabled": { + "type": "boolean" + }, + "locked": { + "type": "boolean" + }, + "backup_window": { + "type": "null" + }, + "outgoing_traffic": { + "type": "integer" + }, + "ingoing_traffic": { + "type": "integer" + }, + "included_traffic": { + "type": "integer" + }, + "protection": { + "type": "object", + "properties": { + "delete": { + "type": "boolean" + }, + "rebuild": { + "type": "boolean" + } + }, + "required": [ + "delete", + "rebuild" + ] + }, + "labels": { + "type": "object" + }, + "volumes": { + "type": "array", + "items": { + "type": "integer" + } + }, + "load_balancers": { + "type": "array", + "items": { + "type": "integer" + } + }, + "primary_disk_size": { + "type": "integer" + }, + "placement_group": { + "type": "null" + } + }, + "required": [ + "backup_window", + "created", + "datacenter", + "id", + "image", + "included_traffic", + "ingoing_traffic", + "iso", + "labels", + "load_balancers", + "locked", + "name", + "outgoing_traffic", + "placement_group", + "primary_disk_size", + "private_net", + "protection", + "public_net", + "rescue_enabled", + "server_type", + "status", + "volumes" + ] + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "type": "object", + "properties": { + "page": { + "type": "integer" + }, + "per_page": { + "type": "integer" + }, + "previous_page": { + "type": "null" + }, + "next_page": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "total_entries": { + "type": "integer" + } + }, + "required": [ + "last_page", + "next_page", + "page", + "per_page", + "previous_page", + "total_entries" + ] + } + }, + "required": [ + "pagination" + ] + } + }, + "required": [ + "meta", + "servers" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-7.json b/registry/cmd/sr-cli/testdata/json/schema-7.json new file mode 100644 index 0000000..d7778da --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-7.json @@ -0,0 +1,243 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "effect_changes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "effect_entries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "effect": { + "type": "string" + }, + "language": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + } + }, + "required": [ + "effect", + "language" + ] + } + }, + "version_group": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + } + }, + "required": [ + "effect_entries", + "version_group" + ] + } + }, + "effect_entries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "effect": { + "type": "string" + }, + "language": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + }, + "short_effect": { + "type": "string" + } + }, + "required": [ + "effect", + "language", + "short_effect" + ] + } + }, + "flavor_text_entries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "flavor_text": { + "type": "string" + }, + "language": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + }, + "version_group": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + } + }, + "required": [ + "flavor_text", + "language", + "version_group" + ] + } + }, + "generation": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + }, + "id": { + "type": "integer" + }, + "is_main_series": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "object", + "properties": { + "language": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "language", + "name" + ] + } + }, + "pokemon": { + "type": "array", + "items": { + "type": "object", + "properties": { + "is_hidden": { + "type": "boolean" + }, + "pokemon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "name", + "url" + ] + }, + "slot": { + "type": "integer" + } + }, + "required": [ + "is_hidden", + "pokemon", + "slot" + ] + } + } + }, + "required": [ + "effect_changes", + "effect_entries", + "flavor_text_entries", + "generation", + "id", + "is_main_series", + "name", + "names", + "pokemon" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-8.json b/registry/cmd/sr-cli/testdata/json/schema-8.json new file mode 100644 index 0000000..c82956c --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-8.json @@ -0,0 +1,57 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "args": { + "type": "object" + }, + "headers": { + "type": "object", + "properties": { + "Accept": { + "type": "string" + }, + "Accept-Encoding": { + "type": "string" + }, + "Accept-Language": { + "type": "string" + }, + "Host": { + "type": "string" + }, + "Upgrade-Insecure-Requests": { + "type": "string" + }, + "User-Agent": { + "type": "string" + }, + "X-Amzn-Trace-Id": { + "type": "string" + } + }, + "required": [ + "Accept", + "Accept-Encoding", + "Accept-Language", + "Host", + "Upgrade-Insecure-Requests", + "User-Agent", + "X-Amzn-Trace-Id" + ] + }, + "origin": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "args", + "headers", + "origin", + "url" + ] +} \ No newline at end of file diff --git a/registry/cmd/sr-cli/testdata/json/schema-9.json b/registry/cmd/sr-cli/testdata/json/schema-9.json new file mode 100644 index 0000000..a58e95e --- /dev/null +++ b/registry/cmd/sr-cli/testdata/json/schema-9.json @@ -0,0 +1,127 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "geometry": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "coordinates": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "coordinates", + "type" + ] + }, + "geometry_name": { + "type": "string" + }, + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "streetaddress": { + "type": "string" + }, + "twitteraccount": { + "type": "string" + }, + "facebookaccount": { + "type": "string" + }, + "siteurl": { + "type": "string" + }, + "frequencyfinderurl": { + "type": "string" + } + }, + "required": [ + "facebookaccount", + "frequencyfinderurl", + "name", + "siteurl", + "streetaddress", + "twitteraccount" + ] + } + }, + "required": [ + "geometry", + "geometry_name", + "id", + "properties", + "type" + ] + } + }, + "totalFeatures": { + "type": "integer" + }, + "numberMatched": { + "type": "integer" + }, + "numberReturned": { + "type": "integer" + }, + "timeStamp": { + "type": "string" + }, + "crs": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + } + }, + "required": [ + "properties", + "type" + ] + } + }, + "required": [ + "crs", + "features", + "numberMatched", + "numberReturned", + "timeStamp", + "totalFeatures", + "type" + ] +} \ No newline at end of file diff --git a/registry/compatibility/checker.go b/registry/compatibility/checker.go new file mode 100644 index 0000000..4e33d90 --- /dev/null +++ b/registry/compatibility/checker.go @@ -0,0 +1,11 @@ +package compatibility + +type Checker interface { + Check(schema string, history []string, mode string) (bool, error) +} + +type CheckerFunc func(schema string, history []string, mode string) (bool, error) + +func (f CheckerFunc) Check(schema string, history []string, mode string) (bool, error) { + return f(schema, history, mode) +} diff --git a/registry/compatibility/checker_test.go b/registry/compatibility/checker_test.go new file mode 100644 index 0000000..8ba4f4b --- /dev/null +++ b/registry/compatibility/checker_test.go @@ -0,0 +1,105 @@ +package compatibility + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestNew(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + v, err := New(ctx, "http://localhost:8088", 2*time.Second) + + fmt.Println(v.url) + + if err != nil { + t.Fatal(err) + } +} + +func TestCompatibilityChecker_Check(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + checker, err := NewFromEnv(ctx) + if err != nil { + t.Fatal(err) + } + + type Data struct { + Id string `json:"id"` + Format string `json:"format"` + Schema string `json:"schema"` + } + + tt := []struct { + name string + schema string + history string + mode string + compatible bool + }{ + {"compatible-1", "backward_json_true/schema2.json", "backward_json_true/schema1.json", "BACKWARD", true}, + {"compatible-2", "backward_json_false/schema2.json", "backward_json_false/schema1.json", "BACKWARD", false}, + {"compatible-3", "backward_avro_true/schema2.json", "backward_avro_true/schema1.json", "BACKWARD", true}, + {"compatible-4", "backward_avro_false/schema2.json", "backward_avro_false/schema1.json", "BACKWARD", false}, + + {"compatible-5", "forward_json_true/schema2.json", "forward_json_true/schema1.json", "FORWARD", true}, + {"compatible-6", "forward_json_false/schema2.json", "forward_json_false/schema1.json", "FORWARD", false}, + {"compatible-7", "forward_avro_true/schema2.json", "forward_avro_true/schema1.json", "FORWARD", true}, + {"compatible-8", "forward_avro_false/schema2.json", "forward_avro_false/schema1.json", "FORWARD", false}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + newSchema, err := os.ReadFile(filepath.Join(testdataDir, tc.schema)) + if err != nil { + t.Fatalf("newSchema read error: %s", err) + } + + var schemaHistory []string + previousSchema, err := os.ReadFile(filepath.Join(testdataDir, tc.history)) + if err != nil { + t.Fatalf("schemaHistory read error: %s", err) + } + var previousSchemaJson Data + if err := json.Unmarshal(previousSchema, &previousSchemaJson); err != nil { + t.Fatalf("couldn't unmarshall schema history") + } + + schemaHistory = append(schemaHistory, base64.StdEncoding.EncodeToString([]byte(previousSchemaJson.Schema))) + + compatible, err := checker.Check(string(newSchema), schemaHistory, tc.mode) + if err != nil { + t.Errorf("validator error: %s", err) + } + if compatible != tc.compatible { + if compatible { + t.Errorf("message compatible, incompatible expected") + } else { + t.Errorf("message incompatible, compatible expected") + } + } + }) + } +} diff --git a/registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-common-2.3.1.Final.jar b/registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-common-2.3.1.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..747e7fb07584ae43107fc8d07e7d76550c950e34 GIT binary patch literal 18965 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 literal 0 HcmV?d00001 diff --git a/registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-json-2.3.1.Final.jar b/registry/compatibility/external/compatibility-checker/lib/apicurio-registry-schema-util-json-2.3.1.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..2f05400287bd6b8a28bfcec81f6d2bc9b65bcbda GIT binary patch literal 94141 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 literal 0 HcmV?d00001 diff --git a/registry/compatibility/external/compatibility-checker/lib/kafka-schema-registry-client-7.2.1.jar b/registry/compatibility/external/compatibility-checker/lib/kafka-schema-registry-client-7.2.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..037753ef6582628f92f38c01b0d7b9f78d927db9 GIT binary patch literal 193861 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π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¬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

3B$=me=dJ9h976j_a8k{poZ~C+ZVRqTo$U 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

PNc*V#WyH%j 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%0AreoI<-b7{fU?IAXNtl2*7aM+{HBOs^j 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%0AOYW2%z`>1FzWGJ6qVzmzO&l$3&HmRq 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

G@Y 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

{JCHamL?>L=L&2-UGtaV3# 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 V8XD#S9rylc@qQDmLizC9{{S%qo+|(V literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-common-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-common-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..afdc31b3b802649ec69f5fea51beb295f27cbc4b GIT binary patch literal 18968 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 UV8FnrKtC>^Z9V2&6%*`#02qqx1^@s6 literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-json-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-json-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..a2a60e99fcbac90d79a34b43d104e6597402027d GIT binary patch literal 94144 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 z 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 HHlY6p+%df4 literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-protobuf-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-protobuf-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..9c77d525a6755e223e59851a6d547ed39a82ab9a GIT binary patch literal 17277 zcmb_^1ymhN)-}OBxDzb6yF&=>?r?E;cL?qfBsc_jcXtc!?(PmD=uhTNChukDWxiSK zFSy+1QfKe#u5+rYPuE6990U{^2nZ4gNZDpx0q9Q!>g8BcP=SwHR7!|e=A|0SOEt)U zR9oxn43vBMv+T?3<AL7g#_glXe5O$C5Hwj#Hne<;l!yaMutYKm9KJu3@q9eWd96Z7B0F#Int*0xsm zR=N&`zd5lte~0%UY=7-b+`qHcv$C`|u(baTEzy57)zh)GviuFe-(Joi-1-K#28J&$ zOFe_%z`TBG$G;-SLdVhIcbwn7=a?Ri6*Dwq zZfFFhVsTg_S+i2JQpmiZbXXEBCX!iljZ`x;*tYJqCVk*$h#uz;w|>FJ!^OFKlls;D z>m}~W)95rS&`}>R|6F)X&0de*!Q~Uj)Fz07aR&syGfv*r8Nb6A{fxv#upy*`pEbA= zE<-tS3PL3twoj-AWZzl=0Kg|j5oU)ZPjJ*(-5p4rmfs<4dM?X_xxpvxUk)ctc@Zh< z&gF-DD}al1o86uFmWTR0th)-h!*Y_Pg&$Zks#ezfU1SUcDAs1K1?&!^UI1rtq-u&u z1gGdS*0iR4cxcQktIi=PoRDNGh0&xh&4UqU*~2NjQo_s423wgijRv_ARvdTbht4A^ zp3Qv~++8<9)6FOBmJ;cPm2~)9^Zg<1LZPYk^d>451M1QKzL`BBcvHu*2HhKZ*P`4> zUnM9x(v9@Q_5y4s86vP6vds*?eC)OZ&X`bncUWi9bzE_!F_PYld!8K=oQq3pfjMq2 zTWoB?Us^MjXRl}&;d4xZW4`amv0$Ytq*jOYM(`w63`=#?-dv95o3_VR?koetmMZ?v z=TDr;vzkPo!_ycwiIT*nFfh4I<)~(7N{p49>;lwf&U}VJr{siY%H;!6nNT;wL;XlQ z>i2h=UlGMmPU>H@4@gs*>LZpQWsE_Lx)bf zXcFzJ#0VYK(_7Y01<3Wz*hZ#}jJRBHZmS&t@Z~%0Bsp8&B;ycr^0V@4qi&FQyEe*Q zz*e{;zU3i0R}J3X@4Zw?@2-Jjv^WH;ezlplA=&b9~7T-*3zq{VchwZ z`2mR5?%)$im`HQsdf;tTw;7ga*ypkH!MRVj1p%Mecah4>>R+QXYjnb3d3tM^-hMh5 zUaM>$Nq(yf_nLsFyx=_ra=lq%KKsaN{=P~hp=SB+NO$$|zC3k|of-9J#3DmpcU;3! zt+K9C7plgzwIuywh?dzc+={jupvsCOmX-Md%?hfzjB5?Fan>$pGM{)GE-0> z)Y^+F?s}mZH^~CZ(x*+ilWUCqQVk@+c8{|wjjPM%f(uAH9WEOE#@_^D(iNlxYNvH= zf=UU*^{6>k_|WV`;BRY`W~T2<4cGu z>z}mbknq&}^Wuc}f-(^kG_-IlZ=f|Qd9bD!!!U>K&`2V7DFg;NoHa5#6}baVx$@e9 zeaS=*3zb(vP`g|dnV*^{<=m(aVbH56&RlNy)}5cnpL7f>7b!R6Pw}nWZxjoaC)ULf zD9kB`VWsOw*tb(Xy|L50p5Zt{W4sI>0W~4O3hfcaj-#%(S!c{w0D!oQ-Z?G<-VUc# z=g02POb?h|(`WE26V^CHz)j+8x!n6H^qDqog@z>sMVW)=W%Uv!Z_k}L43}(1wi0Pq zRE@6*-(^TpvjIwL-ZeCT8f2ky4EaPG*HUa*UT3jy8fmEtH7VbUlO2J_K(@)d_e_Z- zu~xgi?_71%X-Nn43UsdWZucvE#EBv0oKl@uKz;uR_|g}vAnNkKZrq^qJk+4E0LNM% zO5A)opbag^%m6z^HyWL;LCA^%SFkb%K;VoE*sG3N0r@^u1(+ei+r6TMBs_aC5qz+s zeJt;yd@x=D>zotlYPjOSL!I7oXeZE0u#;|kyeM&KnV+@ z2Th9`t{#2y9ALW669Io#2J@P*mtze`YRxmH6GVUw7@fPDT_`)t8Oy^t?U6S9bAqox z_$Dy;ZL7=N><-&h+k@$Na1*|$X5?1{^$RDguV>9bQEo0fo~92d@aJ0~Qx{<78}sy~ za*KlE`2be~O1TBG|bEf?Jf4o zj(cVPFbX~F0-fejBHJVHUvCwxfd&KRfPsKQL0^_Rzh6=OvReJuvf@u`Sbk#zJu?H_ zxAcE3E=ponrI7hhdfPH`7UKjd(v=<{Dxvf31qEqk^r%Z%V&5D4!_e3_;Vya`1P-0( zIun*ncVp-|18H?Q(WjArobbaymT+vf^Q@{b1Q_iZ zLkma9x0RG_7uDFdGy}5pCk7UDTGolmb{(3pa^*6hCU&|*hu9wFNgnm6Vy5-7xZl$I z!OmX_v>_0^UR!O4_snifKdtiA)k2Ica~E(g@P+DpqQUYDrXhg}r^$tk(Ud?ogwNt7 z@J11`fqLxMMXLKEHLfud;}OP%_64mX1Z$pSrGpr|i>@Yqk14SW(gd$WR&A4x6*feL zN3c*0q0e9HL9j5NT->#xDkf*)T~a0dM?sQr5Px;vamNS#StKB!aYi5@_5a0re=e_o zl6j{x<0K+OW>b$FRbb?ZV%iBidoa#4##89=@0x^~vpLqYV}VI(m% z@yk|6R?BL<)hN&XQPm8q5#8;t3ja`O18jm%Ouw`4E47QX0hvCe+ct8&KKZE(iPzH|4#_;YHr`*I6)Sb6(%|OuJ!HQA021Hj zB9Tzg7y4QBGr_`yOt3zx^90_MiV*TFk~wfUq3L^IA-(FV9>|ij+FSZ)bv*OyJ7pJs z9+z4OMnY^4o!sdH#ehstB8?fWqoWHUcWRzC+KJ`14+%R-x3kRH;WNWR`75(X7Xgjy z*t=+DtFt@d@049T!W>jonrO#r+h_I-T03UwG39z?V|n8M+8mX? zX0ZN25HBk&xMZWUcWt1Yc5GbVFMJFw%OYd+tggdy86BvwQ^>3v9acoYBTA=2r4WX)X!Mi6KY7<9q<)b zo)ODh^#?hAvbgpS!zdWehiHDPq@ne}qfp2An$b=8*7eAM#g&uTPpw*91)Q$FB!31p zE3*d^h8lqH_b5%;2Ucy8-dvGu@&z8#DuU%^5c3tvQNGC03>;pQ-eoZ4s>2l=O^5&&-(lohD2|B(^cx;A?Ws6>QK|^tUEzD!sM|BIdnJHFek_`Ul31$XQncD zykpyd6SzY>sATFN#BeBn3Wx&VpR*aW=~T?Flx1>})+U3PJpbgyRVYs@h-SCVi?rlR z+Z6-7Dfh|`^^eK7>z(6bjkm(d!vJ;c=FC(_sn=j36Dg_!qVTQ(wtGMBeVM*O|XCF6U zs>hd28>=ZHN91rHsgh>OiORTfeG>CY7Zu%W@7$!2T?EpCkl&WY{D`x4fmq7=ttnJm zB?PPciJ27t7?#krcz=OpGn$Mcs?e~wMDC`KiZV3;JG+P-1Fi-OMsfo!Z0%N_Ld>Bt zi1eU3Zf4&;g9*ImkSkcmC;V9J`a!0Dkvb1D)#u_#KdpGuU~gP;!d*V;RKzZs2_mQA z^8#~P<|TPb*||ch^!B8ETJNNTtH|4w5u-f~{9#y{sfM6X2bv6)RPhEXz8dJn5hL5g z5yo#+Z+k)YGq;Ys09$ZY-3cRA0%P@0=*)a=s~iPE!$yZMGf5(JRM+BT>x_tJIXABo z%Z{|wAZyXOwGB_S#@wRLmUO%wz_z6H(mXBeoSozIAS#FQg+}=3WJAd4tjil|BMP6l z#M4NLZK!=k?oC1w@nx6pJVYHVbES4Qw|N1iX3g(*)m&8i(f67~2A(eT3i<5;L*n+O z!gTfCyL7_}H@!2T+NL>h=R&`REFyWxqS|RxT${9(QMV~FyvvmR*7FTbh_V<0xiPmQ zT=!^cbKc4U0L{6_yN7m!o9q3pQVVyPAPpjh`!>`qw zMA?`(So)`2Y%VXlDyF!zM+81$)$J_}^keP@9BCN%b}r5Yw9 z+ZYT^frut2@B+>88^!8$M1spEEj=W3I^|9(CzZK5lyRlPLMd#qpb$PA*Mo}U9qotU z6?(8rG42U(Vyyl3HLJq9ntQ!jsiiJ``Ubk8v{dWfNqxS!xb>T*Kh=w<9mlq0qWLtz zsQna1nLuw{LI*~vqKnV7kDGaNr2w9DHxj&G)cllBFYwNQ9}W|-j8+?*hbXLb5mZPs ztnd69XQo*Yl*R(R>R_X$mx70?PLsl!>T1cy+wH-hzf2Q#+vv^laO%`)hIXC?NN(YM z;58Yhm-e&&j1x_d&mFrj7l)AmVu`ueRE+62VNotXTn;+-FoHuxO>Y_cd_qN4*Nw&JR`@TFybHoc zyb%YROOm7fsdw2Pgwpx54f}L)N>577Vh&HUsqmRFkx%j5GP5YL=m|bj7D%S*0MF2$ zXZ!Iv@U+jo+MX2J;Bsy)aQrsVn7aVB_9*hmZLsIU^l4^nUm#YfK@K!4p3;HNvnqI> z@D6w(^t>94apIh_@QiPxGZTWWr2O`kSX@3vJ##$Pg#9 z6F||)3UOD8vDRW(>`5G+tH|`qxCHbA7ElUFdmqqy-*#ixqh`$3MlczqQ))uE)55iJ z@iDXZc!DdOTSp>)6BvUK)>td6?2=q7;mNvvxqdO5J7W>In#oLMKT20Z#(rgdJ z2`bFw*f3nNUikixkdhf!JV{cCSS5T3Occz|j!2K69Nk0aA8neb(CU~V?DcgXTBd9U z&8Va>>x4Hqm7*CekNNwkZ*)U2sW=TSs#0A>JQQSN)y;btM%e{03N(hrkysUuiZ*n$ z{6YDGN|B?m;UcBeA-Uf8Ki3i7#1j%OJ2$1a`a!zmdbXmcxqWyF_7qkg!`l->hLF5n zXh%nbZx!%&_G0hF0vez+7g)+bI8S@utqzT7HAaJtNXutPNQi|(D6rs2Jp7N33H1V_ z5%~pP8RQCe?_M#7lbA3OA0sCv289>t&WW_4EC~57b_kfq&drgTRMX2v>BQimMDU05 z>rxx9GwjbBk4vZ+JJyT26@-bFuTw>Jc%pn#(s!wZmoM$x|H43eJ&_osb!Q$=+Lh)K zWOy^7x=*sTls1Ht)mSh@eo@6e|E7+ZXmtAvi%#XM&J867@z|8`PrJ^x<|(w%X$=<_ zA+jn1`EQbz#qB1}3dc6%`s_Y1+v)R4p6!VeMNn$Gr=LD?&0hQL+gV67nLC@3ueof^ zvpLtsKpb0w-eH02()!$&%}JDjb+^L3I|AXl0Regjr_&JD%E8{lwnz3r7d;@Tmfje8 z;)cgZ5>7wJo0R zLh12N3!JQqZWHbfI{nz^s%y*%sv%<^-vf?&dFrdfRb_!UX|nY!Cek{F0~-w9{V`V0^MoOX}Q-yf(_+AWm1uyV>p7BCR}6 z4hdfc!LE=$r}V9$cgXd050cO{H8^;raEt2=9s~V+LsCMHC>7bY85S>Vd0wq5B#F7L z{ecu_7*0VkR()OOn`$}yRNp9L@JEx8ILiqVk94b213d$(E(In15OxrGSZ>76x(YNh zjvU-l74qUbMsZu{iz8ITU0{_>8wNvyAvU3@H0r%eZ#YIbg<`bxa*x738!hhFHh~-! zhY@+e7)xDY06l|>JcDpOLb5-LB0P~FG4p~8cmgAFN!Cp=Ua@eCpMKam9f!FhXn{0u z?arGR)Q~FkIV!W^eDrDBk8h3#?C$Op)KoggtVM+;jl35R;7{qGeUqVaCe*rj(Q7#`e7Y$e@qz$iofv$fH;$4q1A* z@C`>>Cvn&Qd+Ez@YWX5=nvV14M|&yRlZT8sO#}HRidUzEda4iArit<%L8cPHFagmj z7UIQHx?{H>!k%b-={;;@NG&j+kBG3Yc(8ZK2v zX?%YfJ5TS)jDdOky)Q9DC~@|_p$KUwST~1(9enti&DR={Wp|G5kKEe_F;Tn4nWno?|&If7E6 zyBOhQD~QMN7vZ-&VCBgn((})G=(UyVFRX`EjEUKAo<|_IoJyu6SQ+W|0c=P(~!Jbwz2565=!Blb8oUzrM zpQ@XNh$e(tRH-nXC^4ND^~s}%tTCp^8JP1)RR14=3Am!i= z&Q)2$c$Ijw3?W57JGd-7S+VMI_6_pHT|dT@%K8<9B=yAzShY8L#%*a9{;WJJ>)3EJ zET5&E6P~TGO{7cf@;hd>%Yl8T+onj(gA*e9u(;}Fu?0)wvVIn}j z+s%zC)I8gINuMyf?iFEI>s+2qbzzf_F<4$Bbv={vl(9MTjP^nW-xB&g=w2!?dAC5i zz`S1(k~ANaidAv5wrosfow#gH1aw248>DRNa;^AUb8BBX=WW>dZrB*$L~1DlIRjp; zk%N8c12=aiED;uUlM&_A2VQdl1Bx0i(!c7xbiO6D#E-<2Yv3L3ZEy0OHZC}&!^7Nw zpX_a~3+QN{(J`yeiw?={VxnFD22h*lFS?P{kv%yW;%koz3N3=aO63JYmm9HyplJ;P zI{~Gk0imIRpeY5SaeRfYJn{7#g=oQu&D+G8033{eih`{Ub$&n>V;LwQ%{mZ|L13b=9N1oJF!k z6~qt&AMlW9X+Q6N!~SbNEph+rjmgX7Ws#T1%i{k_K27E~X|zA`XTvI*PT0bjp1pA` zmCX*i@(>z<3O0(?55(`GMUT3B95<)J-^S00ituMpx|mxLo)$JydSz$BRp-Q74H(%$ zu%>{pf{%#m+QR4MIi2y>@5F&*a4|-+L~n1+6=c-3FrG#juDE>Ob=l>ATJ(B)KnD^& zw}jaj+U zL%l3ik?F~#Fjv%2A}Xuag>_M+A}^CdDJ_Hn2Sn)baw*=*g36-6QDLjlmz!!!wx`(Q z>`QJ@ug15&yM$V-@RjxMUE$vaBSbz)L79uG#7!ipG00&xGq^P07inOp^jf(vzXn)_ zfrhepq)5$MPEgD>WD0l1z|`V7n~9bs#CtOA(x4W%k1V)ws)+NPHh3pfk4P)jNl^_f zq3(x6Rzpm@HswKfZgaXnF$>7usvL^UrcobMs>GQ4rXK<#T$574F`h>R{sF zU=;sr_R9jr#Lci$JEglG_jlU34UPSvQl4bm`r@Uwe#cZ{F5cW$+rXw3PK*E+RIa+U zJKNF;No{RXD#-4g<7S-r%TnR-NGooo;XP6q1CJO_OIaG#jFp&L$Ei%5@L`AvSJ zSu=kzrEp6hYhBWg2-`SeLtsiLVhhv(cy+@gus-MziaW0(QPWJ$Q<+IrJC{{y z+qaI|v@wBBu61>EwFHMJf>hS)uf^r8^bWpK zeoa@zyXMKhiPn;$pa6yAE@RD4k;pC?usJE0TGtvpx>hyhdxuPv#>2{pJt{HUTg7l9 z;|{V)X9HITeKmy(=8%f{Wyd$YG%|SBdbyod(jBG@2FIiSf$ki9h3VX)nRu-3aoc2r z(^qaHOIx1!pk6Vf{bo}```jf{D^!_nbdUgHIcoGtMYqsoE>lH zQ_#c>#cpVgMyn!jCFiEbSs9=9;fCQDT67C(Lk-fb_^FBu8wG#+>_P*QvwD&S%^8Oc z621GpIOv0b!J@A)oEcAi>J+S>-F%=Wu1{8!aLi z9(y$}yBJjv9nZAzXi}MXZncK&@g?+KY zSn!xm@<#D&Dm&7r+4vh~gIGVJuyRd5zp2FH=X|98>QvJf8jGI6QgW3CvQlUT=0@}F zV|L1q4>ztKSHoQz&qHlvnIk#kTHM7e(TbDrEcqV1g+Smd%xA(Qvm$d;4?cLpmZM>G zBe>a=lU3FvTGZWfVp(RLcfJ!AQ1r!>yt4oq20rbqhtqq6&qRlqn|PnG!-8Pe?q|Ms&v)Hy5^sFQ3)wBe6XMZMbQFd=9{P^%^QL?6H?BUT+%n3EX?tY1*?Vw> zUgDTRUQeUSGq?^`2A*DY|? zqrM6*tzETsKs~&X-js&TlD;2Ph&7Q@iYD@_h2Ol)mQWQwL&4g&!_-Ru49QKqMpi%7+Lj9cMLD!cCsM|BKsr=cO8mIJqg9b6|^rYd*L)=`t;=q?g$wp!d{T&OjPh0 z(ZEBDtTiwhWmHoVHIvc97i4RTq|q`xXR~5)5Ab{p;Z>ruLx1cLV$LPJK1x@LLT?o0 zqL$?u5{0Mj$X!yx$B<{uTqyFMgyfuf1AReG1-r1ka5Q34PQ`7^IeyLjr_qm(9oPl{TQOl5WG14Ax=UH z(r8qZOK$_h&KZ5_2NdGqKcWA1Mu)ztHAsHhekuJjtF!#wjQ(#=!vstW|GA6qkI6e# zLDLFb5QSUs)D_n#x!xpZgT(?`GK4p}zS?_&gIuN#Eh<_riUQJEXG7x1B1N;RsWjHB zgJ=U{ES?Jm%17ZXC@ubZ@&{YP7Pej%$dA#9Zbm05ZX+$T_k*XSZ4lPT%rHH$pkkQ% zcc->6kCs-Q2{MEj3O!D_X@jkg(z?bMN6C zkv&H(nF!9eG@4t8ua0}VC#X4SkTw(1aZ^0Atas)jLux$pDlovIT0W6KnYYr3d5U=~ zM3rcNXm{g`ROBv3;Xy)J(SkwOf=U3)DYSkl!5sM-;!eSFa#{CYb#*oNSjDE1X8E3j zbT}6_Y1x+e(%<1dkGq%0C6C>N)HjN~>i0sa+By7X;wcNY%@JD4%))wU*l}&em@pdm zWd>FB{*0~-CVDuv;e-A22_5X%v?hlJ&4eFY4qXVM^xfqBC9PN!B-V$SEa&Utlt?&L zN<>y2!HZOo>)BG6@F+Eq!9v(S-WMJ;IAD6N`4vZE`%S>jXBH6|+3)pt;!19nwm*DH z-Q+pHQN)=LEc@cR_bm|Zq+$U(t!~w%D*3Rq=)qJR+*@~G^j^LfLv#34%&9KN=i5ow z09|;S+wER?iIATcm+nIVL1E?eg6(_3sFWCguO7*@3EsYn0vs|=I=21B{c5VPbrce3 z2GLXS=;{v@r}#Wno}t~098mfVxtXDZY{Szh;5`UfM-s3ydiFkU0g*916RdQt2Luub zIQ76Fm+nmn1jF`OHfWRY^uvYs-b?F-sYbZBQ+dMaeUxd9{D|2F$=z|jX%xoNpe)`) ztAiz+gGbQ%A(4yX5vZa;g)0EFfl2N)TEh}coM*4|$SqXf=T5)?W?y+GnI~ply5so)V`!^nge3bAy67X>eqwL6)+%$b_O=D`k0p?~T6NeDneGFD6_24&l1USBS zB0jMaLUtP&Z`Y0){mRTfNfaHK3GGbEf$AJuQuC)Sc}>h0r$-R;~#-{{P5 zc~}=pj5QROZ-(874Pa9F16nT+>=ck0buy>h6M}6dFq}~Kew6epFj;nLC^vOU{lY#R~5yN%s6@Z`Rj+%H_+D}SbYT~S1Z0eJLX23 ztZnnFyQ-NJJHHD|2>;wu9s&@=OWN1bGtN*hjd<%o7#?qI5T*YX8@%m<2YlV4u{rFg z7UR5eD(p1|4iP!|%$VZpOJM;S>B?Oo2Z$h84}R`00<21+K;s8!JzmagJPxfMW~Qiu zfD=f~4Nz{01;m4=ak?Q4e`C@j8hd2(u=mDgK>=lcGgTO+fkE6?O?)h@kx-_?)DufI zlU{lVN>M=QnH5d zfuH-+e*~AZiQA+Qf+uT5NjKWt1OyRsBjj=rfh!*$e*7&m6n--JSFSQBF2_Or(c_5e zIXR>)r#He^*pG5ZcU%^{U-zv{IVmaUI;GlgeQTPk?3x)ltE!&vSMR-m*n&Q9?)9vL zx_%7S!w^Oa(tGQj#TJ+S_~k7I$tGK{G7_7AvEQUkN{0fD(Rtx*N~j*M?R$5%&M-e1 zo8qn>P(V8|RGFx=W+yh%ihdB>VeUx;U3K0BBWx5s7pud*=SX9 z`EbnXnH~;&p(XZZ9k!%tYC-D5B%{gh9l>Rrg92;!z7g`sV_h?P80DnPO#( zvWX*D{>*?tKIxKD>tcp9nc?OR#`&THpF-zSOR~IaTax84Di9(!_1=c8dDr=xBh2Zs z%fce{oo=}B_#Qt#9+RY{H;f8>>#a>migF=wicIx#@HldX94SwV*HNs7f&DT}7;P|2B^G zd5K;}TXICP#zpS934fh|-$;r!sqk=qYn+yPOLy>uHF1zTKrLyw=#jZ+s!gj?9d;Zl z1{8B7rxWttgJa%=n4N`b>I=fCYFdd+$I#ep{zaf)dYI&14E+a6Bx8CQNuf9PNMM+P zL$WM*byV><%7b|goJQNJr5IP18pj9S?yRtw#0dhGjW+MztM)R_A>m-saB-|4ut32u zlx_z2B{Qt_HZiPpSzw-ShJ?L7%kYcDh^SUrhUF{@^qin`mSq+?&Lq{n{vcZaP!T3= z9jJ459+^;HV?QoORy3DuSY{he6R_T=gsBZ>#&y-5*j3)jw<3dtx4txU|p+oc<5+#LZ)5G8u&e}d_mKp?dp3>Lz7&m!JljHc7_Wp`sz*3!rYDGqI z#m#`T`;^ng8--=J&Gi$`34z=Yl)@F#U9i{7pI$F~twuHcct+f{Ko_17Yf4}<8R^TS4w)G%jtCzJ+p+^)^nt2TUCVz*+wv$s;cU+alBU2wE9Olg8LPO_3=X1J6q zpRzuv<*CUCg2~j7icNp=!y^|`9ZdR4*7987k4Khozbpou@&s*^+c9Yf#&^!;UO7CL zWePTL|9FyMiow2&x{I3i@$<&k%Z(sNc_iFk@|h`-DH`tczKmJB0< zH+(thR>m>Yw-w|{%NBjyG3FZzxJjuto(-H%tRe6YWFj_kDefL=IVc4Xl_5y?=)=5a zv?WogY__O)6KzwVG2&6qBVeJ(`Z!C~z$)klCDRi8J`z@l*!<%d5dn?&n?f79U~TS0 z;gg1wdNObP>MlOx7+-Of(f)5~+hofgWFx-JHd4_b5RZDUUv@eCj2`d>`UhOFI16-o z&vlEDPsi@iaJN`*U#(8CVX;}K==ae@1Z&?gNIks%Io?BCtt&i%=B3@gdKvG*UnDm# zG_C~38XkI-_jT)a1QsmX>#u{xr8RB}?3C zx^83=BYHjO?g3mc>Z0%aVnd#=YVz~TQPKz0Z89xt`iR;fZ8YcpvPqpHF$y>SYbFL( zz(S%28_w9e_*%*31N^gx>jSQW(RT zxt?VCV}RJTaKxmwH#o*aY!wDeF6DU!;9@$d?1)?;@Z_4W_pnOFS+DrXNT60Cr$Lim z?LV$|G1_s4Alz7$P;Ry0J0pccv_C>czjiRF=uqAC8+rhj;p(+OXT*X)LT(Ge&$P{w)&Nt*uwg|B_`n zvq~@;lZ#CPfJM;P0AG9$rooBL$~gm%fhC} zH<4}lNe>`DJ?y)(&h8xKo6L)6slB|uzyJU7u$LQpYXe(*69YTuL3;QP_^?3jsco^| z-BHusMhc+jKC!Vg-K&Qio`IPPbo-71II$8ze6~3S7wr;8tq2kY9SBM*CG`~Mo15KF zcqbza!EUfTw>@Q36%8-hg;&5RAb&4NeL01ff&g^P_x=4}XY+^I&-;{L1*+dGe=phI zq%S}JW%ehz>Ys^!l_b98H~v|^6BoT4zv$wAXYgHa`bYV0F!XZxV(=q^e{1<&e)>oG zZh7-^_-D(1N$`G0{#{V`NBIsx{xZD$M~ENd)W5&p-{q-4fpmWl^ivM_n;!hGul$La z{d>e;Ke z|J>2P3P6c|ApIjAD*qeQ5Ao~Yclcks=kmV+{^bVbH<$0b9QKd$-61(%qUm1&_(L4~ z_ig&CHyi!C@n6NVe-HHjMUiANk@-G9z-)1EKO!%J`!9NMDSpRLP_;a-XAA|ItOX5G%{->4EPug+z i|6jB({r%5%l8iXm%NidD2=nD@?&Y6tL~?xp?f(Hw6eZvQ literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xml-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xml-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..be20d4543951d7a9ca6568233f3509b6a3686a15 GIT binary patch literal 7496 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 literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xsd-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-schema-util-xsd-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..c7920e08562040b5463be85b0f6fc18801b5a96c GIT binary patch literal 5046 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 literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/pom.xml b/registry/validity/external/validity-checker/pom.xml new file mode 100644 index 0000000..b31b76f --- /dev/null +++ b/registry/validity/external/validity-checker/pom.xml @@ -0,0 +1,250 @@ + + + 4.0.0 + + org.example + Validity + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.4 + + + + + 11 + 11 + 3.0.2 + 6.0.4 + 10.1.5 + + + + + apicurio + apicurio + https://mvnrepository.com/artifact/io.apicurio + + + + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-websocket + ${tomcat.version} + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat.version} + + + + org.projectlombok + lombok + 1.18.20 + + + com.fasterxml.jackson.core + jackson-core + 2.13.4 + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.4 + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.1 + + + + org.springframework + spring-beans + ${springframework.version} + + + org.springframework + spring-core + ${springframework.version} + + + org.springframework + spring-webmvc + ${springframework.version} + + + org.springframework + spring-web + ${springframework.version} + + + org.springframework + spring-aop + ${springframework.version} + + + org.springframework + spring-context + ${springframework.version} + + + org.springframework + spring-expression + ${springframework.version} + + + org.springframework + spring-jcl + ${springframework.version} + + + org.springframework + spring-test + ${springframework.version} + + + + com.fasterxml.woodstox + woodstox-core + 6.4.0 + + + + + org.springframework.boot + spring-boot-starter-test + test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-web + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-tomcat + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-validation + ${springframework.boot.version} + + + org.springframework.boot + spring-boot + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-json + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-logging + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test-autoconfigure + ${springframework.boot.version} + + + + org.yaml + snakeyaml + 2.0 + + + + com.google.protobuf + protobuf-java + 3.21.9 + + + + io.apicurio + apicurio-registry-schema-util-common + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-protobuf + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-avro + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-json + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-xsd + 2.3.1.Final + + + org.json + json + 20230227 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 14 + 14 + + + + validity-checker + + diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/Message.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/Message.java new file mode 100644 index 0000000..c9d473e --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/Message.java @@ -0,0 +1,25 @@ +package net.syntio.validity; + +public class Message { + private final String schemaType; + private final String schema; + private final String validityLevel; + + public Message(String schemaType, String schema, String validityLevel) { + this.schemaType = schemaType; + this.schema = schema; + this.validityLevel = validityLevel; + } + + public String getSchemaType() { + return schemaType; + } + + public String getSchema() { + return schema; + } + + public String getValidityLevel() { + return validityLevel; + } +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/SchemaTypes.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/SchemaTypes.java new file mode 100644 index 0000000..df2ee12 --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/SchemaTypes.java @@ -0,0 +1,9 @@ +package net.syntio.validity; + +public class SchemaTypes { + public static final String JSON = "json"; + public static final String AVRO = "avro"; + public static final String PROTOBUF = "protobuf"; + public static final String XML = "xml"; + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidatorFactory.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidatorFactory.java new file mode 100644 index 0000000..626847d --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidatorFactory.java @@ -0,0 +1,20 @@ +package net.syntio.validity; + +import io.apicurio.registry.rules.validity.AvroContentValidator; +import io.apicurio.registry.rules.validity.ContentValidator; +import io.apicurio.registry.rules.validity.JsonSchemaContentValidator; +import io.apicurio.registry.rules.validity.ProtobufContentValidator; +import io.apicurio.registry.rules.validity.XsdContentValidator; + +public class ValidatorFactory { + public static ContentValidator createValidator(String schema) { + return switch (schema) { + case SchemaTypes.JSON -> new JsonSchemaContentValidator(); + case SchemaTypes.AVRO -> new AvroContentValidator(); + case SchemaTypes.PROTOBUF -> new ProtobufContentValidator(); + case SchemaTypes.XML -> new XsdContentValidator(); + default -> null; + }; + } + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidityCheckerApplication.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidityCheckerApplication.java new file mode 100644 index 0000000..aa3eb01 --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/ValidityCheckerApplication.java @@ -0,0 +1,16 @@ +package net.syntio.validity; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.util.Collections; + +@SpringBootApplication +public class ValidityCheckerApplication { + public static void main(String[] args) { + SpringApplication app = new SpringApplication(ValidityCheckerApplication.class); + app.setDefaultProperties(Collections.singletonMap("server.port", "8089")); + app.run(args); + } + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/checker/Checker.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/checker/Checker.java new file mode 100644 index 0000000..27baf0c --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/checker/Checker.java @@ -0,0 +1,30 @@ +package net.syntio.validity.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.RuleViolationException; +import io.apicurio.registry.rules.validity.ContentValidator; +import io.apicurio.registry.rules.validity.ValidityLevel; + +import net.syntio.validity.ValidatorFactory; + +import java.util.Collections; + +public class Checker { + public static boolean checkValidity(String schemaType, String schema, String mode) { + ValidityLevel valLevel = switch (mode.toLowerCase()) { + case "syntax-only" -> ValidityLevel.SYNTAX_ONLY; + case "full" -> ValidityLevel.FULL; + default -> ValidityLevel.NONE; + }; + + ContentValidator validator = ValidatorFactory.createValidator(schemaType); + ContentHandle contentHandle = ContentHandle.create(schema); + try { + validator.validate(valLevel, contentHandle, Collections.emptyMap()); + return true; + } catch (RuleViolationException e) { + return false; + } + } + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/controller/CheckerController.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/controller/CheckerController.java new file mode 100644 index 0000000..1b76ae6 --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/controller/CheckerController.java @@ -0,0 +1,44 @@ +package net.syntio.validity.controller; + +import net.syntio.validity.Message; +import net.syntio.validity.checker.Checker; +import net.syntio.validity.dto.CheckRequestDto; +import net.syntio.validity.dto.CheckResponseDto; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class CheckerController { + @PostMapping(value = "/") + public ResponseEntity check(@RequestBody CheckRequestDto req) { + Message payload = req.getMessage(); + + try { + String schemaType = payload.getSchemaType(); + String schema = payload.getSchema(); + String mode = payload.getValidityLevel(); + + boolean result = Checker.checkValidity(schemaType, schema, mode); + CheckResponseDto res = new CheckResponseDto(result); + if (result) { + res.setInfo("Schema is valid"); + return ResponseEntity.ok(res); + } + res.setInfo("Schema is invalid"); + return ResponseEntity.ok(res); + + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + } + + @GetMapping(value = "/health") + public ResponseEntity healthCheck() { + return ResponseEntity.ok().build(); + } + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckRequestDto.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckRequestDto.java new file mode 100644 index 0000000..8819bf6 --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckRequestDto.java @@ -0,0 +1,16 @@ +package net.syntio.validity.dto; + +import net.syntio.validity.Message; + +public class CheckRequestDto { + private final Message message; + + public CheckRequestDto(String schema, String format, String mode) { + this.message = new Message(format, schema, mode); + } + + public Message getMessage() { + return this.message; + } + +} diff --git a/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckResponseDto.java b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckResponseDto.java new file mode 100644 index 0000000..143415d --- /dev/null +++ b/registry/validity/external/validity-checker/src/main/java/net/syntio/validity/dto/CheckResponseDto.java @@ -0,0 +1,22 @@ +package net.syntio.validity.dto; + +public class CheckResponseDto { + private final boolean result; + private String info; + + public CheckResponseDto(boolean result) { + this.result = result; + } + + public boolean getResult() { + return result; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/registry/validity/externalChecker.go b/registry/validity/externalChecker.go new file mode 100644 index 0000000..3ff55d2 --- /dev/null +++ b/registry/validity/externalChecker.go @@ -0,0 +1,139 @@ +package validity + +import ( + "context" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-sr/validity/http" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-retry/pkg/retry" +) + +const ( + urlEnvKey = "VALIDITY_CHECKER_URL" + timeoutEnvKey = "VALIDITY_CHECKER_TIMEOUT_BASE" + globalValidityMode = "GLOBAL_VALIDITY_MODE" +) + +const ( + DefaultTimeoutBase = 2 * time.Second + defaultGlobalValidityMode = "FULL" +) + +type ExternalChecker struct { + url string + TimeoutBase time.Duration +} + +// NewExternalCheckerFromEnv loads the needed environment variables and calls NewExternalChecker. +func NewExternalCheckerFromEnv(ctx context.Context) (*ExternalChecker, error) { + url := os.Getenv(urlEnvKey) + if url == "" { + return nil, errtemplates.EnvVariableNotDefined(urlEnvKey) + } + timeout := DefaultTimeoutBase + if timeoutStr := os.Getenv(timeoutEnvKey); timeoutStr != "" { + var err error + timeout, err = time.ParseDuration(timeoutStr) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ParsingEnvVariableFailed(timeoutEnvKey)) + } + } + + return NewExternalChecker(ctx, url, timeout) +} + +// NewExternalChecker returns a new instance of ExternalChecker. +func NewExternalChecker(ctx context.Context, url string, timeoutBase time.Duration) (*ExternalChecker, error) { + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach validity checker at %s failed", url) + } + + return &ExternalChecker{ + url: url, + TimeoutBase: timeoutBase, + }, nil +} + +func (c *ExternalChecker) Check(schema, schemaType, mode string) (bool, error) { + //check if validity mode is none, if it is, don't send HTTP request to java code + if strings.ToLower(mode) == "none" { + return true, nil + } + if strings.ToLower(mode) == "syntax-only" || strings.ToLower(mode) == "full" { + internalCheck, err := internalCheck(schema, schemaType) + if err != nil { + return false, err + } + if !internalCheck { + return false, nil + } + } + + size := []byte(schema + schemaType + mode) + + ctx, cancel := context.WithTimeout(context.Background(), http.EstimateHTTPTimeout(len(size), c.TimeoutBase)) + defer cancel() + + return http.CheckOverHTTP(ctx, schemaType, schema, mode, c.url+"/") +} + +func InitExternalValidityChecker(ctx context.Context) (*ExternalChecker, string, error) { + valChecker, err := NewExternalCheckerFromEnv(ctx) + if err != nil { + return nil, "", err + } + globalValMode := os.Getenv(globalValidityMode) + if globalValMode == "" { + globalValMode = defaultGlobalValidityMode + } + if globalValMode == "SYNTAX-ONLY" || globalValMode == "FULL" || globalValMode == "NONE" { + return valChecker, globalValMode, nil + } + return nil, "", errors.Errorf("unsupported validity mode") +} + +func internalCheck(schema, schemaType string) (bool, error) { + switch schemaType { + case "json", "avro": + return json.Valid([]byte(schema)), nil + case "xml": + return IsValidXML(schema), nil + case "protobuf": //since there is no builtin protobuf validator, we assume schema is valid and propagate validation to external checker + return true, nil + default: + return false, fmt.Errorf("the schemaType is unavailiable") + } +} + +func IsValidXML(input string) bool { + decoder := xml.NewDecoder(strings.NewReader(input)) + for { + err := decoder.Decode(new(interface{})) + if err != nil { + return err == io.EOF + } + } +} + +func CheckIfValidMode(mode *string) bool { + if *mode == "" { + *mode = defaultGlobalValidityMode + } + lowerMode := strings.ToLower(*mode) + if lowerMode != "none" && lowerMode != "syntax-only" && lowerMode != "full" { + return false + } + return true +} diff --git a/registry/validity/http/http.go b/registry/validity/http/http.go new file mode 100644 index 0000000..0979287 --- /dev/null +++ b/registry/validity/http/http.go @@ -0,0 +1,91 @@ +package http + +import ( + "bytes" + "context" + "encoding/json" + "github.com/dataphos/lib-httputil/pkg/httputil" + "io" + "math" + "net/http" + "time" + + "github.com/pkg/errors" +) + +// checkRequest contains a new schema, its type and a validity mode which should be enforced. The structure represents an HTTP request body. +type checkRequest struct { + Schema string `json:"schema"` + Format string `json:"format"` + Mode string `json:"mode"` +} + +// checkResponse contains the validity result and an info message. The structure represents an HTTP response body. +type checkResponse struct { + Result bool `json:"result"` + Info string `json:"info"` +} + +// HTTPTimeoutBytesUnit the base amount of bytes used by EstimateHTTPTimeout. +const HTTPTimeoutBytesUnit = 1024 * 100 + +// EstimateHTTPTimeout calculates the expected timeout, by dividing the size given in bytes with HTTPTimeoutBytesUnit, and then +// multiplying the coefficient with the given time duration. +// +// If the given size is less than HTTPTimeoutBytesUnit, base is returned, to avoid problems due to the http overhead which isn't fully linear. +func EstimateHTTPTimeout(size int, base time.Duration) time.Duration { + coef := int(math.Round(float64(size) / float64(HTTPTimeoutBytesUnit))) + if coef <= 1 { + return base + } + + return time.Duration(coef) * base +} + +// CheckOverHTTP requests a schema check over HTTP. +// Function returns false if schema isn't valid. +func CheckOverHTTP(ctx context.Context, schemaType, schema, mode, url string) (bool, error) { + response, err := sendCheckRequest(ctx, schemaType, schema, mode, url) + if err != nil { + return false, err + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + panic(errors.New("couldn't close response body")) + } + }(response.Body) + + body, err := io.ReadAll(response.Body) + if err != nil { + return false, err + } + + var parsedBody checkResponse + if err = json.Unmarshal(body, &parsedBody); err != nil { + return false, err + } + + valid := parsedBody.Result + + switch response.StatusCode { + case http.StatusOK: + return valid, nil + case http.StatusBadRequest: + return valid, nil + default: + return valid, errors.Errorf("error: status code [%v]", response.StatusCode) + } +} + +func sendCheckRequest(ctx context.Context, schemaType, schema, mode, url string) (*http.Response, error) { + // this can't generate an error, so it's safe to ignore + data, _ := json.Marshal(checkRequest{Schema: schema, Format: schemaType, Mode: mode}) + + request, err := httputil.Post(ctx, url, "application/json", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + return http.DefaultClient.Do(request) +} diff --git a/registry/validity/testdata/invalid_avro_full1.json b/registry/validity/testdata/invalid_avro_full1.json new file mode 100644 index 0000000..8e9758b --- /dev/null +++ b/registry/validity/testdata/invalid_avro_full1.json @@ -0,0 +1,3 @@ +{ + "schema": "{\n \"type\" : \"enu\",\n \"name\" : \"Numbers\", \n \"namspace\": \"data\", \n \"symbols\" : [ \"ONE\", \"TWO\", \"THREE\", \"FOUR\" ]\n}" +} diff --git a/registry/validity/testdata/invalid_avro_syntax1.json b/registry/validity/testdata/invalid_avro_syntax1.json new file mode 100644 index 0000000..a110035 --- /dev/null +++ b/registry/validity/testdata/invalid_avro_syntax1.json @@ -0,0 +1,3 @@ +{ + "schema": "\n \"type\" : \"enum\",\n \"name\" : \"Numbers\", \n \"namspace\": \"data\", \n \"symbols\" : [ \"ONE\", \"TWO\", \"THREE\", \"FOUR\" ]\n" +} diff --git a/registry/validity/testdata/invalid_json_full1.json b/registry/validity/testdata/invalid_json_full1.json new file mode 100644 index 0000000..e7a4e8d --- /dev/null +++ b/registry/validity/testdata/invalid_json_full1.json @@ -0,0 +1,3 @@ +{ + "schema": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": \"1\",\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n }\n }\n}" +} diff --git a/registry/validity/testdata/invalid_json_syntax1.json b/registry/validity/testdata/invalid_json_syntax1.json new file mode 100644 index 0000000..2c9acb2 --- /dev/null +++ b/registry/validity/testdata/invalid_json_syntax1.json @@ -0,0 +1,3 @@ +{ + "schema": "\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n }\n " +} diff --git a/registry/validity/testdata/valid_avro_full1.json b/registry/validity/testdata/valid_avro_full1.json new file mode 100644 index 0000000..02aeef2 --- /dev/null +++ b/registry/validity/testdata/valid_avro_full1.json @@ -0,0 +1,3 @@ +{ + "schema": "{\n \"type\" : \"enum\",\n \"name\" : \"Numbers\", \n \"namespace\": \"data\", \n \"symbols\" : [ \"ONE\", \"TWO\", \"THREE\", \"FOUR\" ]\n}" +} diff --git a/registry/validity/testdata/valid_json_syntax1.json b/registry/validity/testdata/valid_json_syntax1.json new file mode 100644 index 0000000..c561478 --- /dev/null +++ b/registry/validity/testdata/valid_json_syntax1.json @@ -0,0 +1,3 @@ +{ + "schema": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n }\n }\n}" +} diff --git a/validator/README.md b/validator/README.md new file mode 100644 index 0000000..55cf4f2 --- /dev/null +++ b/validator/README.md @@ -0,0 +1,270 @@ +# Dataphos Schema Registry - Worker component + +Repository of the Dataphos Schema Registry Worker. + +## Worker + +The Worker is deployed as a deployment on a Kubernetes cluster and performs the following: + +- Message schema retrieval (and caching) from the Registry using message metadata +- Input message validation using the retrieved schema +- Input message transmission depending on its validation result + +Before the producer starts sending messages their schema needs to be registered in the database, whether it is an +entirely new schema or a new version of an existing one. Each of the messages being sent to the input topic needs to +have its metadata enriched with the schema information, which includes the ID, version and the message format. + +The role of the Worker component is to filter the messages being pushed from the input topic based on the metadata +attributes and route them to their destination. It does so with the help of the Registry component. + +If the schema is registered in the database, the request sent to the Registry will return the schema specification and +the message can be successfully validated and routed to a topic for valid messages. In case of validation failure, the +message will be routed to a topic for dead letter messages. + +Message brokers supported with the Worker component are: + +- GCP Pub/Sub +- Azure ServiceBus +- Azure Event Hubs +- Apache Kafka +- Apache Pulsar +- NATS JetSteam + +Also, the Schema registry enables the use of different protocols for producers and consumers, which ultimately enables +protocol conversion. For example, using the Schema registry protocol conversion you will be able to have a producer that +publishes messages using the Kafka protocol and a consumer that consumes messages using Pub/Sub protocol. + +Providing a data schema and data the validators can determine if the given data is valid for the given schema. Data +types supported are: + +- JSON +- AVRO +- Protocol Buffers +- XML +- CSV + +Instead of logging metrics to standard output, the Worker component has Prometheus support for monitoring and alerting. + + +## Getting Started +### Prerequisites + +Schema Registry components run in a Kubernetes environment. This quickstart guide will assume that you have +the ```kubectl``` tool installed and a running Kubernetes cluster on one of the major cloud providers (GCP, Azure) and a +connection with the cluster. The Kubernetes cluster node/nodes should have at least 8 GB of available RAM. + +Schema Registry has multiple message broker options. This quickstart guide will assume that the publishing message +broker and the consuming message broker will be either GCP Pub/Sub, Azure ServiceBus or Kafka, and that you have +created: + +- (in case of GCP Pub/Sub) service account JSON key with the appropriate roles (Pub/Sub Publisher, Pub/Sub Subscriber) + - [link to create a service account](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console) + - [link to create a JSON key](https://cloud.google.com/iam/docs/keys-create-delete) +- (in case of Azure ServiceBus) ServiceBus connection string +- (in case of Kafka) Kafka broker + - [link to create a Kafka broker on Kubernetes](https://strimzi.io/docs/operators/0.30.0/quickstart.html) +- An input topic and subscription[^1] (The input topic refers to the topic that contains the data in its original +format) +- Valid topic and subscription[^1] (The valid topic refers to the topic where the data is stored after being validated +and serialized using a specific schema) +- Dead-letter topic and subscription[^1] (The valid topic refers to the topic where messages that could not be processed +by a consumer are stored for troubleshooting and analysis purposes) +- (optional) Prometheus server for gathering the metrics and monitoring the logs + - can be deployed using the ```./scripts/prometheus.sh ``` command from the content root + +[^1]: In case of Kafka, no subscription is required. + +> **_NOTE:_** All the deployment scripts are located in the ```./scripts``` folder from the content root. + +--- + +#### Namespace +Before deploying the Schema Registry, the namespace where the components will be deployed should be created if it +doesn't exist. + +--- +Open a command line tool of your choice and connect to your cluster. Create the namespace where Schema Registry will be +deployed. We will use namespace "dataphos" in this quickstart guide. + +```yaml +kubectl create namespace dataphos +``` + +### Quick Start + +Deploy Schema Registry - worker component using the following script. The required arguments are: + +- the namespace +- Schema History Postgres password + +#### GCP Deployment + +The required arguments are: + +- the namespace +- Producer Pub/Sub valid topic ID +- Producer Pub/Sub dead-letter topic ID +- name of the message type used by this worker (json, avro, protobuf, csv, xml) +- Consumer GCP Project ID +- Consumer Pub/Sub Subscription ID (created beforehand) +- Producer GCP Project ID + + +The script is located in the ```./scripts/sr-worker/``` folder from the content root. To run the script, run the +following command: + +``` +# "dataphos" is an example of the namespace name +# "valid-topic" is example of the valid topic name +# "dead-letter-topic" is example of the dead-letter topic name +# "json" is example of the message format name (needs to be either "json", "avro", "csv", "xml", "protobuf") +# "dataphos-project" is example of the consumer GCP project ID +# "input-topic-sub" is example of the input topic subcription name +# "dataphos-project" is example of the producer GCP project ID + +./sr-worker-pubsub.sh "dataphos" "valid-topic" "dead-letter-topic" "json" "dataphos-project" "input-topic-sub" "dataphos-project" +``` + +#### Azure (ServiceBus) Deployment +Required arguments are: + +- the namespace +- Producer ServiceBus valid topic ID +- Producer ServiceBus dead-letter topic ID +- name of the message type used by this worker (json, avro, protobuf, csv, xml) +- Consumer ServiceBus Connection String +- Consumer ServiceBus Topic +- Consumer ServiceBus Subscription +- Producer ServiceBus Connection String + +The script is located in the ```./scripts/sr-worker/``` folder. from the content root. To run the script, run the +following command: + +``` +# "dataphos" is an example of the namespace name +# "valid-topic" is example of the valid topic name +# "dead-letter-topic" is example of the dead-letter topic name +# "json" is example of the message format name (needs to be either "json", "avro", "csv", "xml", "protobuf") +# "Endpoint=sb://foo.servicebus.windows.net/;SharedAccessKeyName=someKeyName;SharedAccessKey=someKeyValue" is example of the consumer ServiceBus connection string (https://azurelessons.com/azure-service-bus-connection-string/) +# "input-topic" is example of the input topic name +# "input-topic-sub" is example of the input topic subcription name +# "Endpoint=sb://foo.servicebus.windows.net/;SharedAccessKeyName=someKeyName;SharedAccessKey=someKeyValue" is example of the producer ServiceBus connection string (https://azurelessons.com/azure-service-bus-connection-string/) + +./sr-worker-servicebus.sh "dataphos" "valid-topic" "dead-letter-topic" "json" "Endpoint=sb://foo.servicebus.windows.net/;SharedAccessKeyName=someKeyName;SharedAccessKey=someKeyValue" "input-topic" "input-topic-sub" "Endpoint=sb://foo.servicebus.windows.net/;SharedAccessKeyName=someKeyName;SharedAccessKey=someKeyValue" +``` + +#### Kafka Deployment (Platform agnostic) + +Required arguments are: + +- the namespace +- Producer Kafka valid topic ID +- Producer Kafka dead-letter topic ID +- name of the message type used by this worker (json, avro, protobuf, csv, xml) +- Consumer Kafka bootstrap server address +- Consumer Kafka Topic +- Consumer Kafka Group ID +- Producer Kafka bootstrap server address + +The script is located in the ```./scripts/sr-worker/``` folder. from the content root. To run the script, run the +following command: + +``` +# "dataphos" is an example of the namespace name +# "valid-topic" is example of the valid topic name +# "dead-letter-topic" is example of the dead-letter topic name +# "json" is example of the message format name (needs to be either "json", "avro", "csv", "xml", "protobuf") +# "127.0.0.1:9092" is example of the consumer Kafka bootstrap server address +# "input-topic" is example of the input topic name +# "group01" is example of the input topic group ID +# "127.0.0.1:9092" is example of the producer Kafka bootstrap server address + +./sr-worker-kafka.sh "dataphos" "valid-topic" "dead-letter-topic" "json" "127.0.0.1:9092" "input-topic" "group01" "127.0.0.1:9092" +``` + +## Usage + + +### Message format + +Depending on the technology your producer uses, the way you shape the message may differ and therefore the part of the +message that contains the metadata might be called ```attributes```, ```metadata,``` etc. + +Besides the data field, which contains the message data, inside the attributes (or metadata) structure it's important to +add fields ```schemaId```, ```versionId``` and ```format``` +which are important information for the worker component. In case some additional attributes are provided, the worker +won't lose them, they will be delegated to the destination topic. + +### GCP Pub/Sub + +``` +{ + "ID": string, + "Data": string, + "Attributes": { + schemaId: string, + versionId: string, + format: string, + ... + }, + "PublishTime": time, +} +``` + +| Field | Description | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Data | **string** (bytes format)

The message data field. If this field is empty, the message must contain at least one attribute.

A base64-encoded string. | +| Attributes | **map** (key: string, value: string)

Attributes for this message. If this field is empty, the message must contain non-empty data. This can be used to filter messages on the subscription.

An object containing a list of "key": value pairs. Example: { "schemaId": "1", "versionId": "2", "format": "json" }. | +| PublishTime| **time** (time.Time format)

PublishTime is the time at which the message was published. This is populated by the server for Messages obtained from a subscription.| + +### Azure ServiceBus +``` +{ + "MessageID": string, + "Body": string, + "PartitionKey": string, + "ApplicationProperties": { + schemaId: string, + versionId: string, + format: string, + ... + }, + EnqueuedTime: time +} +``` + +| Field | Description | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Body | **string** (bytes format)

The message data field. If this field is empty, the message must contain at least one application property. | +| ApplicationProperties | **map** (key: string, value: string)

Attributes for this message. ApplicationProperties can be used to store custom metadata for a message.

An object containing a list of "key": value pairs. Example: { "schemaId": "1", "versionId": "2", "format": "json" }. | +| PartitionKey| **string**

PartitionKey is used with a partitioned entity and enables assigning related messages to the same internal partition. This ensures that the submission sequence order is correctly recorded. The partition is chosen by a hash function in Service Bus and cannot be chosen directly.| +| EnqueuedTime| **time** (time.Time format)

EnqueuedTime is the UTC time when the message was accepted and stored by Service Bus.| + + +### Kafka + +``` +{ + "Key": string, + "Value": string, + "Offset": int64, + "Partition": int32, + "Headers": { + schemaId: string, + versionId: string, + format: string, + ... + }, + Timestamp: time +} +``` + +| Field | Description | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Key | **string** (bytes format)

Key is an optional field that can be used for partition assignment. | +| Value | **string** (bytes format)

Value is blob of data to write to Kafka. | +| Offset | **int64**

Offset is the offset that a record is written as.| +| Partition | **int32**

Partition is the partition that a record is written to.| +| Headers | **map** (key: string, value: string)

Headers are optional key/value pairs that are passed along with records.

Example: { "schemaId": "1", "versionId": "2", "format": "json" }.

These are purely for producers and consumers; Kafka does not look at this field and only writes it to disk. | +| Timestamp| **time** (time.Time format)

Timestamp is the timestamp that will be used for this record. Record batches are always written with "CreateTime", meaning that timestamps are generated by clients rather than brokers.| + diff --git a/validator/cmd/centralconsumer/main.go b/validator/cmd/centralconsumer/main.go new file mode 100644 index 0000000..8b7e3b8 --- /dev/null +++ b/validator/cmd/centralconsumer/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "flag" + "math/rand" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitorctl" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + configFile := flag.String("f", "", "toml file containing configuration of working environment") + flag.Parse() + + janitorctl.RunCentralConsumer(*configFile) +} diff --git a/validator/cmd/pullercleaner/main.go b/validator/cmd/pullercleaner/main.go new file mode 100644 index 0000000..fa86a3a --- /dev/null +++ b/validator/cmd/pullercleaner/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "flag" + "math/rand" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitorctl" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + configFile := flag.String("f", "", "toml file containing configuration of working environment") + flag.Parse() + + janitorctl.RunPullerCleaner(*configFile) +} diff --git a/validator/config/validator.toml b/validator/config/validator.toml new file mode 100644 index 0000000..98128f5 --- /dev/null +++ b/validator/config/validator.toml @@ -0,0 +1,60 @@ +# configuration for central consumer +mode = "" +schema_id = "" +schema_version = "" +schema_type = "" + +[consumer] +type = "" # insert "kafka", "pubsub", "servicebus" or "jetstream" +encryption_key = "" + +[consumer.kafka] +address = "" # insert +topic = "" # insert +group_id = "" # insert + +[consumer.pubsub] +project_id = "" # insert +subscription_id = "" # insert + +[consumer.servicebus] +connection_string = "" # insert +topic = "" # insert +subscription = "" # insert + +[consumer.jetstream] +url = "" # insert +subject = "" # insert +consumer_name = "" # insert + +[producer] +type = "" # insert "kafka", "eventhubs", "pubsub", "servicebus" or "jetstream" + +[producer.kafka] +address = "" # insert + +[producer.pubsub] +project_id = "" # insert + +[producer.servicebus] +connection_string = "" # insert + +[producer.jetstream] +url = "" # insert + +[topics] +valid = "" # insert +dead_letter = "" # insert + +[registry] +url = "" +type = "janitor" # insert "janitor" or "apicurio" +groupID = "default" + +[validators] +enable_json = "true" +enable_csv = "false" +enable_xml = "false" +enable_protobuf = "false" +csv_url = "http://csv-validator-svc:8080" +xml_url = "http://xml-validator-svc:8081" diff --git a/validator/docker/csv-validator/Dockerfile b/validator/docker/csv-validator/Dockerfile new file mode 100644 index 0000000..a6a051d --- /dev/null +++ b/validator/docker/csv-validator/Dockerfile @@ -0,0 +1,41 @@ +# References the base image for Java 11 and maven +FROM maven:3.8.4-openjdk-17-slim AS build + +# Maintainer Info +LABEL maintainer="Syntio Inc." + +# Copy the source code to a new working directory +COPY validator/internal/validator/external/csv-validator/src /home/app/src + +# Copy the pom.xml to the root of the project +COPY validator/internal/validator/external/csv-validator/pom.xml /home/app + +COPY validator/licenses/csv-validator/LICENSE-3RD-PARTY.md /home/app/licenses/LICENSE-3RD-PARTY.md +COPY LICENSE /home/app/licenses/LICENSE + +# Download dependecies and build +RUN mvn -f /home/app/pom.xml clean package + +# References base image for Java 11 runtime +FROM openjdk:22-ea-17-jdk-slim + +# Copy the binaries in a new working directory +COPY --from=build /home/app/target/csv-validator-0.0.1-SNAPSHOT.jar /home/csv/validator.jar +COPY --from=build /home/app/licenses/LICENSE-3RD-PARTY.md /home/csv/licenses/LICENSE-3RD-PARTY.md +COPY --from=build /home/app/licenses/LICENSE /home/csv/licenses/LICENSE + +# Expose port 8080 to the outside world +EXPOSE 8080 + +# change to a non-root user for security +RUN adduser --disabled-password --home /home/csv user +RUN chown -R user /home/csv +RUN chmod -R 555 /home/csv +USER user + +# Set entrypoint of command that will run when container is started +ENTRYPOINT ["java","-jar","/home/csv/validator.jar"] + +# From the helper-functions directory: +# sudo docker build -t centralconsumer-csv-val . +# sudo docker run centralconsumer-csv-val diff --git a/validator/docker/validator/Dockerfile b/validator/docker/validator/Dockerfile new file mode 100644 index 0000000..0a91492 --- /dev/null +++ b/validator/docker/validator/Dockerfile @@ -0,0 +1,37 @@ +FROM golang:alpine3.16 as build + +LABEL maintainer="Syntio Inc." + +ENV GO111MODULE=on \ + GOOS=linux \ + GOARCH=amd64 \ + CGO_ENABLED=0 + +RUN apk add --no-cache git + +WORKDIR /src + +COPY ./validator/go.mod ./validator/go.sum . +RUN go mod download + +COPY ./validator . +COPY LICENSE ./licenses/ + +RUN go mod tidy + +RUN go build -buildvcs=false -o /app/validator ./cmd/centralconsumer + +FROM alpine:3.16 + +COPY --from=build /app/validator /app/validator +COPY --from=build /src/config/validator.toml app/config/validator.toml +COPY --from=build /src/licenses/LICENSE-3RD-PARTY.md /app/licenses/ +COPY --from=build /src/licenses/LICENSE /app/licenses/ + +# change to a non-root user for security +RUN adduser -D -h /app user +RUN chown -R user /app +RUN chmod -R 777 /app +USER user + +ENTRYPOINT ["/app/validator", "-f", "/app/config/validator.toml" ] diff --git a/validator/docker/xml-validator/Dockerfile b/validator/docker/xml-validator/Dockerfile new file mode 100644 index 0000000..7532c8e --- /dev/null +++ b/validator/docker/xml-validator/Dockerfile @@ -0,0 +1,28 @@ +# References the base image for running Python applications +FROM python:3.7-alpine + +# Maintainer Info +LABEL maintainer="Syntio Inc." + +# Set the current working directory inside the container +WORKDIR /code + +# Copy the dependencies file to the working directory inside the container +COPY validator/internal/validator/external/xml-validator/requirements.txt . + +# Install dependencies from the file +RUN pip install --no-cache-dir -r requirements.txt + +# Copy source (content of the local src directory) to the working directory inside the container +COPY validator/internal/validator/external/xml-validator . +COPY validator/licenses/xml-validator/LICENSE-3RD-PARTY.md app/licenses/LICENSE-3RD-PARTY.md +COPY LICENSE /app/licenses/LICENSE + +# change to a non-root user for security +RUN adduser -D -h /code user +RUN chown -R user /code +RUN chmod -R 555 /code +USER user + +EXPOSE 8081 +CMD [ "python", "./main.py" ] diff --git a/validator/go.mod b/validator/go.mod new file mode 100644 index 0000000..2178f19 --- /dev/null +++ b/validator/go.mod @@ -0,0 +1,115 @@ +module github.com/dataphos/aquarium-janitor-standalone-internal + +go 1.21 + +toolchain go1.22.2 + +require ( + github.com/dataphos/lib-batchproc v1.0.0 + github.com/dataphos/lib-brokers v1.0.0 + github.com/dataphos/lib-httputil v1.0.0 + github.com/dataphos/lib-logger v1.0.0 + github.com/dataphos/lib-retry v1.0.0 + github.com/dataphos/lib-shutdown v1.0.0 + github.com/dataphos/lib-streamproc v1.0.0 + github.com/go-playground/validator/v10 v10.11.1 + github.com/hamba/avro v1.8.0 + github.com/hashicorp/golang-lru v0.5.4 + github.com/jhump/protoreflect v1.12.0 + github.com/kkyr/fig v0.3.0 + github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.15.1 + github.com/santhosh-tekuri/jsonschema/v5 v5.0.2 + github.com/xeipuuv/gojsonschema v1.2.0 + go.uber.org/multierr v1.9.0 + go.uber.org/ratelimit v0.2.0 + golang.org/x/net v0.23.0 + golang.org/x/sync v0.3.0 + google.golang.org/protobuf v1.33.0 +) + +require ( + cloud.google.com/go v0.110.8 // indirect + cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.2 // indirect + cloud.google.com/go/pubsub v1.33.0 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/99designs/keyring v1.2.2 // indirect + github.com/AthenZ/athenz v1.11.29 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.3.0 // indirect + github.com/Azure/go-amqp v1.0.0 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect + github.com/apache/pulsar-client-go v0.14.0 // indirect + github.com/ardielle/ardielle-go v1.5.2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/danieljoos/wincred v1.2.0 // indirect + github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/frankban/quicktest v1.14.6 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hamba/avro/v2 v2.22.2-0.20240625062549-66aad10411d9 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/joho/godotenv v1.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/nats-io/nats.go v1.25.0 // indirect + github.com/nats-io/nkeys v0.4.4 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pierrec/lz4/v4 v4.1.17 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.43.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/twmb/franz-go v1.13.3 // indirect + github.com/twmb/franz-go/pkg/kmsg v1.5.0 // indirect + github.com/twmb/franz-go/pkg/sasl/kerberos v1.1.0 // indirect + github.com/twmb/franz-go/plugin/kprom v1.0.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + go.opencensus.io v0.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/zap v1.23.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/api v0.128.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.59.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/validator/go.sum b/validator/go.sum new file mode 100644 index 0000000..a537da2 --- /dev/null +++ b/validator/go.sum @@ -0,0 +1,918 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/AthenZ/athenz v1.11.29 h1:lVo3kz17gXMagqpN7rzTwEym5jsfhthvfLUKo5JXU5o= +github.com/AthenZ/athenz v1.11.29/go.mod h1:hz8WrHkj4KOOaejllzTJIoXBCtptWV279CtEAUDuxis= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 h1:Yoicul8bnVdQrhDMTHxdEckRGX01XvwXDHUT9zYZ3k0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.3.0 h1:eLqmA+3GXbOOLJVTSqkrFudTbHkfOp5HIy+iShCNM7A= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.3.0/go.mod h1:pXDkeh10bAqElvd+S5Ppncj+DCKvJGXNa8rRT2R7rIw= +github.com/Azure/go-amqp v1.0.0 h1:QfCugi1M+4F2JDTRgVnRw7PYXLXZ9hmqk3+9+oJh3OA= +github.com/Azure/go-amqp v1.0.0/go.mod h1:+bg0x3ce5+Q3ahCEXnCsGG3ETpDQe3MEVnOuT2ywPwc= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 h1:WVsrXCnHlDDX8ls+tootqRE87/hL9S/g4ewig9RsD/c= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.5 h1:haEcLNpj9Ka1gd3B3tAEs9CpE0c+1IhoL59w/exYU38= +github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/pulsar-client-go v0.14.0 h1:P7yfAQhQ52OCAu8yVmtdbNQ81vV8bF54S2MLmCPJC9w= +github.com/apache/pulsar-client-go v0.14.0/go.mod h1:PNUE29x9G1EHMvm41Bs2vcqwgv7N8AEjeej+nEVYbX8= +github.com/ardielle/ardielle-go v1.5.2 h1:TilHTpHIQJ27R1Tl/iITBzMwiUGSlVfiVhwDNGM3Zj4= +github.com/ardielle/ardielle-go v1.5.2/go.mod h1:I4hy1n795cUhaVt/ojz83SNVCYIGsAFAONtv2Dr7HUI= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= +github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= +github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= +github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= +github.com/dataphos/lib-batchproc v1.0.0 h1:5rZo080k+3wmzg7vTcccJgyX0cnbEhczOhfL1N6arQw= +github.com/dataphos/lib-batchproc v1.0.0/go.mod h1:ZdReLkmcDK9r+qvjRZRNqqNn+OKOTcKpgx+J4cdasMc= +github.com/dataphos/lib-brokers v1.0.0 h1:8/uu2iX5iaddDBIp9iVugPOHWWLnN0My3eIpnnnZmME= +github.com/dataphos/lib-brokers v1.0.0/go.mod h1:6pOEBPGA4GUbTQPAEt8XwsamRHE7hmkXNb/9sRhn05A= +github.com/dataphos/lib-httputil v1.0.0 h1:xfaZqHz+PXxifPJU0kS/FhbQG7dEVQEibBCz9MPBPgY= +github.com/dataphos/lib-httputil v1.0.0/go.mod h1:XlXMsNAj94vwBt0pc3G9reLln51G5puRX8Qv24zmmiI= +github.com/dataphos/lib-logger v1.0.0 h1:c6d1//cyVpXB0QvixUb79rMz9OuFzvGYtk2PE8WXqtE= +github.com/dataphos/lib-logger v1.0.0/go.mod h1:AJi106+YVssJ0ak0GrrMoqvtgA+0ido2ZlvxuKyxqUQ= +github.com/dataphos/lib-retry v1.0.0 h1:pvh00Esu34z9bWKliphkeT8DHO9paLOGAi9oQ3yVN4c= +github.com/dataphos/lib-retry v1.0.0/go.mod h1:0T0VfgdamSHvieGMVMBRThXqZGezx/E1bItanDHsmDM= +github.com/dataphos/lib-shutdown v1.0.0 h1:RDFwxWH6UpEvQvpi9ubbMP7ZPu9zqTB22vz9i/or9Nc= +github.com/dataphos/lib-shutdown v1.0.0/go.mod h1:mQP+k4FYte4EOwbHGjiOOqE0PVyECKaWrLa9fVw3h/Y= +github.com/dataphos/lib-streamproc v1.0.0 h1:3t9tDlkOm4atsglnAhdZB+0o6h/yTFqeXvqfB79wZv0= +github.com/dataphos/lib-streamproc v1.0.0/go.mod h1:UNiH7T+macu2tHWjnI1C/2P6a1luYX7X6t43TN/cWjo= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dimfeld/httptreemux v5.0.1+incompatible h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA= +github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v23.0.0+incompatible h1:bcM4syaQ+EM/iczJTimMOGzvnzJBFPFEf4acS7sZ+RM= +github.com/docker/cli v23.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= +github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/hamba/avro v1.8.0 h1:eCVrLX7UYThA3R3yBZ+rpmafA5qTc3ZjpTz6gYJoVGU= +github.com/hamba/avro v1.8.0/go.mod h1:NiGUcrLLT+CKfGu5REWQtD9OVPPYUGMVFiC+DE0lQfY= +github.com/hamba/avro/v2 v2.22.2-0.20240625062549-66aad10411d9 h1:NEoabXt33PDWK4fXryK4e+XX+fSKDmmu9vg3yb9YI2M= +github.com/hamba/avro/v2 v2.22.2-0.20240625062549-66aad10411d9/go.mod h1:fQVdB2mFZBhPW1D5Abej41LMvrErARGrrdjOnKbm5yw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= +github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= +github.com/jhump/protoreflect v1.12.0 h1:1NQ4FpWMgn3by/n1X0fbeKEUxP1wBt7+Oitpv01HR10= +github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkyr/fig v0.3.0 h1:5bd1amYKp/gsK2bGEUJYzcCrQPKOZp6HZD9K21v9Guo= +github.com/kkyr/fig v0.3.0/go.mod h1:fEnrLjwg/iwSr8ksJF4DxrDmCUir5CaVMLORGYMcz30= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.9.14 h1:n2GscWVgXpA14vQSRP/MM1SGi4wyazR9l19/gWxqgXQ= +github.com/nats-io/nats-server/v2 v2.9.14/go.mod h1:40ZwFm4npKdFBhOdY7rkh3YyI1oI91FzLvlYyB7HfzM= +github.com/nats-io/nats.go v1.25.0 h1:t5/wCPGciR7X3Mu8QOi4jiJaXaWM8qtkLu4lzGZvYHE= +github.com/nats-io/nats.go v1.25.0/go.mod h1:D2WALIhz7V8M0pH8Scx8JZXlg6Oqz5VG+nQkK8nJdvg= +github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA= +github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= +github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= +github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh5us= +github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/santhosh-tekuri/jsonschema/v5 v5.0.2 h1:zOYFITq/5SO7YOv39/Taw8s1skb0Py39K5V2XvCEP48= +github.com/santhosh-tekuri/jsonschema/v5 v5.0.2/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= +github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/twmb/franz-go v1.0.0/go.mod h1:cdFLk8d/5/ox88y38xgiDKP3Yo338OO0t5QbTEM2K6I= +github.com/twmb/franz-go v1.7.0/go.mod h1:PMze0jNfNghhih2XHbkmTFykbMF5sJqmNJB31DOOzro= +github.com/twmb/franz-go v1.13.3 h1:AO0HcPu7hNMi+ue+jz3CnV+VpuAizaazQuqTo1SvLr4= +github.com/twmb/franz-go v1.13.3/go.mod h1:jm/FtYxmhxDTN0gNSb26XaJY0irdSVcsckLiR5tQNMk= +github.com/twmb/franz-go/pkg/kadm v1.7.0 h1:TAgcS+t5q+9jnm8INCD2OJ1MD9y4Ij6pD5CYfZ3tkbg= +github.com/twmb/franz-go/pkg/kadm v1.7.0/go.mod h1:sI9BjVkpjyYssIlVa+WIwseaUjJqPsR/8gmJi6aDyEk= +github.com/twmb/franz-go/pkg/kmsg v0.0.0-20210901051457-3c197a133ddd/go.mod h1:SxG/xJKhgPu25SamAq0rrucfp7lbzCpEXOC+vH/ELrY= +github.com/twmb/franz-go/pkg/kmsg v0.0.0-20210914042331-106aef61b693/go.mod h1:SxG/xJKhgPu25SamAq0rrucfp7lbzCpEXOC+vH/ELrY= +github.com/twmb/franz-go/pkg/kmsg v1.2.0/go.mod h1:SxG/xJKhgPu25SamAq0rrucfp7lbzCpEXOC+vH/ELrY= +github.com/twmb/franz-go/pkg/kmsg v1.5.0 h1:eqVJquFQLdBNLrRMWX03pPDPpngn6PTjGZLlZnagouk= +github.com/twmb/franz-go/pkg/kmsg v1.5.0/go.mod h1:se9Mjdt0Nwzc9lnjJ0HyDtLyBnaBDAd7pCje47OhSyw= +github.com/twmb/franz-go/pkg/sasl/kerberos v1.1.0 h1:alKdbddkPw3rDh+AwmUEwh6HNYgTvDSFIe/GWYRR9RM= +github.com/twmb/franz-go/pkg/sasl/kerberos v1.1.0/go.mod h1:k8BoBjyUbFj34f0rRbn+Ky12sZFAPbmShrg0karAIMo= +github.com/twmb/franz-go/plugin/kprom v1.0.0 h1:VcWVmtYnsTBhhes33xHp0FHJBLZRa7hslUfdFNPmJwQ= +github.com/twmb/franz-go/plugin/kprom v1.0.0/go.mod h1:DFcybS1MpHf9POwG2BYvViS4u4y12t8dyCp7Hlc4g9I= +github.com/twmb/go-rbtree v1.0.0/go.mod h1:UlIAI8gu3KRPkXSobZnmJfVwCJgEhD/liWzT5ppzIyc= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8= +google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/validator/internal/centralconsumer/centralconsumer.go b/validator/internal/centralconsumer/centralconsumer.go new file mode 100644 index 0000000..8665c43 --- /dev/null +++ b/validator/internal/centralconsumer/centralconsumer.go @@ -0,0 +1,463 @@ +package centralconsumer + +import ( + "context" + "encoding/json" + "strconv" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-logger/logger" + "github.com/pkg/errors" +) + +// Mode is the way Central consumer works; if the mode is Default, one CC will be deployed, and it will validate multiple +// different schemas. If it's OneCCPerTopic, there will be one CC for each topic, and it will validate only one schema. +type Mode int + +const ( + Default Mode = iota + OneCCPerTopic +) + +type SchemaMetadata struct { + ID string + Version string + Format string +} + +type Schema struct { + SchemaMetadata SchemaMetadata + Specification []byte +} + +type SchemaDefinition struct { + ID string `json:"schema_id,omitempty"` + Type string `json:"schema_type"` + Name string `json:"name"` + Description string `json:"description"` + LastCreated string `json:"last_created"` + Versions []VersionDetails `json:"schemas"` +} + +type VersionDetails struct { + Version string `json:"version"` + Specification []byte `json:"specification"` +} + +// CentralConsumer models the central consumer process. +type CentralConsumer struct { + Registry registry.SchemaRegistry + Validators janitor.Validators + Router janitor.Router + Publisher broker.Publisher + topicIDs Topics + topics map[string]broker.Topic + registrySem chan struct{} + validatorsSem chan struct{} + log logger.Log + mode Mode + schema Schema + encryptionKey string +} + +// Settings holds settings concerning the concurrency limits for various stages of the central consumer pipeline. +type Settings struct { + // NumSchemaCollectors defines the maximum amount of inflight requests to the schema registry. + NumSchemaCollectors int + + // NumInferrers defines the maximum amount of inflight destination topic inference jobs (validation and routing). + NumInferrers int +} + +// Topics defines the standard destination topics, based on validation results. +type Topics struct { + Valid string + InvalidCSV string + InvalidJSON string + Deadletter string +} + +// RouterFlags defines logging levels for logging each routing decision. +type RouterFlags struct { + MissingSchema bool + Valid bool + Invalid bool + Deadletter bool +} + +// New is a convenience function which returns a new instance of CentralConsumer. +func New(registry registry.SchemaRegistry, publisher broker.Publisher, validators janitor.Validators, topicIds Topics, settings Settings, log logger.Log, routerFlags RouterFlags, mode Mode, schemaMetadata SchemaMetadata, encryptionKey string) (*CentralConsumer, error) { + var ( + schemaVersion VersionDetails + format string + ) + + topics, err := idsIntoTopics(topicIds, publisher) + if err != nil { + return nil, errors.Wrap(err, errtemplates.LoadingTopicsFailed) + } + + var registrySem chan struct{} + if settings.NumSchemaCollectors > 0 { + registrySem = make(chan struct{}, settings.NumSchemaCollectors) + } + var validatorsSem chan struct{} + if settings.NumInferrers > 0 { + validatorsSem = make(chan struct{}, settings.NumInferrers) + } + + var schemaReturned []byte + if mode == OneCCPerTopic { + if schemaMetadata.ID != "" { + if schemaMetadata.Version != "" { + schemaSpecReturned, err := registry.Get(context.Background(), schemaMetadata.ID, schemaMetadata.Version) + if err != nil { + return &CentralConsumer{}, err + } + schemaVersion.Version = schemaMetadata.Version + schemaVersion.Specification = schemaSpecReturned + } else { + schemaReturned, err = registry.GetLatest(context.Background(), schemaMetadata.ID) + if err != nil { + return &CentralConsumer{}, err + } + if err = json.Unmarshal(schemaReturned, &schemaVersion); err != nil { + return &CentralConsumer{}, errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + } + if schemaMetadata.Format != "" { + format = schemaMetadata.Format + } else { + return &CentralConsumer{}, errors.New("schema format not specified") + } + } else { + return &CentralConsumer{}, errors.New("schema ID not specified") + } + } + + return &CentralConsumer{ + Registry: registry, + Validators: validators, + Router: setupRoutingFunc(topicIds, routerFlags, log), + topicIDs: topicIds, + Publisher: publisher, + topics: topics, + registrySem: registrySem, + validatorsSem: validatorsSem, + log: log, + mode: mode, + schema: Schema{ + SchemaMetadata: SchemaMetadata{ + ID: schemaMetadata.ID, + Version: schemaVersion.Version, + Format: format, + }, + Specification: schemaVersion.Specification, + }, + encryptionKey: encryptionKey, + }, nil +} + +// idsIntoTopics maps Topics into instances of broker.Topic. +func idsIntoTopics(topicIds Topics, publisher broker.Publisher) (map[string]broker.Topic, error) { + topics := make(map[string]broker.Topic) + + if topicIds.Valid != "" { + topic, err := publisher.Topic(topicIds.Valid) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.Valid)) + } + topics[topicIds.Valid] = topic + } + + if topicIds.InvalidJSON != "" { + topic, err := publisher.Topic(topicIds.InvalidJSON) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.InvalidJSON)) + } + topics[topicIds.InvalidJSON] = topic + } + + if topicIds.InvalidCSV != "" { + topic, err := publisher.Topic(topicIds.InvalidCSV) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.InvalidCSV)) + } + topics[topicIds.InvalidCSV] = topic + } + + if topicIds.Deadletter != "" { + topic, err := publisher.Topic(topicIds.Deadletter) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.Deadletter)) + } + topics[topicIds.Deadletter] = topic + } + return topics, nil +} + +// setupRoutingFunc sets up the janitor.LoggingRouter, by first checking if there's a need for logging any of the routing +// decisions (if any logging level flag is set). If none of the flags are set, standard intoRouter is used, +// wrapping it with logging middleware otherwise. +func setupRoutingFunc(topics Topics, routerFlags RouterFlags, log logger.Log) janitor.Router { + next := intoRouter(topics) + + if routerFlags.MissingSchema || routerFlags.Valid || routerFlags.Invalid || routerFlags.Deadletter { + return janitor.LoggingRouter( + log, + janitor.RouterFlags{ + MissingSchema: routerFlags.MissingSchema, + Valid: routerFlags.Valid, + Invalid: routerFlags.Invalid, + Deadletter: routerFlags.Deadletter, + }, + next, + ) + } + + return next +} + +const ( + avroFormat = "avro" + csvFormat = "csv" + jsonFormat = "json" + protobufFormat = "protobuf" + xmlFormat = "xml" +) + +// intoRouter maps the given Topics into a janitor.LoggingRouter. +// +// All janitor.Valid messages are routed to Topics.Valid. +// +// All janitor.Deadletter messages are routed to Topics.Deadletter. +// +// If the result is janitor.MissingSchema, +// CSV and JSON formats are routed to Topics.InvalidCSV and Topics.InvalidJSON, respectively, +// while all other formats are routed to Topics.Deadletter. +// +// If the result is janitor.Invalid, +// CSV and JSON formats are routed to Topics.InvalidCSV and Topics.InvalidJSON, respectively, +// while all other formats are routed to Topics.Deadletter. +func intoRouter(topics Topics) janitor.Router { + return janitor.RoutingFunc(func(result janitor.Result, message janitor.Message) string { + format := message.Format + + switch result { + case janitor.Valid: + return topics.Valid + case janitor.Deadletter: + return topics.Deadletter + case janitor.MissingSchema, janitor.Invalid: + switch format { + case csvFormat: + return topics.InvalidCSV + case jsonFormat: + return topics.InvalidJSON + default: + return topics.Deadletter + } + default: + return topics.Deadletter + } + }) +} + +func (cc *CentralConsumer) AsProcessor() *janitor.Processor { + return janitor.NewProcessor(cc, cc.topics, cc.topicIDs.Deadletter, cc.log) +} + +func (cc *CentralConsumer) Handle(ctx context.Context, message janitor.Message) (janitor.MessageTopicPair, error) { + var ( + messageSchemaPair janitor.MessageSchemaPair + messageTopicPair janitor.MessageTopicPair + specificSchemaVersion VersionDetails + err error + encryptedMessageData []byte + ) + + if cc.mode == Default { + acquireIfSet(cc.registrySem) + messageSchemaPair, err = janitor.CollectSchema(ctx, message, cc.Registry) + if err != nil { + setMessageRawAttributes(message, err, "Wrong compile") + releaseIfSet(cc.registrySem) + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } + releaseIfSet(cc.registrySem) + + messageTopicPair, err = cc.getMessageTopicPair(messageSchemaPair, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + return messageTopicPair, nil + + } else if cc.mode == OneCCPerTopic { + if message.Version == "" { // Version not set in message + messageTopicPair, err = cc.getMessageTopicPair(janitor.MessageSchemaPair{ + Message: message, + Schema: cc.schema.Specification, + }, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + if messageTopicPair.Topic == cc.topicIDs.Deadletter { + // if message is invalid against latest schema saved in CC, then fetch latest from SR and revalidate + messageTopicPair, err = cc.revalidatedAgainstLatest(ctx, specificSchemaVersion, message, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + } + return messageTopicPair, nil + } else { + if message.Version == cc.schema.SchemaMetadata.Version { + messageTopicPair, err = cc.getMessageTopicPair(janitor.MessageSchemaPair{ + Message: message, + Schema: cc.schema.Specification, + }, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + return messageTopicPair, nil + } else { + acquireIfSet(cc.registrySem) + specificSchemaVersionSpec, err := cc.Registry.Get(ctx, cc.schema.SchemaMetadata.ID, message.Version) + if err != nil { + setMessageRawAttributes(message, err, "Wrong compile") + releaseIfSet(cc.registrySem) + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } + releaseIfSet(cc.registrySem) + + err = cc.updateIfNewer(VersionDetails{ + Version: message.Version, + Specification: specificSchemaVersionSpec, + }) + if err != nil { + setMessageRawAttributes(message, err, "Non number version") + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } + + messageTopicPair, err = cc.getMessageTopicPair(janitor.MessageSchemaPair{ + Message: message, + Schema: specificSchemaVersionSpec, + }, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + return messageTopicPair, nil + } + } + } else { + err = errors.New("unknown CC mode") + setMessageRawAttributes(message, err, "Unknown CC mode") + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } +} + +func (cc *CentralConsumer) getMessageTopicPair(messageSchemaPair janitor.MessageSchemaPair, encryptedMessageData []byte) (janitor.MessageTopicPair, error) { + acquireIfSet(cc.validatorsSem) + var err error + if cc.encryptionKey != "" { + encryptedMessageData = messageSchemaPair.Message.Payload + messageSchemaPair.Message.Payload, err = janitor.Decrypt(messageSchemaPair.Message.Payload, cc.encryptionKey) + if err != nil { + messageSchemaPair.Message.RawAttributes["deadLetterErrorCategory"] = "Failure to decrypt" + messageSchemaPair.Message.RawAttributes["deadLetterErrorReason"] = err.Error() + return janitor.MessageTopicPair{Message: messageSchemaPair.Message, Topic: cc.Router.Route(janitor.Deadletter, messageSchemaPair.Message)}, err + } + } + messageTopicPair, err := janitor.InferDestinationTopic(messageSchemaPair, cc.Validators, cc.Router) + if err != nil { + releaseIfSet(cc.validatorsSem) + return messageTopicPair, err + } + releaseIfSet(cc.validatorsSem) + return messageTopicPair, nil +} + +func (cc *CentralConsumer) updateVersion(vd VersionDetails) { + cc.schema.SchemaMetadata.Version = vd.Version + cc.schema.Specification = vd.Specification +} + +// checkIfNewer checks if v2 is newer than v1 +func checkIfNewer(v1, v2 string) (bool, error) { + v1Int, err := strconv.Atoi(v1) + if err != nil { + return false, err + } + v2Int, err := strconv.Atoi(v2) + if err != nil { + return false, err + } + if v2Int > v1Int { + return true, nil + } + return false, nil +} + +// revalidatedAgainstLatest fetches latest version of schema from Schema Registry and validates the message against it +func (cc *CentralConsumer) revalidatedAgainstLatest(ctx context.Context, specificSchemaVersion VersionDetails, message janitor.Message, encryptedMessageData []byte) (janitor.MessageTopicPair, error) { + var messageTopicPair janitor.MessageTopicPair + + acquireIfSet(cc.registrySem) + specificSchemaVersionBytes, err := cc.Registry.GetLatest(ctx, cc.schema.SchemaMetadata.ID) + if err != nil { + setMessageRawAttributes(message, err, "Wrong compile") + releaseIfSet(cc.registrySem) + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } + if err = json.Unmarshal(specificSchemaVersionBytes, &specificSchemaVersion); err != nil { + setMessageRawAttributes(message, err, "Broken message") + releaseIfSet(cc.registrySem) + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + releaseIfSet(cc.registrySem) + + err = cc.updateIfNewer(specificSchemaVersion) + if err != nil { + setMessageRawAttributes(message, err, "Non number version") + return janitor.MessageTopicPair{Message: message, Topic: cc.Router.Route(janitor.Deadletter, message)}, err + } + + messageTopicPair, err = cc.getMessageTopicPair(janitor.MessageSchemaPair{ + Message: message, + Schema: cc.schema.Specification, + }, encryptedMessageData) + if err != nil { + return messageTopicPair, err + } + return messageTopicPair, nil +} + +func (cc *CentralConsumer) updateIfNewer(versionDetails VersionDetails) error { + newer, err := checkIfNewer(cc.schema.SchemaMetadata.Version, versionDetails.Version) + if err != nil { + return err + } + if newer { + cc.updateVersion(versionDetails) + } + return nil +} + +func setMessageRawAttributes(message janitor.Message, err error, errMessage string) { + message.RawAttributes["deadLetterErrorCategory"] = errMessage + message.RawAttributes["deadLetterErrorReason"] = err.Error() +} + +func acquireIfSet(sem chan struct{}) { + if sem != nil { + sem <- struct{}{} + } +} + +func releaseIfSet(sem chan struct{}) { + if sem != nil { + <-sem + } +} diff --git a/validator/internal/centralconsumer/centralconsumer_test.go b/validator/internal/centralconsumer/centralconsumer_test.go new file mode 100644 index 0000000..908aab9 --- /dev/null +++ b/validator/internal/centralconsumer/centralconsumer_test.go @@ -0,0 +1,185 @@ +package centralconsumer + +import ( + "golang.org/x/net/context" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/publisher" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + localjson "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/json" +) + +func TestTopicsIntoRoutingFunc(t *testing.T) { + topics := Topics{ + Valid: "valid-topic", + InvalidCSV: "deadletter", + InvalidJSON: "deadletter", + Deadletter: "deadletter", + } + + tt := []struct { + name string + isValid janitor.Result + format string + destination string + }{ + {"valid avro", janitor.Valid, avroFormat, topics.Valid}, + {"invalid avro", janitor.Invalid, avroFormat, topics.Deadletter}, + {"deadletter avro", janitor.Deadletter, avroFormat, topics.Deadletter}, + {"missing schema avro", janitor.MissingSchema, avroFormat, topics.Deadletter}, + {"valid protobuf", janitor.Valid, protobufFormat, topics.Valid}, + {"invalid protobuf", janitor.Invalid, protobufFormat, topics.Deadletter}, + {"deadletter protobuf", janitor.Deadletter, protobufFormat, topics.Deadletter}, + {"missing schema protobuf", janitor.MissingSchema, protobufFormat, topics.Deadletter}, + {"valid xml", janitor.Valid, xmlFormat, topics.Valid}, + {"invalid xml", janitor.Invalid, xmlFormat, topics.Deadletter}, + {"deadletter xml", janitor.Deadletter, xmlFormat, topics.Deadletter}, + {"missing schema xml", janitor.MissingSchema, xmlFormat, topics.Deadletter}, + {"valid json", janitor.Valid, jsonFormat, topics.Valid}, + {"invalid json", janitor.Invalid, jsonFormat, topics.InvalidJSON}, + {"deadletter json", janitor.Deadletter, jsonFormat, topics.Deadletter}, + {"missing schema json", janitor.MissingSchema, jsonFormat, topics.InvalidJSON}, + {"valid csv", janitor.Valid, csvFormat, topics.Valid}, + {"invalid csv", janitor.Invalid, csvFormat, topics.InvalidCSV}, + {"deadletter csv", janitor.Deadletter, csvFormat, topics.Deadletter}, + {"missing schema csv", janitor.MissingSchema, csvFormat, topics.InvalidCSV}, + } + + routingFunc := intoRouter(topics) + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + destination := routingFunc.Route(tc.isValid, janitor.Message{Format: tc.format}) + if destination != tc.destination { + t.Errorf("expected and actual destination not the same (%s != %s)", tc.destination, destination) + } + }) + } +} + +func TestOneCCPerTopic(t *testing.T) { + ctx := context.Background() + topics := Topics{ + Valid: "valid", + InvalidCSV: "deadletter", + InvalidJSON: "deadletter", + Deadletter: "deadletter", + } + + _, b, _, _ := runtime.Caller(0) + dir := filepath.Dir(b) + testdataDir := filepath.Join(dir, "testdata") + + data1, err := os.ReadFile(filepath.Join(testdataDir, "data-1.json")) + if err != nil { + t.Fatal(err) + } + data2, err := os.ReadFile(filepath.Join(testdataDir, "data-2.json")) + if err != nil { + t.Fatal(err) + } + data3, err := os.ReadFile(filepath.Join(testdataDir, "data-3.json")) + if err != nil { + t.Fatal(err) + } + schemaSpec1, err := os.ReadFile(filepath.Join(testdataDir, "schema-1.json")) + if err != nil { + t.Fatal(err) + } + schemaSpec2, err := os.ReadFile(filepath.Join(testdataDir, "schema-2.json")) + if err != nil { + t.Fatal(err) + } + schemaSpec3, err := os.ReadFile(filepath.Join(testdataDir, "schema-3.json")) + if err != nil { + t.Fatal(err) + } + + schemaRegistry := registry.NewMock() + schemaRegistry.SetGetResponse("1", "1", schemaSpec1, nil) + schemaRegistry.SetGetResponse("1", "2", schemaSpec2, nil) + schemaRegistry.SetGetResponse("1", "3", schemaSpec3, nil) + + validators := make(map[string]validator.Validator) + validators["json"] = localjson.New() + encryptionKey := "" + + cc, err := New(schemaRegistry, &publisher.MockPublisher{}, validators, topics, Settings{}, nil, RouterFlags{}, Mode(1), + SchemaMetadata{ + ID: "1", + Version: "1", + Format: "json", + }, + encryptionKey) + if err != nil { + t.Fatal(err) + } + + message1 := janitor.Message{ + ID: "", + Key: "", + RawAttributes: map[string]interface{}{}, + Payload: data1, + IngestionTime: time.Time{}, + SchemaID: "1", + Version: "1", + Format: "json", + } + message2 := janitor.Message{ + ID: "", + Key: "", + RawAttributes: map[string]interface{}{}, + Payload: data2, + IngestionTime: time.Time{}, + SchemaID: "1", + Version: "2", + Format: "json", + } + message3 := janitor.Message{ + ID: "", + Key: "", + RawAttributes: map[string]interface{}{}, + Payload: data3, + IngestionTime: time.Time{}, + SchemaID: "1", + Version: "3", + Format: "json", + } + + tt := []struct { + name string + expectedTopic string + version string + message janitor.Message + }{ + {"valid data1 unspecified", "valid", "", message1}, + {"valid data2 specified", "valid", "2", message2}, + //{"invalid data1 unspecified", "deadletter", "", message1}, + {"valid data3 specified", "valid", "3", message3}, + //{"invalid data2 unspecified", "deadletter", "", message2}, + {"invalid data 1 against v2", "deadletter", "2", message1}, + {"invalid data 1 against v3", "deadletter", "3", message1}, + {"invalid data 2 against v3", "deadletter", "3", message2}, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + tc.message.Version = tc.version + messageTopicPair, err := cc.Handle(ctx, tc.message) + if err != nil { + t.Fatal(err) + } + if messageTopicPair.Topic != tc.expectedTopic { + t.Errorf("expected and actual destination not the same (%s != %s)", tc.expectedTopic, messageTopicPair.Topic) + } + }) + } +} diff --git a/validator/internal/centralconsumer/testdata/data-1.json b/validator/internal/centralconsumer/testdata/data-1.json new file mode 100644 index 0000000..c8719b2 --- /dev/null +++ b/validator/internal/centralconsumer/testdata/data-1.json @@ -0,0 +1,3 @@ +{ + "firstName": "John" +} diff --git a/validator/internal/centralconsumer/testdata/data-2.json b/validator/internal/centralconsumer/testdata/data-2.json new file mode 100644 index 0000000..b1227e4 --- /dev/null +++ b/validator/internal/centralconsumer/testdata/data-2.json @@ -0,0 +1,4 @@ +{ + "firstName": "John", + "lastName": "Doe" +} diff --git a/validator/internal/centralconsumer/testdata/data-3.json b/validator/internal/centralconsumer/testdata/data-3.json new file mode 100644 index 0000000..3fe0812 --- /dev/null +++ b/validator/internal/centralconsumer/testdata/data-3.json @@ -0,0 +1,5 @@ +{ + "firstName": "John", + "lastName": "Doe", + "age": 21 +} diff --git a/validator/internal/centralconsumer/testdata/schema-1.json b/validator/internal/centralconsumer/testdata/schema-1.json new file mode 100644 index 0000000..687ae74 --- /dev/null +++ b/validator/internal/centralconsumer/testdata/schema-1.json @@ -0,0 +1,21 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/validator/internal/centralconsumer/testdata/schema-2.json b/validator/internal/centralconsumer/testdata/schema-2.json new file mode 100644 index 0000000..cdb7cfd --- /dev/null +++ b/validator/internal/centralconsumer/testdata/schema-2.json @@ -0,0 +1,22 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "required": ["lastName"], + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/validator/internal/centralconsumer/testdata/schema-3.json b/validator/internal/centralconsumer/testdata/schema-3.json new file mode 100644 index 0000000..4ff6aa2 --- /dev/null +++ b/validator/internal/centralconsumer/testdata/schema-3.json @@ -0,0 +1,22 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "required": ["lastName", "age"], + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/validator/internal/config/centralconsumer.go b/validator/internal/config/centralconsumer.go new file mode 100644 index 0000000..10a3fd4 --- /dev/null +++ b/validator/internal/config/centralconsumer.go @@ -0,0 +1,67 @@ +package config + +import ( + "time" + + "github.com/kkyr/fig" +) + +// CentralConsumer represents all required configuration to run an instance of central consumer. +type CentralConsumer struct { + Producer Producer `toml:"producer"` + Consumer Consumer `toml:"consumer"` + Registry Registry `toml:"registry"` + Topics CentralConsumerTopics `toml:"topics"` + Validators CentralConsumerValidators `toml:"validators"` + ShouldLog CentralConsumerShouldLog `toml:"should_log"` + NumSchemaCollectors int `toml:"num_schema_collectors" default:"-1"` + NumInferrers int `toml:"num_inferrers" default:"-1"` + MetricsLoggingInterval time.Duration `toml:"metrics_logging_interval" default:"5s"` + RunOptions RunOptions `toml:"run_option"` + Mode int `toml:"mode"` + SchemaID string `toml:"schema_id"` + SchemaVersion string `toml:"schema_version"` + SchemaType string `toml:"schema_type"` + Encryption Encryption `toml:"encryption"` +} + +type Encryption struct { + EncryptionKey string `toml:"encryption_key"` +} + +type CentralConsumerTopics struct { + Valid string `toml:"valid" val:"required"` + DeadLetter string `toml:"dead_letter" val:"required"` +} + +type CentralConsumerValidators struct { + EnableAvro bool `toml:"enable_avro"` + EnableCsv bool `toml:"enable_csv"` + EnableJson bool `toml:"enable_json"` + EnableProtobuf bool `toml:"enable_protobuf"` + EnableXml bool `toml:"enable_xml"` + CsvUrl string `toml:"csv_url" val:"required_if=EnableCsv true,omitempty,url"` + CsvTimeoutBase time.Duration `toml:"csv_timeout_base" default:"2s"` + JsonUseAltBackend bool `toml:"json_use_alt_backend"` + JsonCacheSize int `toml:"json_cache_size" default:"100"` + ProtobufFilePath string `toml:"protobuf_file_path" default:"/app/.schemas"` + ProtobufCacheSize int `toml:"protobuf_cache_size" default:"100"` + XmlUrl string `toml:"xml_url" val:"required_if=EnableXml true,omitempty,url"` + XmlTimeoutBase time.Duration `toml:"xml_timeout_base" default:"3s"` +} + +type CentralConsumerShouldLog struct { + MissingSchema bool `toml:"missing_schema"` + Valid bool `toml:"valid"` + DeadLetter bool `toml:"dead_letter"` +} + +// Read loads parameters from configuration file into CentralConsumer struct. +func (cfg *CentralConsumer) Read(filename string) error { + return fig.Load(cfg, fig.File(filename), fig.Tag("toml"), fig.UseEnv("")) +} + +// Validate validates CentralConsumer struct. +func (cfg *CentralConsumer) Validate() error { + return validate(cfg, "CentralConsumer.") +} diff --git a/validator/internal/config/config.go b/validator/internal/config/config.go new file mode 100644 index 0000000..9643bfd --- /dev/null +++ b/validator/internal/config/config.go @@ -0,0 +1,406 @@ +package config + +import ( + "reflect" + "strings" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/go-playground/validator/v10" + "go.uber.org/multierr" +) + +type Producer struct { + Type string `toml:"type" val:"oneof=kafka eventhubs pubsub servicebus jetstream pulsar"` + EncryptionKey string `toml:"encryption_key"` + Kafka KafkaPublisherConfig `toml:"kafka"` + Eventhubs EventhubsPublisherConfig `toml:"eventhubs"` + Pubsub PubsubPublisherConfig `toml:"pubsub"` + Servicebus ServicebusPublisherConfig `toml:"servicebus"` + Jetstream JetstreamPublisherConfig `toml:"jetstream"` + Pulsar PulsarPublisherConfig `toml:"pulsar"` +} + +type KafkaPublisherConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + KrbConfig KrbConfig `toml:"krb_config"` + SaslConfig SaslConfig `toml:"sasl_config"` + Settings KafkaPublisherSettings `toml:"settings"` +} + +type EventhubsPublisherConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + SaslConfig SaslConfig `toml:"sasl_config"` + Settings EventhubsPublisherSettings `toml:"settings"` +} + +type TlsConfig struct { + Enabled bool `toml:"enabled"` + ClientCertFile string `toml:"client_cert_file" val:"required_if=Enabled true,omitempty,file"` + ClientKeyFile string `toml:"client_key_file" val:"required_if=Enabled true,omitempty,file"` + CaCertFile string `toml:"ca_cert_file" val:"required_if=Enabled true,omitempty,file"` + InsecureSkipVerify bool `toml:"insecure_skip_verify"` +} + +type KrbConfig struct { + Enabled bool `toml:"enabled"` + KrbConfigPath string `toml:"krb_config_path"` + KrbKeyTabPath string `toml:"krb_keytab_path"` + KrbRealm string `toml:"krb_realm"` + KrbServiceName string `toml:"krb_service_name"` + KrbUsername string `toml:"krb_username"` +} + +type SaslConfig struct { + User string `toml:"user"` + Password string `toml:"password"` +} + +type KafkaPublisherSettings struct { + BatchSize int `toml:"batch_size" default:"40"` + BatchBytes int64 `toml:"batch_bytes" default:"5242880"` + Linger time.Duration `toml:"linger" default:"10ms"` +} + +type EventhubsPublisherSettings struct { + BatchSize int `toml:"batch_size" default:"40"` + BatchBytes int64 `toml:"batch_bytes" default:"5242880"` + Linger time.Duration `toml:"linger" default:"10ms"` +} + +type PubsubPublisherConfig struct { + ProjectId string `toml:"project_id"` + Settings PubsubPublisherSettings `toml:"settings"` +} + +type PubsubPublisherSettings struct { + DelayThreshold time.Duration `toml:"delay_threshold" default:"50ms"` + CountThreshold int `toml:"count_threshold" default:"50"` + ByteThreshold int `toml:"byte_threshold" default:"52428800"` + NumGoroutines int `toml:"num_goroutines" default:"5"` + Timeout time.Duration `toml:"timeout" default:"15s"` + MaxOutstandingMessages int `toml:"max_outstanding_messages" default:"800"` + MaxOutstandingBytes int `toml:"max_outstanding_bytes" default:"1048576000"` + EnableMessageOrdering bool `toml:"enable_message_ordering"` +} + +type ServicebusPublisherConfig struct { + ConnectionString string `toml:"connection_string"` +} + +type JetstreamPublisherConfig struct { + Url string `toml:"url"` + Settings JetstreamPublisherSettings `toml:"settings"` +} + +type JetstreamPublisherSettings struct { + MaxInflightPending int `toml:"max_inflight_pending" default:"512"` +} + +type PulsarPublisherConfig struct { + ServiceUrl string `toml:"service_url"` + TlsConfig TlsConfig `toml:"tls_config"` +} + +type Consumer struct { + Type string `toml:"type" val:"oneof=kafka eventhubs pubsub servicebus jetstream pulsar"` + Kafka KafkaConsumerConfig `toml:"kafka"` + Eventhubs EventhubsConsumerConfig `toml:"eventhubs"` + Pubsub PubsubConsumerConfig `toml:"pubsub"` + Servicebus ServicebusConsumerConfig `toml:"servicebus"` + Jetstream JetstreamConsumerConfig `toml:"jetstream"` + Pulsar PulsarConsumerConfig `toml:"pulsar"` +} + +type KafkaConsumerConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + KrbConfig KrbConfig `toml:"krb_config"` + Topic string `toml:"topic"` + GroupId string `toml:"group_id"` + Settings KafkaConsumerSettings `toml:"settings"` +} + +type EventhubsConsumerConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + SaslConfig SaslConfig `toml:"sasl_config"` + Topic string `toml:"topic"` + GroupId string `toml:"group_id"` + Settings EventhubsConsumerSettings `toml:"settings"` +} + +type KafkaConsumerSettings struct { + MinBytes int `toml:"min_bytes" default:"100"` + MaxWait time.Duration `toml:"max_wait" default:"5s"` + MaxBytes int `toml:"max_bytes" default:"10485760"` + MaxConcurrentFetches int `toml:"max_concurrent_fetches" default:"3"` + MaxPollRecords int `toml:"max_poll_records" default:"100"` +} + +type EventhubsConsumerSettings struct { + MinBytes int `toml:"min_bytes" default:"100"` + MaxWait time.Duration `toml:"max_wait" default:"5s"` + MaxBytes int `toml:"max_bytes" default:"10485760"` + MaxConcurrentFetches int `toml:"max_concurrent_fetches" default:"3"` + MaxPollRecords int `toml:"max_poll_records" default:"100"` +} + +type PubsubConsumerConfig struct { + ProjectId string `toml:"project_id"` + SubscriptionId string `toml:"subscription_id"` + Settings PubsubConsumerSettings `toml:"settings"` +} + +type PubsubConsumerSettings struct { + MaxExtension time.Duration `toml:"max_extension" default:"30m"` + MaxExtensionPeriod time.Duration `toml:"max_extension_period" default:"3m"` + MaxOutstandingMessages int `toml:"max_outstanding_messages" default:"1000"` + MaxOutstandingBytes int `toml:"max_outstanding_bytes" default:"419430400"` + NumGoroutines int `toml:"num_goroutines" default:"10"` +} + +type ServicebusConsumerConfig struct { + ConnectionString string `toml:"connection_string"` + Topic string `toml:"topic"` + Subscription string `toml:"subscription"` + Settings ServicebusConsumerSettings `toml:"settings"` +} + +type ServicebusConsumerSettings struct { + BatchSize int `toml:"batch_size" default:"100"` +} + +type JetstreamConsumerConfig struct { + Url string `toml:"url"` + Subject string `toml:"subject"` + ConsumerName string `toml:"consumer_name"` + Settings JetstreamConsumerSettings `toml:"settings"` +} + +type JetstreamConsumerSettings struct { + BatchSize int `toml:"batch_size" default:"100"` +} + +type PulsarConsumerConfig struct { + ServiceUrl string `toml:"service_url"` + Topic string `toml:"topic"` + Subscription string `toml:"subscription"` + TlsConfig TlsConfig `toml:"tls_config"` +} + +type Registry struct { + URL string `toml:"url" val:"url"` + Type string `toml:"type" default:"janitor" val:"oneof=janitor apicurio"` + GroupID string `toml:"groupID"` + GetTimeout time.Duration `toml:"get_timeout" default:"4s"` + RegisterTimeout time.Duration `toml:"register_timeout" default:"10s"` + UpdateTimeout time.Duration `toml:"update_timeout" default:"10s"` + InmemCacheSize int `toml:"inmem_cache_size" default:"100"` +} + +type RunOptions struct { + ErrThreshold int64 `toml:"err_threshold" default:"50"` + ErrInterval time.Duration `toml:"err_interval" default:"1m"` + NumRetries int `toml:"num_retries" default:"0"` +} + +// validate validates CentralConsumer or PullerCleaner struct. +func validate(cfg interface{}, prefix string) error { + validate := validator.New() + validate.SetTagName("val") + + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := strings.SplitN(fld.Tag.Get("toml"), ",", 2)[0] + if name == "-" { + return "" + } + return name + }) + + validate.RegisterStructValidation( + ProducerStructLevelValidation, + KafkaPublisherConfig{}, + EventhubsPublisherConfig{}, + PubsubPublisherConfig{}, + ServicebusPublisherConfig{}, + JetstreamPublisherConfig{}, + ) + validate.RegisterStructValidation( + ConsumerStructLevelValidation, + KafkaConsumerConfig{}, + EventhubsConsumerConfig{}, + PubsubConsumerConfig{}, + ServicebusConsumerConfig{}, + JetstreamConsumerConfig{}, + ) + + if err := validate.Struct(cfg); err != nil { + if _, ok := err.(*validator.InvalidValidationError); ok { + return err + } + + var errCombined error + for _, err := range err.(validator.ValidationErrors) { + // Trims prefix ("CentralConsumer." or "PullerCleaner.") + // in order to correspond to TOML key path. + fieldName := strings.TrimPrefix(err.Namespace(), prefix) + + switch err.Tag() { + case "required": + errCombined = multierr.Append(errCombined, errtemplates.RequiredTagFail(fieldName)) + case "required_if": + errCombined = multierr.Append(errCombined, errtemplates.RequiredTagFail(fieldName)) + case "file": + errCombined = multierr.Append(errCombined, errtemplates.FileTagFail(fieldName, err.Value())) + case "url": + errCombined = multierr.Append(errCombined, errtemplates.UrlTagFail(fieldName, err.Value())) + case "oneof": + errCombined = multierr.Append(errCombined, errtemplates.OneofTagFail(fieldName, err.Value())) + case "hostname_port": + errCombined = multierr.Append(errCombined, errtemplates.HostnamePortTagFail(fieldName, err.Value())) + default: + errCombined = multierr.Append(errCombined, err) + } + } + return errCombined + } + return nil +} + +// ProducerStructLevelValidation is a custom validator which validates broker +// structure depending on which type of producer is required. +func ProducerStructLevelValidation(sl validator.StructLevel) { + source := sl.Parent().Interface().(Producer) + + validate := validator.New() + + switch producer := sl.Current().Interface().(type) { + case KafkaPublisherConfig: + if source.Type == "kafka" { + validateMultipleHostnames(validate, sl, producer.Address) + } + case EventhubsPublisherConfig: + if source.Type == "eventhubs" { + validateMultipleHostnames(validate, sl, producer.Address) + if err := validate.Var(producer.SaslConfig, "required"); err != nil { + sl.ReportValidationErrors("sasl_config", "", err.(validator.ValidationErrors)) + } + } + case PubsubPublisherConfig: + if source.Type == "pubsub" { + if err := validate.Var(producer.ProjectId, "required"); err != nil { + sl.ReportValidationErrors("project_id", "", err.(validator.ValidationErrors)) + } + } + case ServicebusPublisherConfig: + if source.Type == "servicebus" { + if err := validate.Var(producer.ConnectionString, "required"); err != nil { + sl.ReportValidationErrors("connection_string", "", err.(validator.ValidationErrors)) + } + } + case JetstreamPublisherConfig: + if source.Type == "jetstream" { + if err := validate.Var(producer.Url, "url"); err != nil { + sl.ReportValidationErrors("url", "", err.(validator.ValidationErrors)) + } + } + case PulsarPublisherConfig: + if source.Type == "pulsar" { + if err := validate.Var(producer.ServiceUrl, "required"); err != nil { + sl.ReportValidationErrors("service_url", "", err.(validator.ValidationErrors)) + } + } + } +} + +// ConsumerStructLevelValidation is a custom validator which validates broker +// structure depending on which type of consumer is required. +func ConsumerStructLevelValidation(sl validator.StructLevel) { + source := sl.Parent().Interface().(Consumer) + + validate := validator.New() + + switch consumer := sl.Current().Interface().(type) { + case KafkaConsumerConfig: + if source.Type == "kafka" { + validateMultipleHostnames(validate, sl, consumer.Address) + if err := validate.Var(consumer.Topic, "required"); err != nil { + sl.ReportValidationErrors("topic", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.GroupId, "required"); err != nil { + sl.ReportValidationErrors("group_id", "", err.(validator.ValidationErrors)) + } + } + case EventhubsConsumerConfig: + if source.Type == "eventhubs" { + validateMultipleHostnames(validate, sl, consumer.Address) + if err := validate.Var(consumer.Topic, "required"); err != nil { + sl.ReportValidationErrors("topic", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.GroupId, "required"); err != nil { + sl.ReportValidationErrors("group_id", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.SaslConfig, "required"); err != nil { + sl.ReportValidationErrors("sasl_config", "", err.(validator.ValidationErrors)) + } + } + case PubsubConsumerConfig: + if source.Type == "pubsub" { + if err := validate.Var(consumer.ProjectId, "required"); err != nil { + sl.ReportValidationErrors("project_id", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.SubscriptionId, "required"); err != nil { + sl.ReportValidationErrors("subscription_id", "", err.(validator.ValidationErrors)) + } + } + case ServicebusConsumerConfig: + if source.Type == "servicebus" { + if err := validate.Var(consumer.ConnectionString, "required"); err != nil { + sl.ReportValidationErrors("connection_string", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.Topic, "required"); err != nil { + sl.ReportValidationErrors("topic", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.Subscription, "required"); err != nil { + sl.ReportValidationErrors("subscription", "", err.(validator.ValidationErrors)) + } + } + case JetstreamConsumerConfig: + if source.Type == "jetstream" { + if err := validate.Var(consumer.Url, "url"); err != nil { + sl.ReportValidationErrors("url", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.Subject, "required"); err != nil { + sl.ReportValidationErrors("subject", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.ConsumerName, "required"); err != nil { + sl.ReportValidationErrors("consumer_name", "", err.(validator.ValidationErrors)) + } + } + case PulsarConsumerConfig: + if source.Type == "pulsar" { + if err := validate.Var(consumer.ServiceUrl, "required"); err != nil { + sl.ReportValidationErrors("service_url", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.Topic, "required"); err != nil { + sl.ReportValidationErrors("topic", "", err.(validator.ValidationErrors)) + } + if err := validate.Var(consumer.Subscription, "required"); err != nil { + sl.ReportValidationErrors("subscription", "", err.(validator.ValidationErrors)) + } + } + } +} + +func validateMultipleHostnames(validate *validator.Validate, sl validator.StructLevel, addresses string) { + splitted := strings.Split(addresses, ",") + + for _, address := range splitted { + if err := validate.Var(strings.Trim(address, " "), "hostname_port"); err != nil { + sl.ReportValidationErrors("address", "", err.(validator.ValidationErrors)) + } + } +} diff --git a/validator/internal/config/logger.go b/validator/internal/config/logger.go new file mode 100644 index 0000000..60a6336 --- /dev/null +++ b/validator/internal/config/logger.go @@ -0,0 +1,40 @@ +package config + +import ( + "fmt" + "github.com/dataphos/lib-logger/logger" + "os" +) + +const ( + LogLevelEnvKey = "LOG_LEVEL_MINIMUM" +) + +const ( + InfoLevel = "info" + WarnLevel = "warn" + ErrorLevel = "error" + DefaultLevel = InfoLevel +) + +var levels = map[string]logger.Level{InfoLevel: logger.LevelInfo, WarnLevel: logger.LevelWarn, ErrorLevel: logger.LevelError} + +// GetLogLevel returns minimum log level based on environment variable. +// Possible levels are info, warn, and error. Defaults to info. +func GetLogLevel() (logger.Level, []string) { + warnings := make([]string, 0, 2) // warnings about log config to be logged after the logger is configured + + levelString := os.Getenv(LogLevelEnvKey) + if levelString == "" { + warnings = append(warnings, fmt.Sprintf("Value for '%s' not set! Using level %s.", LogLevelEnvKey, DefaultLevel)) + return levels[DefaultLevel], warnings + } + + level, supported := levels[levelString] + if supported { + return level, warnings + } else { + warnings = append(warnings, fmt.Sprintf("Value %v for %v is not supported, using level %v.", levelString, LogLevelEnvKey, DefaultLevel)) + return levels[DefaultLevel], warnings + } +} diff --git a/validator/internal/config/pullercleaner.go b/validator/internal/config/pullercleaner.go new file mode 100644 index 0000000..2eef28d --- /dev/null +++ b/validator/internal/config/pullercleaner.go @@ -0,0 +1,50 @@ +package config + +import ( + "time" + + "github.com/kkyr/fig" +) + +// PullerCleaner represents all required configuration to run an instance of puller cleaner. +type PullerCleaner struct { + Producer Producer `toml:"producer"` + Consumer Consumer `toml:"consumer"` + Registry Registry `toml:"registry"` + Topics PullerCleanerTopics `toml:"topics"` + Validators PullerCleanerValidators `toml:"validators"` + ShouldLog PullerCleanerShouldLog `toml:"should_log"` + NumCleaners int `toml:"num_cleaners" default:"10"` + MetricsLoggingInterval time.Duration `toml:"metrics_logging_interval" default:"5s"` + RunOptions RunOptions `toml:"run_options"` +} + +type PullerCleanerTopics struct { + Valid string `toml:"valid" val:"required"` + DeadLetter string `toml:"dead_letter" val:"required"` +} + +type PullerCleanerValidators struct { + EnableCsv bool `toml:"enable_csv"` + EnableJson bool `toml:"enable_json"` + CsvUrl string `toml:"csv_url" val:"required_if=EnableCsv true,omitempty,url"` + CsvTimeoutBase time.Duration `toml:"csv_timeout_base" default:"2s"` + JsonUseAltBackend bool `toml:"json_use_alt_backend"` + JsonCacheSize int `toml:"json_cache_size" default:"100"` + JsonSchemaGenScript string `toml:"json_schema_gen_script" val:"required_if=EnableJson true,omitempty,file"` +} + +type PullerCleanerShouldLog struct { + Valid bool `toml:"valid"` + DeadLetter bool `toml:"dead_letter"` +} + +// Read loads parameters from configuration file into PullerCleaner struct. +func (cfg *PullerCleaner) Read(filename string) error { + return fig.Load(cfg, fig.File(filename), fig.Tag("toml"), fig.UseEnv("")) +} + +// Validate validates PullerCleaner struct. +func (cfg *PullerCleaner) Validate() error { + return validate(cfg, "PullerCleaner.") +} diff --git a/validator/internal/errcodes/errcodes.go b/validator/internal/errcodes/errcodes.go new file mode 100644 index 0000000..53255b6 --- /dev/null +++ b/validator/internal/errcodes/errcodes.go @@ -0,0 +1,68 @@ +// Package errcodes contains all the error codes used by janitor subcomponents. +package errcodes + +const ( + // RegistryInitialization marks unsuccessful initialization of the schema registry dependency. + RegistryInitialization = 100 + + // RegistryUnresponsive marks an unsuccessful attempt at a schema registry operation due to the registry being unresponsive. + RegistryUnresponsive = 101 + + // BrokerInitialization marks unsuccessful initialization of the message broker related external dependencies. + BrokerInitialization = 300 + + // PullingFailure marks failures which occur while pulling messages from some source. + PullingFailure = 301 + + // PublishingFailure marks an unsuccessful attempt at message publishing. + PublishingFailure = 302 + + // BrokerConnClosed marks unsuccessful closing of the connection to the message broker. + BrokerConnClosed = 303 + + // TLSInitialization marks an unsuccessful initialization of a TLS configuration. + TLSInitialization = 304 + + // MetricsServerFailure marks failure of an HTTP server for metrics. + MetricsServerFailure = 305 + + // MetricsServerShutdownFailure marks an unsuccessful shutdown of an HTTP server for metrics. + MetricsServerShutdownFailure = 306 + + // ReadConfigFailure marks unsuccessful read of .yaml file into janitorctl structure. + ReadConfigFailure = 400 + + // ValidateConfigFailure marks unsuccessful validation of janitorctl's exposed fields. + ValidateConfigFailure = 401 + + // ValidationFailure marks an unsuccessful attempt at message validation. + ValidationFailure = 500 + + // InvalidMessage marks messages which were inferred to be invalid. + InvalidMessage = 501 + + // DeadletterMessage marks messages which were inferred to be deadletter. + DeadletterMessage = 502 + + // SchemaGeneration marks an unsuccessful attempt at schema generation. + SchemaGeneration = 600 + + // Initialization is used for general initialization failure of internal structures only, + // initialization failure of external dependencies is marked through other, more descriptive error codes, + Initialization = 900 + + // ParsingMessage marks an unsuccessful attempt at mapping a broker message structure into the one used for processing. + ParsingMessage = 901 + + // UnrecoverableErrorEncountered declares that the system encountered an unrecoverable error. + UnrecoverableErrorEncountered = 902 + + // ErrorThresholdReached declares that the system encountered at least the threshold amount of errors. + ErrorThresholdReached = 903 + + // CompletedWithErrors marks that the process has completed but errors occurred. + CompletedWithErrors = 904 + + // Miscellaneous is used when no other available error code is fitting. + Miscellaneous = 999 +) diff --git a/validator/internal/errtemplates/errtemplates.go b/validator/internal/errtemplates/errtemplates.go new file mode 100644 index 0000000..6efa8ab --- /dev/null +++ b/validator/internal/errtemplates/errtemplates.go @@ -0,0 +1,88 @@ +// Package errtemplates offers convenience functions to standardize error messages and simplify proper error wrapping. +package errtemplates + +import ( + "fmt" + + "github.com/pkg/errors" +) + +const ( + envVariableNotDefinedTemplate = "env variable %s not defined" + parsingEnvVariableFailedTemplate = "parsing env variable %s failed" + unsupportedBrokerTypeTemplate = "unsupported broker type %s" + unsupportedRegistryTypeTemplate = "unsupported registry type %s" + failedTopicInitializationTemplate = "creating reference to %s failed" + attributeNotAStringTemplate = "%s attribute is not a string" + missingAttributeTemplate = "%s attribute is not defined" + mustNotBeEmptyTemplate = "%s must not be empty" + unsupportedMessageFormatTemplate = "unsupported message format: %s" + badHttpStatusCodeTemplate = "bad status code: %d" + httpRequestToUrlFailedTemplate = "%s request to %s failed" +) + +const ( + // ReadingResponseBodyFailed is an error message stating that reading the response body failed. + ReadingResponseBodyFailed = "reading response body failed" + + // UnmarshallingJSONFailed is an error message stating that unmarshalling json failed. + UnmarshallingJSONFailed = "unmarshalling json failed" + + // LoadingTopicsFailed is an error message stating that the target topics couldn't be loaded. + LoadingTopicsFailed = "loading topics failed" +) + +// EnvVariableNotDefined returns an error stating that the given env variable is not defined. +func EnvVariableNotDefined(name string) error { + return errors.Errorf(envVariableNotDefinedTemplate, name) +} + +// ParsingEnvVariableFailed returns a string stating that the given env variable couldn't be parsed properly. +func ParsingEnvVariableFailed(name string) string { + return fmt.Sprintf(parsingEnvVariableFailedTemplate, name) +} + +// UnsupportedBrokerType returns an error stating that the given broker type is not supported. +func UnsupportedBrokerType(name string) error { + return errors.Errorf(unsupportedBrokerTypeTemplate, name) +} + +// UnsupportedRegistryType returns an error stating that the given broker type is not supported. +func UnsupportedRegistryType(name string) error { + return errors.Errorf(unsupportedRegistryTypeTemplate, name) +} + +// CreatingTopicInstanceFailed returns an error stating that topic creation failed. +func CreatingTopicInstanceFailed(name string) string { + return fmt.Sprintf(failedTopicInitializationTemplate, name) +} + +// AttributeNotAString returns an error stating that the given attribute is not a string. +func AttributeNotAString(name string) error { + return errors.Errorf(attributeNotAStringTemplate, name) +} + +// AttributeNotDefined returns an error stating that the given attribute is not defined. +func AttributeNotDefined(name string) error { + return errors.Errorf(missingAttributeTemplate, name) +} + +// MustNotBeEmpty returns an error stating that the given variable must not be empty. +func MustNotBeEmpty(name string) error { + return errors.Errorf(mustNotBeEmptyTemplate, name) +} + +// UnsupportedMessageFormat returns an error stating that the given variable must not be empty. +func UnsupportedMessageFormat(format string) error { + return errors.Errorf(unsupportedMessageFormatTemplate, format) +} + +// BadHttpStatusCode returns an error stating that the given status code wasn't expected. +func BadHttpStatusCode(code int) error { + return errors.Errorf(badHttpStatusCodeTemplate, code) +} + +// HttpRequestToUrlFailed returns a string stating that a http method to the given url has failed. +func HttpRequestToUrlFailed(methodName, url string) string { + return fmt.Sprintf(httpRequestToUrlFailedTemplate, methodName, url) +} diff --git a/validator/internal/errtemplates/valtemplates.go b/validator/internal/errtemplates/valtemplates.go new file mode 100644 index 0000000..b5647a3 --- /dev/null +++ b/validator/internal/errtemplates/valtemplates.go @@ -0,0 +1,31 @@ +package errtemplates + +import "github.com/pkg/errors" + +const ( + requiredTagFailTemplate = "Validation for '%s' failed: can not be blank" + fileTagFailTemplate = "Validation for '%s' failed: '%s' does not exist" + urlTagFailTemplate = "Validation for '%s' failed: '%s' incorrect url" + oneofTagFailTemplate = "Validation for '%s' failed: '%s' is not one of the options" + hostnamePortTagFailTemplate = "Validation for '%s' failed: '%s' incorrect hostname and port" +) + +func RequiredTagFail(cause string) error { + return errors.Errorf(requiredTagFailTemplate, cause) +} + +func FileTagFail(cause string, value interface{}) error { + return errors.Errorf(fileTagFailTemplate, cause, value) +} + +func UrlTagFail(cause string, value interface{}) error { + return errors.Errorf(urlTagFailTemplate, cause, value) +} + +func OneofTagFail(cause string, value interface{}) error { + return errors.Errorf(oneofTagFailTemplate, cause, value) +} + +func HostnamePortTagFail(cause string, value interface{}) error { + return errors.Errorf(hostnamePortTagFailTemplate, cause, value) +} diff --git a/validator/internal/janitor/cleaner.go b/validator/internal/janitor/cleaner.go new file mode 100644 index 0000000..3fde83a --- /dev/null +++ b/validator/internal/janitor/cleaner.go @@ -0,0 +1,140 @@ +package janitor + +import ( + "context" + "sync" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + + "github.com/pkg/errors" +) + +// Cleaner models a process which attempts to find the correct schema metadata for the given Message. +type Cleaner interface { + // Clean takes a Message and tries to generate a new schema for the message, returning a copy of the original Message, + // with the updated AttributeSchemaID and AttributeSchemaVersion properties. + // + // The returned errors are instances of OpError in case the caller needs additional information, like testing OpError.Deadletter. + Clean(context.Context, Message) (Message, error) +} + +// CachingCleaner combines the functionalities of SchemaGenerators, Validators, registry.SchemaRegistry in order +// to perform operations relating to the registration of newly generated schemas. +// +// This implementation of Cleaner tries to validate each new message against the last schema generated for that format. +// This is a heuristic chosen because invalid messages tend to come in bursts, +// so it's sane to assume multiple messages in sequence will have the same schema. +type CachingCleaner struct { + Generators SchemaGenerators + Validators Validators + Registry registry.SchemaRegistry + LastGenerated map[string]SchemaInfo + mu sync.RWMutex +} + +// SchemaInfo holds the schema and the schema registry related info. +type SchemaInfo struct { + Schema []byte + ID string + Version string +} + +// NewCachingCleaner returns a new CachingCleaner. +// +// Because of the caching mechanisms, CachingCleaner is NOT intended for concurrent use. +func NewCachingCleaner(generators SchemaGenerators, validators Validators, schemaRegistry registry.SchemaRegistry) *CachingCleaner { + return &CachingCleaner{ + Generators: generators, + Validators: validators, + Registry: schemaRegistry, + LastGenerated: map[string]SchemaInfo{}, + mu: sync.RWMutex{}, + } +} + +// Clean implements Cleaner. +func (c *CachingCleaner) Clean(ctx context.Context, message Message) (Message, error) { + c.mu.RLock() + lastGeneratedOfFormat, ok := c.LastGenerated[message.Format] + c.mu.RUnlock() + if ok { + isValid, err := c.Validators.Validate(message, lastGeneratedOfFormat.Schema) + if err != nil { + return Message{}, intoOpErr(message.ID, errcodes.ValidationFailure, err) + } + if isValid { + return overwriteSchemaInfo(message, lastGeneratedOfFormat), nil + } + } + + schema, err := c.Generators.Generate(message) + if err != nil { + return Message{}, intoOpErr(message.ID, errcodes.SchemaGeneration, err) + } + id, version, err := c.registerOrUpdateSchema(ctx, schema, message.SchemaID, message.Format) + if err != nil { + return Message{}, intoOpErr(message.ID, errcodes.RegistryUnresponsive, err) + } + + lastGeneratedOfFormat = SchemaInfo{ + Schema: schema, + ID: id, + Version: version, + } + c.mu.Lock() + c.LastGenerated[message.Format] = lastGeneratedOfFormat + c.mu.Unlock() + + return overwriteSchemaInfo(message, lastGeneratedOfFormat), nil +} + +// registerOrUpdateSchema registers the schema if the given id is empty, or updates the schema +// under the given id. +func (c *CachingCleaner) registerOrUpdateSchema(ctx context.Context, schema []byte, id string, schemaType string) (string, string, error) { + if id == "" { + return c.Registry.Register(ctx, schema, schemaType, "none", "none") + } + + version, err := c.Registry.Update(ctx, id, schema) + if err != nil { + return "", "", err + } + + return id, version, nil +} + +// overwriteSchemaInfo returns a new Message, identical to the one given, expect for the fields +// concerning the schema id and version. +func overwriteSchemaInfo(message Message, schemaInfo SchemaInfo) Message { + message.RawAttributes[AttributeSchemaID] = schemaInfo.ID + message.RawAttributes[AttributeSchemaVersion] = schemaInfo.Version + + message.SchemaID = schemaInfo.ID + message.Version = schemaInfo.Version + + return message +} + +// CleanerRouter wraps the Cleaner functionality with a Router. +type CleanerRouter struct { + Cleaner Cleaner + Router Router +} + +// CleanAndReroute attempts to clean the given Message, marking all successfully cleaned messages as Valid. +// +// In case the error returned by Cleaner.Clean evaluates OpError.Deadletter to true, the message is marked as Deadletter. +// All other errors are propagated as is. +func (cr CleanerRouter) CleanAndReroute(ctx context.Context, message Message) (MessageTopicPair, error) { + cleaned, err := cr.Cleaner.Clean(ctx, message) + if err != nil { + var opError *OpError + if errors.As(err, &opError) && opError.Deadletter() { + return MessageTopicPair{Message: message, Topic: cr.Router.Route(Deadletter, message)}, nil + } + return MessageTopicPair{}, err + } + + return MessageTopicPair{Message: cleaned, Topic: cr.Router.Route(Valid, message)}, nil +} diff --git a/validator/internal/janitor/encryption.go b/validator/internal/janitor/encryption.go new file mode 100644 index 0000000..5de9f00 --- /dev/null +++ b/validator/internal/janitor/encryption.go @@ -0,0 +1,58 @@ +package janitor + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" +) + +func Encrypt(plaintext []byte, encryptionKey string) ([]byte, error) { + // NewCipher returns a new cipher.Block in dependence to the key which has to be either 16, 24 or 32 characters long + block, err := aes.NewCipher([]byte(encryptionKey)) + if err != nil { + return nil, err + } + + // GCM instance generation in dependence to the given cipher block + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + // initialization of the nonce size + nonce := make([]byte, gcm.NonceSize()) + // io.ReadFull ensures that the nonce buffer is filled exactly with the specified number of random bytes + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + // return nonce with encrypted message appended + return gcm.Seal(nonce, nonce, plaintext, nil), nil +} + +func Decrypt(encrypted []byte, encryptionKey string) ([]byte, error) { + // NewCipher returns a new cipher.Block in dependence to the key which has to be either 16, 24 or 32 characters long + block, err := aes.NewCipher([]byte(encryptionKey)) + if err != nil { + return nil, err + } + + // gcm instance generation in dependence to the given cipher block + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + // reading the nonce and encrypted + nonceSize := gcm.NonceSize() + var nonce []byte + nonce, encrypted = encrypted[:nonceSize], encrypted[nonceSize:] + + // returns decrypted text except if the key is invalid or the nonce is too short for the cipher + decrypted, err := gcm.Open(nil, nonce, encrypted, nil) + if err != nil { + return nil, err + } + return decrypted, err +} diff --git a/validator/internal/janitor/encryption_test.go b/validator/internal/janitor/encryption_test.go new file mode 100644 index 0000000..3e728a0 --- /dev/null +++ b/validator/internal/janitor/encryption_test.go @@ -0,0 +1,24 @@ +package janitor + +import ( + "bytes" + "testing" +) + +func TestEncryption(t *testing.T) { + message := []byte("Hello, world!") + encryptionKey := "1Pw1EPV7bx8sk0ugotIkRg==" + + encrypted, err := Encrypt(message, encryptionKey) + if err != nil { + t.Fatal(err) + } + decrypted, err := Decrypt(encrypted, encryptionKey) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(message, decrypted) { + t.Fatal("expected and actual message not the same") + } +} diff --git a/validator/internal/janitor/error.go b/validator/internal/janitor/error.go new file mode 100644 index 0000000..dd7d021 --- /dev/null +++ b/validator/internal/janitor/error.go @@ -0,0 +1,51 @@ +package janitor + +import ( + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" +) + +type OpError struct { + MessageID string + Code int + Err error +} + +func (e *OpError) Error() string { + return "processing " + e.MessageID + " failed:" + e.Err.Error() +} + +// Unwrap implements the optional Unwrap error method, which allows for proper usage of errors.Is and errors.As. +func (e *OpError) Unwrap() error { + return e.Err +} + +// Temporary implements the optional Temporary error method, to ensure we don't hide the temporariness of the underlying +// error (in case code checking if this error is temporary doesn't use errors.As but just converts directly). +func (e *OpError) Temporary() bool { + var temporary interface { + Temporary() bool + } + + // errors.As stops at the first error down the chain which implements temporary + // this is important because an unrecoverable error could wrap a recoverable one, so we need the "latest" of the two + if errors.As(e.Err, &temporary) { + return temporary.Temporary() + } + return true +} + +// Deadletter evaluates whether the instance is a Deadletter-type error. +func (e *OpError) Deadletter() bool { + return errors.Is(e.Err, validator.ErrDeadletter) || errors.Is(e.Err, schemagen.ErrDeadletter) +} + +func intoOpErr(messageId string, code int, err error) error { + return &OpError{ + MessageID: messageId, + Code: code, + Err: err, + } +} diff --git a/validator/internal/janitor/error_test.go b/validator/internal/janitor/error_test.go new file mode 100644 index 0000000..ef594bf --- /dev/null +++ b/validator/internal/janitor/error_test.go @@ -0,0 +1,45 @@ +package janitor + +import ( + "syscall" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/pkg/errors" +) + +func TestDeadletter(t *testing.T) { + opError := OpError{ + Err: validator.ErrDeadletter, + } + if !opError.Deadletter() { + t.Fatal("expected Deadletter") + } + + opError.Err = errors.New("oops") + if opError.Deadletter() { + t.Fatal("shouldn't be Deadletter") + } + + opError.Err = schemagen.ErrDeadletter + if !opError.Deadletter() { + t.Fatal("should be Deadletter") + } +} + +func TestTemporary(t *testing.T) { + opError := OpError{ + Err: registry.ErrNotFound, + } + if !opError.Temporary() { + t.Fatal("expected temporary") + } + + opError.Err = syscall.ECONNREFUSED + if opError.Temporary() { + t.Fatal("expected not temporary") + } +} diff --git a/validator/internal/janitor/janitor.go b/validator/internal/janitor/janitor.go new file mode 100644 index 0000000..54c6d97 --- /dev/null +++ b/validator/internal/janitor/janitor.go @@ -0,0 +1,202 @@ +// Package janitor offers a suite of functions for collecting message schemas, +// validating the messages based on the collected schemas, and publishing them to a destination topic. +package janitor + +import ( + "context" + "strings" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/pkg/errors" + + "github.com/dataphos/lib-brokers/pkg/broker" +) + +// Message defines a Message used for processing broker messages. +// Essentially, Message decorates broker messages with additional, extracted information. +type Message struct { + ID string + Key string + RawAttributes map[string]interface{} + Payload []byte + IngestionTime time.Time + SchemaID string + Version string + Format string +} + +const ( + // AttributeSchemaID is one of the keys expected to beÅ‚ found in the attributes field of the message. + // It holds the schema id information concerning the data field of the message + AttributeSchemaID = "schemaId" + + // AttributeSchemaVersion is one of the keys expected to be found in the attributes field of the message, + // It holds the schema version information concerning the data field of the message. + AttributeSchemaVersion = "versionId" + + // AttributeFormat is one of the keys expected to be found in the attributes field of the message. + // It holds the format of the data field of the message. + AttributeFormat = "format" +) + +// MessageSchemaPair wraps a Message with the Schema relating to this Message. +type MessageSchemaPair struct { + Message Message + Schema []byte +} + +// CollectSchema retrieves the schema of the given Message from registry.SchemaRegistry. +// +// If schema retrieval results in registry.ErrNotFound, or Message.SchemaID or Message.Version is an empty string, +// the Message is put on the results channel with MessageSchemaPair.Schema set to nil. +// +// The returned error is an instance of OpError for improved error handling (so that the source of this error is identifiable +// even if combined with other errors). +func CollectSchema(ctx context.Context, message Message, schemaRegistry registry.SchemaRegistry) (MessageSchemaPair, error) { + if message.SchemaID == "" || message.Version == "" { + return MessageSchemaPair{Message: message, Schema: nil}, nil + } + + schema, err := schemaRegistry.Get(ctx, message.SchemaID, message.Version) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + return MessageSchemaPair{Message: message, Schema: nil}, nil + } + return MessageSchemaPair{}, intoOpErr(message.ID, errcodes.RegistryUnresponsive, err) + } + + return MessageSchemaPair{Message: message, Schema: schema}, nil +} + +// Validators is a convenience type for a map containing validator.Validator instances for available message formats. +type Validators map[string]validator.Validator + +// Validate wraps the same function of validator.Validator, by first selecting the proper validator, and then using that +// validator to determine the validity of the given Message.Payload under this schema. +// +// Returns an error if Validators doesn't contain a validator instance for the message format. +func (vs Validators) Validate(message Message, schema []byte) (bool, error) { + v, ok := vs[strings.ToLower(message.Format)] + if !ok { + return false, errtemplates.UnsupportedMessageFormat(message.Format) + } + return v.Validate(message.Payload, schema, message.SchemaID, message.Version) +} + +// SchemaGenerators is a convenience type for a map containing schemagen.Generator instances for available message formats. +type SchemaGenerators map[string]schemagen.Generator + +// Generate wraps the same function of schemagen.Generator, by first selecting the proper generator, and then using that +// generator to construct a schema from the given Parsed instance. +// +// Returns an error if SchemaGenerators doesn't contain a generator instance for the MessageFormat of the given Parsed instance. +func (gs SchemaGenerators) Generate(message Message) ([]byte, error) { + generator, ok := gs[message.Format] + if !ok { + return nil, errtemplates.UnsupportedMessageFormat(message.Format) + } + return generator.Generate(message.Payload) +} + +// Router determines where should the messages be sent to. +type Router interface { + Route(Result, Message) string +} + +// RoutingFunc convenience type to allow functions to implement Router directly. +type RoutingFunc func(Result, Message) string + +func (f RoutingFunc) Route(result Result, message Message) string { + return f(result, message) +} + +// Result holds the four possible outcomes concerning with routing messages to some destination topic: Valid, Invalid, Deadletter and MissingSchema. +// Valid, Invalid and Deadletter are possible outcomes of message validation, while MissingSchema occurs if there is no record +// of the Schema in the Schema Registry. +type Result int + +const ( + Valid Result = iota + Invalid + Deadletter + MissingSchema +) + +// MessageTopicPair wraps a Message with the Topic the Message is supposed to be sent to. +type MessageTopicPair struct { + Message Message + Topic string +} + +// InferDestinationTopic infers the destination topic for the given MessageSchemaPair. +// +// In case MessageSchemaPair.Schema is empty, MissingSchema is passed onto the given Router to +// infer the destination topic. +// +// If the schema exists, the message is validated against it, and the Result is passed onto the Router +// to infer the destination topic. In case validation returns validator.ErrDeadletter, Deadletter is passed onto the Router. +// +// The returned error is an instance of OpError for improved error handling (so that the source of this error is identifiable +// even if combined with other errors). +func InferDestinationTopic(messageSchemaPair MessageSchemaPair, validators Validators, router Router) (MessageTopicPair, error) { + message, schema := messageSchemaPair.Message, messageSchemaPair.Schema + + if len(schema) == 0 { + errMissingSchema := errors.WithMessage(validator.ErrMissingSchema, "") + message.RawAttributes["deadLetterErrorCategory"] = "Schema error" + message.RawAttributes["deadLetterErrorReason"] = errMissingSchema.Error() + return MessageTopicPair{Message: message, Topic: router.Route(MissingSchema, message)}, nil + } + + isValid, err := validators.Validate(message, schema) + if err != nil { + if errors.Is(err, validator.ErrBrokenMessage) { + message.RawAttributes["deadLetterErrorCategory"] = "Broken message" + message.RawAttributes["deadLetterErrorReason"] = err.Error() + return MessageTopicPair{Message: message, Topic: router.Route(Deadletter, message)}, nil + } + if errors.Is(err, validator.ErrWrongCompile) { + message.RawAttributes["deadLetterErrorCategory"] = "Wrong compile" + message.RawAttributes["deadLetterErrorReason"] = err.Error() + return MessageTopicPair{Message: message, Topic: router.Route(Deadletter, message)}, nil + } + if errors.Is(err, validator.ErrFailedValidation) { + message.RawAttributes["deadLetterErrorCategory"] = "Validation error" + message.RawAttributes["deadLetterErrorReason"] = err.Error() + return MessageTopicPair{Message: message, Topic: router.Route(Deadletter, message)}, nil + } + if errors.Is(err, validator.ErrDeadletter) { + return MessageTopicPair{Message: message, Topic: router.Route(Deadletter, message)}, nil + } + return MessageTopicPair{}, intoOpErr(message.ID, errcodes.ValidationFailure, err) + } + + var result Result + if isValid { + result = Valid + } else { + result = Invalid + } + return MessageTopicPair{Message: message, Topic: router.Route(result, message)}, nil +} + +// PublishToTopic publishes a Message to a broker.Topic, returning the relevant OpError in case of failure. +// +// If publishing is successful, the ack func of the underlying broker.Message is called, and the global Metrics are updated. +func PublishToTopic(ctx context.Context, message Message, topic broker.Topic) error { + if err := topic.Publish(ctx, broker.OutboundMessage{ + Key: message.Key, + Data: message.Payload, + Attributes: message.RawAttributes, + }); err != nil { + return intoOpErr(message.ID, errcodes.PublishingFailure, err) + } + + return nil +} diff --git a/validator/internal/janitor/janitor_test.go b/validator/internal/janitor/janitor_test.go new file mode 100644 index 0000000..288e2e3 --- /dev/null +++ b/validator/internal/janitor/janitor_test.go @@ -0,0 +1,167 @@ +package janitor + +import ( + "reflect" + "strconv" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + "github.com/dataphos/lib-streamproc/pkg/streamproc" + + "github.com/pkg/errors" +) + +const ( + AvroFormat = "avro" + CSVFormat = "csv" + JSONFormat = "json" + ProtobufFormat = "protobuf" + XMLFormat = "xml" +) + +func TestParse(t *testing.T) { + brokerMessage := streamproc.Message{ + Data: []byte("this is supposed to be some json data"), + Attributes: map[string]interface{}{ + AttributeSchemaID: "1", + AttributeSchemaVersion: "1", + AttributeFormat: "json", + }, + } + + expected := Message{ + RawAttributes: brokerMessage.Attributes, + Payload: brokerMessage.Data, + SchemaID: "1", + Version: "1", + Format: "json", + } + + actual, err := ParseMessage(brokerMessage) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(expected, actual) { + t.Fatal("expected and actual message not the same") + } +} + +func TestParseError(t *testing.T) { + brokerMessages := []streamproc.Message{ + { + Data: []byte("this is supposed to be some json data"), + Attributes: map[string]interface{}{ + AttributeSchemaID: "1", + AttributeSchemaVersion: "1", + }, + }, + { + Data: []byte("this is supposed to be some json data"), + Attributes: map[string]interface{}{ + AttributeSchemaID: "1", + AttributeSchemaVersion: 1, + "format": "json", + }, + }, + { + Data: []byte("this is supposed to be some json data"), + Attributes: map[string]interface{}{ + AttributeSchemaID: 1, + AttributeSchemaVersion: "1", + "format": "json", + }, + }, + } + + for i, brokerMessage := range brokerMessages { + brokerMessage := brokerMessage + t.Run("parsing failure number "+strconv.Itoa(i), func(t *testing.T) { + _, err := ParseMessage(brokerMessage) + if err == nil { + t.Error("expected error") + } + }) + } +} + +func TestValidatorsValidate(t *testing.T) { + tt := []struct { + name string + message Message + isValid bool + shouldReturnError bool + }{ + { + name: "is valid", + message: Message{ + SchemaID: "1", + Version: "1", + Format: JSONFormat, + Payload: []byte("this is some data to be validates against a Schema, not important for this unit test"), + }, + isValid: true, + shouldReturnError: false, + }, + { + name: "is not valid", + message: Message{ + SchemaID: "1", + Version: "1", + Format: JSONFormat, + Payload: []byte("this is some data to be validates against a Schema, not important for this unit test"), + }, + isValid: false, + shouldReturnError: false, + }, + { + name: "valid, but the format is not supported", + message: Message{ + SchemaID: "1", + Version: "1", + Format: JSONFormat, + Payload: []byte("this is some data to be validates against a Schema, not important for this unit test"), + }, + isValid: true, + shouldReturnError: false, + }, + { + name: "throws error", + message: Message{ + SchemaID: "1", + Version: "1", + Format: JSONFormat, + Payload: []byte("this is some data to be validates against a schema, not important for this unit test"), + }, + isValid: false, + shouldReturnError: true, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + schema := []byte("schema for message validation, not important for this unit test") + validators := Validators(map[string]validator.Validator{ + JSONFormat: validator.Func(func(message, schema []byte, id string, version string) (bool, error) { + if tc.shouldReturnError { + return false, errors.New("test error") + } + return tc.isValid, nil + }), + }) + + isValid, err := validators.Validate(tc.message, schema) + if err != nil { + if !tc.shouldReturnError { + if tc.message.Format == JSONFormat { + t.Error("error occurred but was not expected", err) + } + } + } + if isValid && !tc.isValid { + t.Error("message set to valid but not valid expected") + } + }) + } +} diff --git a/validator/internal/janitor/logging.go b/validator/internal/janitor/logging.go new file mode 100644 index 0000000..ac7b0ac --- /dev/null +++ b/validator/internal/janitor/logging.go @@ -0,0 +1,102 @@ +package janitor + +import ( + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-streamproc/pkg/streamproc" +) + +// RouterFlags defines the logging level of each call to the LoggingRouter. +// +// Intended to be used in LoggingRouter. +type RouterFlags struct { + MissingSchema bool + Valid bool + Invalid bool + Deadletter bool +} + +// LoggingRouter wraps the given LoggingRouter with logging middleware. +func LoggingRouter(log logger.Log, routerFlags RouterFlags, next Router) Router { + return RoutingFunc(func(result Result, message Message) string { + switch { + case routerFlags.MissingSchema && result == MissingSchema: + log.Warnw("message is missing the schema", logger.F{ + "status": "missing schema", + "id": message.ID, + "format": message.Format, + }) + case routerFlags.Valid && result == Valid: + log.Infow("message is classified as valid", logger.F{ + "status": "valid", + "id": message.ID, + "schema_id": message.SchemaID, + "schema_version": message.Version, + "format": message.Format, + }) + case routerFlags.Invalid && result == Invalid: + log.Errorw("message is classified as invalid", errcodes.InvalidMessage, logger.F{ + "status": "invalid", + "id": message.ID, + "schema_id": message.SchemaID, + "schema_version": message.Version, + "format": message.Format, + }) + case routerFlags.Deadletter && result == Deadletter: + log.Errorw("message is classified as Deadletter", errcodes.DeadletterMessage, logger.F{ + "status": "Deadletter", + "id": message.ID, + "schema_id": message.SchemaID, + "schema_version": message.Version, + "format": message.Format, + }) + } + + return next.Route(result, message) + }) +} + +type ShouldReturnFlowControl struct { + OnPullErr streamproc.FlowControl + OnProcessErr streamproc.FlowControl + OnUnrecoverable streamproc.FlowControl + OnThresholdReached streamproc.FlowControl +} + +// LoggingCallbacks returns a slice of streamproc.RunOptions, configuring streamproc.RunOptions to log all events with the agreed error codes. +func LoggingCallbacks(log logger.Log, control ShouldReturnFlowControl) []streamproc.RunOption { + onPullErr := func(err error) streamproc.FlowControl { + log.Error(err.Error(), errcodes.PullingFailure) + return control.OnPullErr + } + + OnProcessErr := func(err error) streamproc.FlowControl { + code := errcodes.Miscellaneous + opError := &OpError{} + if errors.As(err, &opError) { + code = opError.Code + } + log.Error(err.Error(), uint64(code)) + + return control.OnProcessErr + } + + onUnrecoverable := func(err error) streamproc.FlowControl { + log.Error(errors.Wrap(err, "unrecoverable error encountered").Error(), errcodes.UnrecoverableErrorEncountered) + return control.OnUnrecoverable + } + + onThresholdReached := func(err error, count, threshold int64) streamproc.FlowControl { + log.Error(errors.Errorf("error threshold reached (%d >= %d)", count, threshold).Error(), errcodes.ErrorThresholdReached) + return control.OnThresholdReached + } + + return []streamproc.RunOption{ + streamproc.OnPullErr(onPullErr), + streamproc.OnProcessErr(OnProcessErr), + streamproc.OnUnrecoverable(onUnrecoverable), + streamproc.OnThresholdReached(onThresholdReached), + } +} diff --git a/validator/internal/janitor/logging_test.go b/validator/internal/janitor/logging_test.go new file mode 100644 index 0000000..af8d838 --- /dev/null +++ b/validator/internal/janitor/logging_test.go @@ -0,0 +1,80 @@ +package janitor + +import ( + "testing" + + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-logger/standardlogger" +) + +func TestRoutingFunc(t *testing.T) { + tt := []struct { + name string + routerFlags RouterFlags + result Result + }{ + { + "valid is propagated", + RouterFlags{ + MissingSchema: true, + Valid: true, + Deadletter: true, + }, + Valid, + }, + { + "invalid is propagated", + RouterFlags{ + MissingSchema: true, + Valid: true, + Deadletter: true, + }, + Invalid, + }, + { + "invalid is propagated", + RouterFlags{ + MissingSchema: true, + Valid: true, + Deadletter: true, + }, + MissingSchema, + }, + { + "Deadletter is propagated", + RouterFlags{ + MissingSchema: true, + Valid: true, + Deadletter: true, + }, + Deadletter, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + destination := "some topic" + var called int + next := RoutingFunc(func(result Result, message Message) string { + if result != tc.result { + t.Fatal("wrong result propagated") + } + called++ + + return destination + }) + + r := LoggingRouter(standardlogger.New(logger.L{}), tc.routerFlags, next) + + actual := r.Route(tc.result, Message{}) + if actual != destination { + t.Error("expected and actual not the same") + } + + if called != 1 { + t.Error("not propagated correctly") + } + }) + } +} diff --git a/validator/internal/janitor/metrics.go b/validator/internal/janitor/metrics.go new file mode 100644 index 0000000..788830c --- /dev/null +++ b/validator/internal/janitor/metrics.go @@ -0,0 +1,104 @@ +package janitor + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + publishCountProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "published_messages_total", + Help: "The total number of published messages", + }) + bytesProcessedProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "processed_bytes_total", + Help: "The total number of processed bytes", + }) + processingTimesProm = promauto.NewSummary(prometheus.SummaryOpts{ + Namespace: "schema_registry", + Name: "processing_times_milliseconds", + Help: "Processing times of published messages in milliseconds", + MaxAge: 5 * time.Minute, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }) +) + +// UpdateSuccessMetrics updates Prometheus metrics: publishCountProm, bytesProcessedProm, and processingTimesProm. +func UpdateSuccessMetrics(messages ...Message) { + publishCountProm.Add(float64(len(messages))) + + for _, message := range messages { + messageProcessingTime := time.Since(message.IngestionTime).Milliseconds() + processingTimesProm.Observe(float64(messageProcessingTime)) + + bytesProcessedProm.Add(float64(len(message.Payload))) + } +} + +var ( + publishDLCountProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "published_dead_letter_messages_total", + Help: "The total number of published dead letter messages", + }) + bytesDLProcessedProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "processed_dead_letter_bytes_total", + Help: "The total number of processed dead letter bytes", + }) + processingDLTimesProm = promauto.NewSummary(prometheus.SummaryOpts{ + Namespace: "schema_registry", + Name: "processing_dead_letter_times_milliseconds", + Help: "Processing times of published dead letter messages in milliseconds", + MaxAge: 5 * time.Minute, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }) +) + +// UpdateSuccessDLMetrics updates Prometheus metrics: publishDLCountProm, bytesDLProcessedProm, and processingDLTimesProm. +func UpdateSuccessDLMetrics(messages ...Message) { + publishDLCountProm.Add(float64(len(messages))) + + for _, message := range messages { + messageProcessingTime := time.Since(message.IngestionTime).Milliseconds() + processingDLTimesProm.Observe(float64(messageProcessingTime)) + + bytesDLProcessedProm.Add(float64(len(message.Payload))) + } +} + +var ( + nackCountProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "nack_messages_total", + Help: "The total number of nack messages", + }) + nackBytesProcessedProm = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "nack_processed_bytes_total", + Help: "The total number of nack processed bytes", + }) + nackProcessingTimesProm = promauto.NewSummary(prometheus.SummaryOpts{ + Namespace: "schema_registry", + Name: "nack_processing_times_milliseconds", + Help: "Processing times of nack messages in milliseconds", + MaxAge: 5 * time.Minute, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }) +) + +// UpdateFailureMetrics updates Prometheus metrics: nackCountProm, nackBytesProcessedProm, and nackProcessingTimesProm. +func UpdateFailureMetrics(messages ...Message) { + nackCountProm.Add(float64(len(messages))) + + for _, message := range messages { + msgNackProcessingTime := time.Since(message.IngestionTime).Milliseconds() + nackProcessingTimesProm.Observe(float64(msgNackProcessingTime)) + + nackBytesProcessedProm.Add(float64(len(message.Payload))) + } +} diff --git a/validator/internal/janitor/parse.go b/validator/internal/janitor/parse.go new file mode 100644 index 0000000..bee5665 --- /dev/null +++ b/validator/internal/janitor/parse.go @@ -0,0 +1,75 @@ +package janitor + +import ( + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/lib-streamproc/pkg/streamproc" +) + +// ParseMessage parses a given broker.Message into Message, by setting Message.Payload to the value of the data field of the given +// broker.Message, and extracting the other fields from the attributes field. +// +// ParseMessage checks if the attributes field contains the following keys: AttributeSchemaID, AttributeSchemaVersion and AttributeFormat. +// If AttributeSchemaID or AttributeSchemaVersion are present, then it is assumed they are strings, returning an error otherwise. +// The AttributeFormat key must be present and must be a non-empty string. +func ParseMessage(message streamproc.Message) (Message, error) { + parsed := Message{ + ID: message.ID, + Key: message.Key, + Payload: message.Data, + RawAttributes: message.Attributes, + IngestionTime: message.IngestionTime, + } + + attributes, err := ExtractAttributes(message.Attributes) + if err != nil { + return parsed, err + } + parsed.SchemaID = attributes.SchemaId + parsed.Version = attributes.SchemaVersion + parsed.Format = attributes.Format + + return parsed, nil +} + +type Attributes struct { + SchemaId string + SchemaVersion string + Format string +} + +func ExtractAttributes(raw map[string]interface{}) (Attributes, error) { + var schemaIDStr, versionStr, formatStr string + + schemaID, ok := raw[AttributeSchemaID] + if ok { + schemaIDStr, ok = schemaID.(string) + if !ok { + return Attributes{}, errtemplates.AttributeNotAString(AttributeSchemaID) + } + } + + version, ok := raw[AttributeSchemaVersion] + if ok { + versionStr, ok = version.(string) + if !ok { + return Attributes{}, errtemplates.AttributeNotAString(AttributeSchemaVersion) + } + } + format, ok := raw[AttributeFormat] + if !ok { + return Attributes{}, errtemplates.AttributeNotDefined(AttributeFormat) + } + formatStr, ok = format.(string) + if !ok { + return Attributes{}, errtemplates.AttributeNotAString(AttributeFormat) + } + if formatStr == "" { + return Attributes{}, errtemplates.MustNotBeEmpty(AttributeFormat) + } + + return Attributes{ + SchemaId: schemaIDStr, + SchemaVersion: versionStr, + Format: formatStr, + }, nil +} diff --git a/validator/internal/janitor/processor.go b/validator/internal/janitor/processor.go new file mode 100644 index 0000000..a5d54ac --- /dev/null +++ b/validator/internal/janitor/processor.go @@ -0,0 +1,225 @@ +package janitor + +import ( + "context" + + "golang.org/x/sync/errgroup" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/lib-batchproc/pkg/batchproc" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-streamproc/pkg/streamproc" +) + +type Processor struct { + Handler Handler + Topics map[string]broker.Topic + Deadletter string + log logger.Log +} + +type Handler interface { + Handle(context.Context, Message) (MessageTopicPair, error) +} + +func NewProcessor(handler Handler, topics map[string]broker.Topic, deadletter string, log logger.Log) *Processor { + return &Processor{ + Handler: handler, + Topics: topics, + Deadletter: deadletter, + log: log, + } +} + +// HandleMessage processes the given streamproc.Message by first attempting to parse it, and then calling the +// underlying Handler. +func (p *Processor) HandleMessage(ctx context.Context, message streamproc.Message) error { + // The received ctx isn't used because the whole process is assumed to take up very little time. + // Because of this, it's preferred to exit "cleanly" instead of stopping mid-process, which might + // have side effects. + ctx = context.Background() //nolint:staticcheck (ignored the rule SA4009 in .golangci.yaml) + + parsed, ok, err := p.parseOrSendToDeadletter(ctx, message) + if err != nil { + UpdateFailureMetrics(parsed) + return err + } + if ok { + messageTopicPair, err := p.Handler.Handle(ctx, parsed) + if err != nil { + UpdateFailureMetrics(parsed) + return err + } + if err = PublishToTopic(ctx, messageTopicPair.Message, p.Topics[messageTopicPair.Topic]); err != nil { + UpdateFailureMetrics(messageTopicPair.Message) + return err + } + // if message is invalid (sent to DL), update DL metrics + if messageTopicPair.Topic == p.Deadletter { + UpdateSuccessDLMetrics(parsed) + } + } + UpdateSuccessMetrics(parsed) + return nil +} + +func (p *Processor) parseOrSendToDeadletter(ctx context.Context, message streamproc.Message) (Message, bool, error) { + parsed, err := ParseMessage(message) + if err != nil { + p.log.Errorw(err.Error(), errcodes.ParsingMessage, logger.F{ + "id": message.ID, + }) + parsed.RawAttributes["deadLetterErrorCategory"] = "Parsing error" + parsed.RawAttributes["deadLetterErrorReason"] = err.Error() + if err = PublishToTopic(ctx, parsed, p.Topics[p.Deadletter]); err != nil { + return Message{}, false, err + } + UpdateSuccessDLMetrics(parsed) + return Message{}, false, nil + } + return parsed, true, nil +} + +// HandleBatch processes the given slice of streamproc.Message instances, by calling the underlying Handler, +// on each streamproc.Message concurrently. +func (p *Processor) HandleBatch(ctx context.Context, batch []streamproc.Message) error { + // The received ctx isn't used because the whole process is assumed to take up very little time. + // Because of this, it's preferred to exit "cleanly" instead of stopping mid-process, which might + // have side effects. + ctx = context.Background() //nolint:staticcheck + + batchSize := len(batch) + messageTopicPairs := make([]*MessageTopicPair, batchSize) + failed := make([]bool, batchSize) + + // The batch is processed in chunks (and not one per goroutine), since the Handler is assumed to be mostly CPU bound. + if err := batchproc.Parallel(ctx, batchSize, func(ctx context.Context, lb int, ub int) error { + for i := lb; i < ub; i++ { + parsed, ok, err := p.parseOrSendToDeadletter(ctx, batch[i]) + if err != nil { + UpdateFailureMetrics(parsed) + failed[i] = true + return err + } + if ok { + messageTopicPair, err := p.Handler.Handle(ctx, parsed) + if err != nil { + UpdateFailureMetrics(parsed) + failed[i] = true + return err + } + messageTopicPairs[i] = &messageTopicPair + } + } + return nil + }); err != nil { + return &streamproc.PartiallyProcessedBatchError{ + Failed: indicesWhereTrue(failed), + Err: err, + } + } + + // Publish order needs to be preserved if messages have the same key, so we partition the processed messages before publishing them. + // That way, we can still utilize concurrency in the general case (it's unlikely for multiple messages in a batch to actually share the key), + // but still ensure ordering on the target topics when it matters. + partitions := groupByKey(messageTopicPairs) + // The empty string key implies no key is defined, so we don't care about order for this partition. + keyless := partitions[""] + delete(partitions, "") + + eg, ctx := errgroup.WithContext(ctx) + + // Required extra check for the number of keyless messages to avoid division by zero in batchproc.Process(). + if numKeyless := len(keyless); numKeyless != 0 { + eg.Go(func() error { + return batchproc.Process(ctx, numKeyless, numKeyless, func(ctx context.Context, i int, _ int) error { + messageTopicPair := messageTopicPairs[keyless[i]] + if err := PublishToTopic(ctx, messageTopicPair.Message, p.Topics[messageTopicPair.Topic]); err != nil { + UpdateFailureMetrics(messageTopicPair.Message) + failed[keyless[i]] = true + return err + } + // if message is invalid (sent to DL), update DL metrics + if messageTopicPair.Topic == p.Deadletter { + UpdateSuccessDLMetrics(messageTopicPair.Message) + } + UpdateSuccessMetrics(messageTopicPair.Message) + return nil + }) + }) + } + + for _, partition := range partitions { + partition := partition + eg.Go(func() error { + // Publishing needs to be sequential on a per-partition basis. + for _, index := range partition { + messageTopicPair := messageTopicPairs[index] + if err := PublishToTopic(ctx, messageTopicPair.Message, p.Topics[messageTopicPair.Topic]); err != nil { + UpdateFailureMetrics(messageTopicPair.Message) + failed[index] = true + return err + } + // if message is invalid (sent to DL), update DL metrics + if messageTopicPair.Topic == p.Deadletter { + UpdateSuccessDLMetrics(messageTopicPair.Message) + } + UpdateSuccessMetrics(messageTopicPair.Message) + } + return nil + }) + } + + if err := eg.Wait(); err != nil { + return &streamproc.PartiallyProcessedBatchError{ + Failed: indicesWhereTrue(failed), + Err: err, + } + } + return nil +} + +// indicesWhereTrue collects the indices of those elements in the bool slice which are set to true. +func indicesWhereTrue(bools []bool) []int { + var indices []int + for i, isFailed := range bools { + if isFailed { + indices = append(indices, i) + } + } + return indices +} + +// groupByKey groups the given slice of *MessageTopicPair by the contents of the Message.Key, returning +// a map which for every unique key, holds the indices of all elements which share that key. +func groupByKey(messageTopicPairs []*MessageTopicPair) map[string][]int { + groups := make(map[string][]int) + for i, messageTopicPair := range messageTopicPairs { + if messageTopicPair == nil { + continue + } + groups[messageTopicPair.Message.Key] = append(groups[messageTopicPair.Message.Key], i) + } + return groups +} + +// AsReceiverExecutor returns a new streamproc.ReceiverExecutor, referencing this instance. +func (p *Processor) AsReceiverExecutor() *streamproc.ReceiverExecutor { + return streamproc.NewReceiverExecutor(p) +} + +// AsBatchedReceiverExecutor returns a new streamproc.BatchedReceiverExecutor, referencing this instance. +func (p *Processor) AsBatchedReceiverExecutor() *streamproc.BatchedReceiverExecutor { + return streamproc.NewBatchedReceiverExecutor(p) +} + +// AsRecordExecutor returns a new streamproc.RecordExecutor, referencing this instance. +func (p *Processor) AsRecordExecutor() *streamproc.RecordExecutor { + return streamproc.NewRecordExecutor(p) +} + +// AsBatchExecutor returns a new streamproc.BatchExecutor, referencing this instance. +func (p *Processor) AsBatchExecutor() *streamproc.BatchExecutor { + return streamproc.NewBatchExecutor(p) +} diff --git a/validator/internal/janitorctl/init.go b/validator/internal/janitorctl/init.go new file mode 100644 index 0000000..d804a86 --- /dev/null +++ b/validator/internal/janitorctl/init.go @@ -0,0 +1,747 @@ +package janitorctl + +import ( + "context" + "crypto/tls" + "net/http" + "runtime" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/config" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry/apicuriosr" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry/janitorsr" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + csvgen "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen/csv" + jsongen "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen/json" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/avro" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/csv" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/json" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/protobuf" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/xml" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-brokers/pkg/broker/jetstream" + "github.com/dataphos/lib-brokers/pkg/broker/kafka" + "github.com/dataphos/lib-brokers/pkg/broker/pubsub" + "github.com/dataphos/lib-brokers/pkg/broker/pulsar" + "github.com/dataphos/lib-brokers/pkg/broker/servicebus" + "github.com/dataphos/lib-brokers/pkg/brokerutil" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-streamproc/pkg/streamproc" +) + +// initializeSchemaRegistry gets the janitor implementation of a schema registry, optionally decorating it with an in-memory lru cache +// if the appropriate env variable is set. +func initializeSchemaRegistry(ctx context.Context, log logger.Log, cfg *config.Registry) (registry.SchemaRegistry, error) { + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + var sr registry.SchemaRegistry + var err error + switch cfg.Type { + case "apicurio": + sr, err = apicuriosr.New( + ctx, + cfg.URL, + apicuriosr.TimeoutSettings{ + GetTimeout: cfg.GetTimeout, + RegisterTimeout: cfg.RegisterTimeout, + UpdateTimeout: cfg.UpdateTimeout, + }, + cfg.GroupID, + ) + case "janitor": + sr, err = janitorsr.New( + ctx, + cfg.URL, + janitorsr.TimeoutSettings{ + GetTimeout: cfg.GetTimeout, + RegisterTimeout: cfg.RegisterTimeout, + UpdateTimeout: cfg.UpdateTimeout, + }, + cfg.GroupID, + ) + default: + sr, err = nil, errtemplates.UnsupportedRegistryType(cfg.Type) + } + if err != nil { + return nil, err + } + + cacheSize := cfg.InmemCacheSize + if cacheSize > 0 { + log.Infow("using in-memory cache for schema registry", logger.F{ + "cache_size": cacheSize, + }) + return registry.WithCache(sr, cacheSize) + } + + return sr, err +} + +// initKafkaPublisher initializes an instance of Kafka Publisher +func initKafkaPublisher(ctx context.Context, cfg *config.Producer) (broker.Publisher, error) { + var tlsConfig *tls.Config + var krbConfig *kafka.KerberosConfig + if cfg.Kafka.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Kafka.TlsConfig.ClientCertFile, cfg.Kafka.TlsConfig.ClientKeyFile, cfg.Kafka.TlsConfig.CaCertFile) + tlsConfig.InsecureSkipVerify = cfg.Kafka.TlsConfig.InsecureSkipVerify + if err != nil { + return nil, err + } + } + + if cfg.Kafka.KrbConfig.Enabled { + krbConfig = &kafka.KerberosConfig{ + KeyTabPath: cfg.Kafka.KrbConfig.KrbKeyTabPath, + ConfigPath: cfg.Kafka.KrbConfig.KrbConfigPath, + Realm: cfg.Kafka.KrbConfig.KrbRealm, + Service: cfg.Kafka.KrbConfig.KrbServiceName, + Username: cfg.Kafka.KrbConfig.KrbUsername, + } + } + + return kafka.NewPublisher( + ctx, + kafka.ProducerConfig{ + BrokerAddr: cfg.Kafka.Address, + TLS: tlsConfig, + Kerberos: krbConfig, + Prometheus: &kafka.PrometheusConfig{ + Namespace: "publisher", + Registerer: prometheus.DefaultRegisterer, + Gatherer: prometheus.DefaultGatherer, + }, + }, kafka.ProducerSettings{ + BatchSize: cfg.Kafka.Settings.BatchSize, + BatchBytes: cfg.Kafka.Settings.BatchBytes, + Linger: cfg.Kafka.Settings.Linger, + }, + ) +} + +// initEventHubsPublisher initializes an instance of Kafka Publisher +func initEventHubsPublisher(ctx context.Context, cfg *config.Producer) (broker.Publisher, error) { + var tlsConfig *tls.Config + saslConfig := &kafka.PlainSASLConfig{ + User: cfg.Eventhubs.SaslConfig.User, + Pass: cfg.Eventhubs.SaslConfig.Password, + } + + if cfg.Eventhubs.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Eventhubs.TlsConfig.ClientCertFile, cfg.Eventhubs.TlsConfig.ClientKeyFile, cfg.Eventhubs.TlsConfig.CaCertFile) + tlsConfig.InsecureSkipVerify = cfg.Eventhubs.TlsConfig.InsecureSkipVerify + if err != nil { + return nil, err + } + } else { + // TLS has to be set when using eventhubs. In case it is not set, we need to skip certificate verification + tlsConfig = &tls.Config{ + InsecureSkipVerify: cfg.Eventhubs.TlsConfig.InsecureSkipVerify, + } + } + return kafka.NewPublisher( + ctx, + kafka.ProducerConfig{ + BrokerAddr: cfg.Eventhubs.Address, + Prometheus: &kafka.PrometheusConfig{ + Namespace: "publisher", + Registerer: prometheus.DefaultRegisterer, + Gatherer: prometheus.DefaultGatherer, + }, + TLS: tlsConfig, + PlainSASL: saslConfig, + DisableCompression: true, + }, kafka.ProducerSettings{ + BatchSize: cfg.Eventhubs.Settings.BatchSize, + BatchBytes: cfg.Eventhubs.Settings.BatchBytes, + Linger: cfg.Eventhubs.Settings.Linger, + }, + ) +} + +// initPubSubPublisher initializes an instance of PubSub Publisher +func initPubSubPublisher(ctx context.Context, cfg *config.Producer) (broker.Publisher, error) { + return pubsub.NewPublisher( + ctx, + pubsub.PublisherConfig{ + ProjectID: cfg.Pubsub.ProjectId, + }, + pubsub.PublishSettings{ + DelayThreshold: cfg.Pubsub.Settings.DelayThreshold, + CountThreshold: cfg.Pubsub.Settings.CountThreshold, + ByteThreshold: cfg.Pubsub.Settings.ByteThreshold, + NumGoroutines: cfg.Pubsub.Settings.NumGoroutines, + Timeout: cfg.Pubsub.Settings.Timeout, + MaxOutstandingMessages: cfg.Pubsub.Settings.MaxOutstandingMessages, + MaxOutstandingBytes: cfg.Pubsub.Settings.MaxOutstandingBytes, + EnableMessageOrdering: cfg.Pubsub.Settings.EnableMessageOrdering, + }, + ) +} + +// initServiceBusPublisher initializes an instance of ServiceBus Publisher +func initServiceBusPublisher(cfg *config.Producer) (broker.Publisher, error) { + return servicebus.NewPublisher(cfg.Servicebus.ConnectionString) +} + +// initJetStreamPublisher initializes an instance of JetStream Publisher +func initJetStreamPublisher(ctx context.Context, cfg *config.Producer) (broker.Publisher, error) { + return jetstream.NewPublisher( + ctx, + cfg.Jetstream.Url, + jetstream.PublisherSettings{ + MaxPending: cfg.Jetstream.Settings.MaxInflightPending, + }, + ) +} + +// initPulsarPublisher initializes an instance of Pulsar Publisher +func initPulsarPublisher(cfg *config.Producer) (broker.Publisher, error) { + var tlsConfig *tls.Config + if cfg.Kafka.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Pulsar.TlsConfig.ClientCertFile, cfg.Pulsar.TlsConfig.ClientKeyFile, cfg.Pulsar.TlsConfig.CaCertFile) + if err != nil { + return nil, err + } + } + + return pulsar.NewPublisher( + pulsar.PublisherConfig{ + ServiceURL: cfg.Pulsar.ServiceUrl, + TLSConfig: tlsConfig, + }, + pulsar.DefaultPublisherSettings, + ) +} + +// initializePublisher selects and initializes an instance of broker.Publisher, depending on the value based through the appropriate +// environment variable. +func initializePublisher(ctx context.Context, cfg *config.Producer) (broker.Publisher, error) { + switch cfg.Type { + case "kafka": + return initKafkaPublisher(ctx, cfg) + case "eventhubs": + return initEventHubsPublisher(ctx, cfg) + case "pubsub": + return initPubSubPublisher(ctx, cfg) + case "servicebus": + return initServiceBusPublisher(cfg) + case "jetstream": + return initJetStreamPublisher(ctx, cfg) + case "pulsar": + return initPulsarPublisher(cfg) + + default: + return nil, errtemplates.UnsupportedBrokerType(cfg.Type) + } +} + +// initializeValidators initializes a map of validator.Validator, +// depending on which validators are enabled. +func initializeValidatorsForCentralConsumer(ctx context.Context, cfg *config.CentralConsumer) (map[string]validator.Validator, error) { + validators := make(map[string]validator.Validator) + + if cfg.Validators.EnableAvro { + validators["avro"] = avro.New() + } + + if cfg.Validators.EnableCsv { + csvValidator, err := csv.New(ctx, cfg.Validators.CsvUrl, cfg.Validators.CsvTimeoutBase) + if err != nil { + return nil, errors.Wrap(err, "couldn't initialize csv validator") + } + validators["csv"] = csvValidator + } + + if cfg.Validators.EnableJson { + if cfg.Validators.JsonCacheSize > 0 { + if cfg.Validators.JsonUseAltBackend { + validators["json"] = json.NewCachedGoJsonSchemaValidator(cfg.Validators.JsonCacheSize) + } else { + validators["json"] = json.NewCached(cfg.Validators.JsonCacheSize) + } + } else { + if cfg.Validators.JsonUseAltBackend { + validators["json"] = json.NewGoJsonSchemaValidator() + } else { + validators["json"] = json.New() + } + } + } + + if cfg.Validators.EnableProtobuf { + protobufValidator, err := protobuf.New(cfg.Validators.ProtobufFilePath, cfg.Validators.ProtobufCacheSize) + if err != nil { + return nil, errors.Wrap(err, "couldn't initialize protobuf validator") + } + validators["protobuf"] = protobufValidator + } + + if cfg.Validators.EnableXml { + xmlValidator, err := xml.New(ctx, cfg.Validators.XmlUrl, cfg.Validators.XmlTimeoutBase) + if err != nil { + return nil, errors.Wrap(err, "couldn't initialize xml validator") + } + validators["xml"] = xmlValidator + } + + return validators, nil +} + +// initializeValidators initializes a map of validator.Validator, +// depending on which validators are enabled. +func initializeValidatorsForPullerCleaner(ctx context.Context, cfg *config.PullerCleaner) (map[string]validator.Validator, error) { + validators := make(map[string]validator.Validator) + + if cfg.Validators.EnableCsv { + csvValidator, err := csv.New(ctx, cfg.Validators.CsvUrl, cfg.Validators.CsvTimeoutBase) + if err != nil { + return nil, errors.Wrap(err, "couldn't initialize csv validator") + } + validators["csv"] = csvValidator + } + + if cfg.Validators.EnableJson { + if cfg.Validators.JsonCacheSize > 0 { + if cfg.Validators.JsonUseAltBackend { + validators["json"] = json.NewCachedGoJsonSchemaValidator(cfg.Validators.JsonCacheSize) + } else { + validators["json"] = json.NewCached(cfg.Validators.JsonCacheSize) + } + } else { + if cfg.Validators.JsonUseAltBackend { + validators["json"] = json.NewGoJsonSchemaValidator() + } else { + validators["json"] = json.New() + } + } + } + + return validators, nil +} + +// initializeGenerators initializes a map of enabled schemagen.Generator for puller cleaner. +func initializeGenerators(cfg *config.PullerCleaner) (map[string]schemagen.Generator, error) { + generators := make(map[string]schemagen.Generator) + + if cfg.Validators.EnableCsv { + generators["csv"] = csvgen.New() + } + + if cfg.Validators.EnableJson { + if cfg.Validators.JsonSchemaGenScript == "" { + return nil, errors.New("jsonSchemaGenScript not defined") + } + generators["json"] = jsongen.New(cfg.Validators.JsonSchemaGenScript) + } + + return generators, nil +} + +// initKafkaConsumer initializes a Kafka consumer component +func initKafkaConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + var tlsConfig *tls.Config + var krbConfig *kafka.KerberosConfig + if cfg.Kafka.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Kafka.TlsConfig.ClientCertFile, cfg.Kafka.TlsConfig.ClientKeyFile, cfg.Kafka.TlsConfig.CaCertFile) + if err != nil { + log.Error(err.Error(), errcodes.TLSInitialization) + return + } + } + + if cfg.Kafka.KrbConfig.Enabled { + krbConfig = &kafka.KerberosConfig{ + KeyTabPath: cfg.Kafka.KrbConfig.KrbKeyTabPath, + ConfigPath: cfg.Kafka.KrbConfig.KrbConfigPath, + Realm: cfg.Kafka.KrbConfig.KrbRealm, + Service: cfg.Kafka.KrbConfig.KrbServiceName, + Username: cfg.Kafka.KrbConfig.KrbUsername, + } + } + + iterator, err := kafka.NewBatchIterator( + ctx, + kafka.ConsumerConfig{ + BrokerAddr: cfg.Kafka.Address, + GroupID: cfg.Kafka.GroupId, + Topic: cfg.Kafka.Topic, + TLS: tlsConfig, + Kerberos: krbConfig, + Prometheus: &kafka.PrometheusConfig{ + Namespace: "consumer", + Registerer: prometheus.DefaultRegisterer, + Gatherer: prometheus.DefaultGatherer, + }, + }, + kafka.BatchConsumerSettings{ + ConsumerSettings: kafka.ConsumerSettings{ + MinBytes: cfg.Kafka.Settings.MinBytes, + MaxWait: cfg.Kafka.Settings.MaxWait, + MaxBytes: cfg.Kafka.Settings.MaxBytes, + MaxConcurrentFetches: cfg.Kafka.Settings.MaxConcurrentFetches, + }, + MaxPollRecords: cfg.Kafka.Settings.MaxPollRecords, + }, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + defer iterator.Close() + + srv = runMetricsServer(log) + + flowOpts := janitor.LoggingCallbacks(log, janitor.ShouldReturnFlowControl{ + OnPullErr: streamproc.FlowControlContinue, + OnProcessErr: streamproc.FlowControlStop, + OnUnrecoverable: streamproc.FlowControlStop, + OnThresholdReached: streamproc.FlowControlStop, + }) + + opts = append(opts, flowOpts...) + + log.Info("setup complete, running") + if err = processor.AsBatchExecutor().Run(ctx, iterator, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initEventHubsConsumer initializes a PubSub consumer component +func initEventHubsConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + var tlsConfig *tls.Config + saslConfig := &kafka.PlainSASLConfig{ + User: cfg.Eventhubs.SaslConfig.User, + Pass: cfg.Eventhubs.SaslConfig.Password, + } + if cfg.Eventhubs.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Eventhubs.TlsConfig.ClientCertFile, cfg.Eventhubs.TlsConfig.ClientKeyFile, cfg.Eventhubs.TlsConfig.CaCertFile) + if err != nil { + log.Error(err.Error(), errcodes.TLSInitialization) + return + } + } else { + // TLS has to be set when using eventhubs. In case it is not set, we need to skip certificate verification + tlsConfig = &tls.Config{ + InsecureSkipVerify: cfg.Eventhubs.TlsConfig.InsecureSkipVerify, + } + } + + iterator, err := kafka.NewBatchIterator( + ctx, + kafka.ConsumerConfig{ + BrokerAddr: cfg.Eventhubs.Address, + GroupID: cfg.Eventhubs.GroupId, + Topic: cfg.Eventhubs.Topic, + TLS: tlsConfig, + Prometheus: &kafka.PrometheusConfig{ + Namespace: "consumer", + Registerer: prometheus.DefaultRegisterer, + Gatherer: prometheus.DefaultGatherer, + }, + PlainSASL: saslConfig, + }, + kafka.BatchConsumerSettings{ + ConsumerSettings: kafka.ConsumerSettings{ + MinBytes: cfg.Eventhubs.Settings.MinBytes, + MaxWait: cfg.Eventhubs.Settings.MaxWait, + MaxBytes: cfg.Eventhubs.Settings.MaxBytes, + MaxConcurrentFetches: cfg.Eventhubs.Settings.MaxConcurrentFetches, + }, + MaxPollRecords: cfg.Eventhubs.Settings.MaxPollRecords, + }, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + defer iterator.Close() + + srv = runMetricsServer(log) + + log.Info("setup complete, running") + if err = processor.AsBatchExecutor().Run(ctx, iterator, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initPubSubConsumer initializes a PubSub consumer component +func initPubSubConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + receiver, err := pubsub.NewReceiver( + ctx, + pubsub.ReceiverConfig{ + ProjectID: cfg.Pubsub.ProjectId, + SubscriptionID: cfg.Pubsub.SubscriptionId, + }, + pubsub.ReceiveSettings{ + MaxExtension: cfg.Pubsub.Settings.MaxExtension, + MaxExtensionPeriod: cfg.Pubsub.Settings.MaxExtensionPeriod, + MaxOutstandingMessages: cfg.Pubsub.Settings.MaxOutstandingMessages, + MaxOutstandingBytes: cfg.Pubsub.Settings.MaxOutstandingBytes, + NumGoroutines: cfg.Pubsub.Settings.NumGoroutines, + }, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + defer func() { + if err := receiver.Close(); err != nil { + log.Error(err.Error(), errcodes.BrokerConnClosed) + } + }() + + srv = runMetricsServer(log) + + flowOpts := janitor.LoggingCallbacks(log, janitor.ShouldReturnFlowControl{ + OnPullErr: streamproc.FlowControlStop, + OnProcessErr: streamproc.FlowControlContinue, + OnUnrecoverable: streamproc.FlowControlContinue, + OnThresholdReached: streamproc.FlowControlStop, + }) + + opts = append(opts, flowOpts...) + + log.Info("setup complete, running") + if err = processor.AsReceiverExecutor().Run(ctx, receiver, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initServiceBusConsumer initializes a ServiceBus consumer component +func initServiceBusConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + iterator, err := servicebus.NewBatchIterator( + servicebus.IteratorConfig{ + ConnectionString: cfg.Servicebus.ConnectionString, + Topic: cfg.Servicebus.Topic, + Subscription: cfg.Servicebus.Subscription, + }, + servicebus.BatchIteratorSettings{ + BatchSize: cfg.Servicebus.Settings.BatchSize, + }, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + defer func() { + if err := iterator.Close(); err != nil { + log.Error(err.Error(), errcodes.BrokerConnClosed) + } + }() + + batchedReceiver := brokerutil.BatchedMessageIteratorIntoBatchedReceiver( + iterator, + brokerutil.IntoBatchedReceiverSettings{ + NumGoroutines: runtime.GOMAXPROCS(0), + }, + ) + + srv = runMetricsServer(log) + + flowOpts := janitor.LoggingCallbacks(log, janitor.ShouldReturnFlowControl{ + OnPullErr: streamproc.FlowControlStop, + OnProcessErr: streamproc.FlowControlContinue, + OnUnrecoverable: streamproc.FlowControlContinue, + OnThresholdReached: streamproc.FlowControlStop, + }) + + opts = append(opts, flowOpts...) + + log.Info("setup complete, running") + if err = processor.AsBatchedReceiverExecutor().Run(ctx, batchedReceiver, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initJetStreamConsumer initializes a JetStream consumer component +func initJetStreamConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + iterator, err := jetstream.NewBatchIterator( + ctx, + jetstream.IteratorConfig{ + URL: cfg.Jetstream.Url, + Subject: cfg.Jetstream.Subject, + ConsumerName: cfg.Jetstream.ConsumerName, + }, + jetstream.BatchIteratorSettings{ + BatchSize: cfg.Jetstream.Settings.BatchSize, + }, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + defer iterator.Close() + + batchedReceiver := brokerutil.BatchedMessageIteratorIntoBatchedReceiver( + iterator, + brokerutil.IntoBatchedReceiverSettings{ + NumGoroutines: runtime.GOMAXPROCS(0), + }, + ) + + srv = runMetricsServer(log) + + flowOpts := janitor.LoggingCallbacks(log, janitor.ShouldReturnFlowControl{ + OnPullErr: streamproc.FlowControlStop, + OnProcessErr: streamproc.FlowControlContinue, + OnUnrecoverable: streamproc.FlowControlContinue, + OnThresholdReached: streamproc.FlowControlStop, + }) + + opts = append(opts, flowOpts...) + + log.Info("setup complete, running") + if err = processor.AsBatchedReceiverExecutor().Run(ctx, batchedReceiver, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initPulsarConsumer initializes a Pulsar consumer component +func initPulsarConsumer(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + var srv *http.Server + var tlsConfig *tls.Config + if cfg.Kafka.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Pulsar.TlsConfig.ClientCertFile, cfg.Pulsar.TlsConfig.ClientKeyFile, cfg.Pulsar.TlsConfig.CaCertFile) + if err != nil { + log.Error(err.Error(), errcodes.TLSInitialization) + return + } + } + + iterator, err := pulsar.NewIterator( + pulsar.IteratorConfig{ + ServiceURL: cfg.Pulsar.ServiceUrl, + Topic: cfg.Pulsar.Topic, + Subscription: cfg.Pulsar.Subscription, + TLSConfig: tlsConfig, + }, + pulsar.DefaultIteratorSettings, + ) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + } + defer func() { + if err := iterator.Close(); err != nil { + log.Error(err.Error(), errcodes.BrokerConnClosed) + } + }() + + batchedReceiver := brokerutil.MessageIteratorIntoBatchedReceiver( + iterator, + brokerutil.IntoBatchedMessageIteratorSettings{ + BatchSize: pulsar.DefaultIteratorSettings.ReceiverQueueSize, + Timeout: pulsar.DefaultIteratorSettings.OperationTimeout, + }, + brokerutil.IntoBatchedReceiverSettings{ + NumGoroutines: runtime.GOMAXPROCS(0), + }, + ) + + srv = runMetricsServer(log) + + flowOpts := janitor.LoggingCallbacks(log, janitor.ShouldReturnFlowControl{ + OnPullErr: streamproc.FlowControlStop, + OnProcessErr: streamproc.FlowControlContinue, + OnUnrecoverable: streamproc.FlowControlContinue, + OnThresholdReached: streamproc.FlowControlStop, + }) + + opts = append(opts, flowOpts...) + + log.Info("setup complete, running") + if err = processor.AsBatchedReceiverExecutor().Run(ctx, batchedReceiver, opts...); err != nil { + log.Error(err.Error(), errcodes.CompletedWithErrors) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + log.Error(errors.Wrap(err, "http server shutdown failed").Error(), errcodes.MetricsServerShutdownFailure) + } +} + +// initializeSourceSystemAndRunProcessor initializes a consumer component and runs processor. +func initializeSourceSystemAndRunProcessor(ctx context.Context, processor *janitor.Processor, log logger.Log, cfg *config.Consumer, opts []streamproc.RunOption) { + switch cfg.Type { + case "kafka": + initKafkaConsumer(ctx, processor, log, cfg, opts) + case "eventhubs": + initEventHubsConsumer(ctx, processor, log, cfg, opts) + case "pubsub": + initPubSubConsumer(ctx, processor, log, cfg, opts) + case "servicebus": + initServiceBusConsumer(ctx, processor, log, cfg, opts) + case "jetstream": + initJetStreamConsumer(ctx, processor, log, cfg, opts) + case "pulsar": + initPulsarConsumer(ctx, processor, log, cfg, opts) + default: + log.Error(errtemplates.UnsupportedBrokerType(cfg.Type).Error(), errcodes.BrokerInitialization) + } +} + +func loadRunOptions(cfg *config.RunOptions) []streamproc.RunOption { + var opts []streamproc.RunOption + + opts = append(opts, streamproc.WithErrThreshold(cfg.ErrThreshold)) + opts = append(opts, streamproc.WithErrInterval(cfg.ErrInterval)) + opts = append(opts, streamproc.WithNumRetires(cfg.NumRetries)) + + return opts +} diff --git a/validator/internal/janitorctl/metrics.go b/validator/internal/janitorctl/metrics.go new file mode 100644 index 0000000..bb4de9f --- /dev/null +++ b/validator/internal/janitorctl/metrics.go @@ -0,0 +1,32 @@ +package janitorctl + +import ( + "fmt" + "net/http" + + "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/lib-logger/logger" +) + +// runMetricsServer runs a http server on which Prometheus metrics are being exposed. +// All metrics that are registered to default Prometheus Registry are displayed at: +// "localhost:2112/metrics" endpoint. +func runMetricsServer(log logger.Log) *http.Server { + http.Handle("/metrics", promhttp.Handler()) + + port := ":2112" + + srv := &http.Server{Addr: port} + + go func() { + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Error(err.Error(), errcodes.MetricsServerFailure) + } + }() + + log.Info(fmt.Sprintf("exposed metrics at port %s", port)) + + return srv +} diff --git a/validator/internal/janitorctl/run.go b/validator/internal/janitorctl/run.go new file mode 100644 index 0000000..faf4111 --- /dev/null +++ b/validator/internal/janitorctl/run.go @@ -0,0 +1,215 @@ +package janitorctl + +import ( + "context" + "runtime/debug" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/centralconsumer" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/config" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/pullercleaner" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-logger/logger" + "github.com/dataphos/lib-logger/standardlogger" + "github.com/dataphos/lib-shutdown/pkg/graceful" +) + +type ProcessorInitFunc func(context.Context, registry.SchemaRegistry, broker.Publisher) (*janitor.Processor, error) + +func RunCentralConsumer(configFile string) { + labels := logger.Labels{ + "product": "Schema Registry", + "component": "central_consumer", + } + var Commit = func() string { + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + + return "" + }() + if Commit != "" { + labels["commit"] = Commit + } + + logLevel, logConfigWarnings := config.GetLogLevel() + log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) + + for _, w := range logConfigWarnings { + log.Warn(w) + } + + var cfg config.CentralConsumer + if err := cfg.Read(configFile); err != nil { + log.Fatal(err.Error(), errcodes.ReadConfigFailure) + } + if err := cfg.Validate(); err != nil { + log.Fatal(err.Error(), errcodes.ValidateConfigFailure) + } + + initProcessor := func(ctx context.Context, registry registry.SchemaRegistry, publisher broker.Publisher) (*janitor.Processor, error) { + validators, err := initializeValidatorsForCentralConsumer(ctx, &cfg) + if err != nil { + return nil, err + } + + cc, err := centralconsumer.New( + registry, + publisher, + validators, + centralconsumer.Topics{ + Valid: cfg.Topics.Valid, + InvalidCSV: cfg.Topics.DeadLetter, + InvalidJSON: cfg.Topics.DeadLetter, + Deadletter: cfg.Topics.DeadLetter, + }, + centralconsumer.Settings{ + NumSchemaCollectors: cfg.NumSchemaCollectors, + NumInferrers: cfg.NumInferrers, + }, + log, + centralconsumer.RouterFlags{ + MissingSchema: cfg.ShouldLog.MissingSchema, + Valid: cfg.ShouldLog.Valid, + Deadletter: cfg.ShouldLog.DeadLetter, + }, + centralconsumer.Mode(cfg.Mode), + centralconsumer.SchemaMetadata{ + ID: cfg.SchemaID, + Version: cfg.SchemaVersion, + Format: cfg.SchemaType, + }, + cfg.Encryption.EncryptionKey, + ) + if err != nil { + return nil, err + } + return cc.AsProcessor(), nil + } + + run( + graceful.WithSignalShutdown(context.Background()), + log, + &cfg.Registry, + initProcessor, + &cfg.Producer, + &cfg.RunOptions, + &cfg.Consumer, + ) +} + +func RunPullerCleaner(configFile string) { + labels := logger.Labels{ + "product": "Schema Registry", + "component": "puller_cleaner", + } + var Commit = func() string { + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + + return "" + }() + if Commit != "" { + labels["commit"] = Commit + } + + logLevel, logConfigWarnings := config.GetLogLevel() + log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) + + for _, w := range logConfigWarnings { + log.Warn(w) + } + + var cfg config.PullerCleaner + if err := cfg.Read(configFile); err != nil { + log.Fatal(err.Error(), errcodes.ReadConfigFailure) + } + if err := cfg.Validate(); err != nil { + log.Fatal(err.Error(), errcodes.ValidateConfigFailure) + } + + initProcessor := func(ctx context.Context, registry registry.SchemaRegistry, publisher broker.Publisher) (*janitor.Processor, error) { + validators, err := initializeValidatorsForPullerCleaner(ctx, &cfg) + if err != nil { + return nil, err + } + + generators, err := initializeGenerators(&cfg) + if err != nil { + return nil, err + } + + pc, err := pullercleaner.New( + generators, + registry, + validators, + publisher, + pullercleaner.Topics{ + Valid: cfg.Topics.Valid, + Deadletter: cfg.Topics.DeadLetter, + }, + cfg.NumCleaners, + log, + pullercleaner.RouterFlags{ + Valid: cfg.ShouldLog.Valid, + Deadletter: cfg.ShouldLog.DeadLetter, + }, + ) + if err != nil { + return nil, err + } + return pc.AsProcessor(), nil + } + + run( + graceful.WithSignalShutdown(context.Background()), + log, + &cfg.Registry, + initProcessor, + &cfg.Producer, + &cfg.RunOptions, + &cfg.Consumer, + ) +} + +func run(ctx context.Context, log logger.Log, registryCfg *config.Registry, initProcessor ProcessorInitFunc, producerCfg *config.Producer, runOptions *config.RunOptions, consumerCfg *config.Consumer) { + log.Info("initializing schema registry") + schemaRegistry, err := initializeSchemaRegistry(ctx, log, registryCfg) + if err != nil { + log.Error(err.Error(), errcodes.RegistryInitialization) + return + } + + log.Info("initializing publisher") + publisher, err := initializePublisher(ctx, producerCfg) + if err != nil { + log.Error(err.Error(), errcodes.BrokerInitialization) + return + } + + log.Info("initializing main component") + processor, err := initProcessor(ctx, schemaRegistry, publisher) + if err != nil { + log.Error(err.Error(), errcodes.Initialization) + return + } + + log.Info("loading run settings") + opts := loadRunOptions(runOptions) + + log.Info("initializing source system and running processor") + initializeSourceSystemAndRunProcessor(ctx, processor, log, consumerCfg, opts) + + log.Info("shutting down") +} diff --git a/validator/internal/producer/config.go b/validator/internal/producer/config.go new file mode 100644 index 0000000..d5a53f0 --- /dev/null +++ b/validator/internal/producer/config.go @@ -0,0 +1,216 @@ +package producer + +import ( + "reflect" + "strings" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/go-playground/validator/v10" + "github.com/kkyr/fig" + "go.uber.org/multierr" +) + +// Config represents all required configuration to run a standalone producer. +type Config struct { + BaseDir string `toml:"base_dir" default:""` + FileName string `toml:"file_name" val:"file"` + NumberOfMessages int `toml:"number_of_messages" default:"100"` + RateLimit int `toml:"rate_limit" default:"100"` + TopicId string `toml:"topic_id" val:"required"` + Type string `toml:"type" val:"oneof=kafka eventhubs pubsub servicebus jetstream"` + EncryptionKey string `toml:"encryption_key"` + Kafka KafkaConfig `toml:"kafka"` + Eventhubs EventhubsConfig `toml:"eventhubs"` + Pubsub PubsubConfig `toml:"pubsub"` + Servicebus ServicebusConfig `toml:"servicebus"` + Jetstream JetstreamConfig `toml:"jetstream"` + RegistryConfig RegistryConfig `toml:"registry_config"` + Mode int `toml:"mode"` +} + +type KafkaConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + KrbConfig KrbConfig `toml:"krb_config"` + SaslConfig SaslConfig `toml:"sasl_config"` + Settings KafkaPublisherSettings `toml:"settings"` +} + +type EventhubsConfig struct { + Address string `toml:"address"` + TlsConfig TlsConfig `toml:"tls_config"` + SaslConfig SaslConfig `toml:"sasl_config"` + Settings EventhubsPublisherSettings `toml:"settings"` +} + +type TlsConfig struct { + Enabled bool `toml:"enabled"` + ClientCertFile string `toml:"client_cert_file" val:"required_if=Enabled true,omitempty,file"` + ClientKeyFile string `toml:"client_key_file" val:"required_if=Enabled true,omitempty,file"` + CaCertFile string `toml:"ca_cert_file" val:"required_if=Enabled true,omitempty,file"` +} + +type KrbConfig struct { + Enabled bool `toml:"enabled"` + KrbConfigPath string `toml:"krb_config_path"` + KrbKeyTabPath string `toml:"krb_keytab_path"` + KrbRealm string `toml:"krb_realm"` + KrbServiceName string `toml:"krb_service_name"` + KrbUsername string `toml:"krb_username"` +} + +type SaslConfig struct { + User string `toml:"user"` + Password string `toml:"password"` +} + +type KafkaPublisherSettings struct { + BatchSize int `toml:"batch_size" default:"40"` + BatchBytes int64 `toml:"batch_bytes" default:"5242880"` + Linger time.Duration `toml:"linger" default:"10ms"` +} + +type EventhubsPublisherSettings struct { + BatchSize int `toml:"batch_size" default:"40"` + BatchBytes int64 `toml:"batch_bytes" default:"5242880"` + Linger time.Duration `toml:"linger" default:"10ms"` +} + +type PubsubConfig struct { + ProjectId string `toml:"project_id"` + Settings PubsubPublisherSettings `toml:"settings"` +} + +type PubsubPublisherSettings struct { + DelayThreshold time.Duration `toml:"delay_threshold" default:"50ms"` + CountThreshold int `toml:"count_threshold" default:"50"` + ByteThreshold int `toml:"byte_threshold" default:"52428800"` + NumGoroutines int `toml:"num_goroutines" default:"5"` + Timeout time.Duration `toml:"timeout" default:"15s"` + MaxOutstandingMessages int `toml:"max_outstanding_messages" default:"800"` + MaxOutstandingBytes int `toml:"max_outstanding_bytes" default:"1048576000"` + EnableMessageOrdering bool `toml:"enable_message_ordering"` +} + +type ServicebusConfig struct { + ConnectionString string `toml:"connection_string"` +} + +type JetstreamConfig struct { + Url string `toml:"url"` + Settings JetstreamPublisherSettings `toml:"settings"` +} + +type JetstreamPublisherSettings struct { + MaxInflightPending int `toml:"max_inflight_pending" default:"512"` +} + +type RegistryConfig struct { + URL string `toml:"url" val:"url"` + GetTimeout time.Duration `toml:"get_timeout" default:"4s"` + RegisterTimeout time.Duration `toml:"register_timeout" default:"10s"` + UpdateTimeout time.Duration `toml:"update_timeout" default:"10s"` + Type string `toml:"type" default:"janitor" val:"oneof=janitor apicurio"` + GroupID string `toml:"groupID"` +} + +// Read loads parameters from configuration file into Config struct. +func (cfg *Config) Read(fileName string) error { + return fig.Load(cfg, fig.File(fileName), fig.Tag("toml"), fig.UseEnv("")) +} + +// Validate validates Config struct. +func (cfg *Config) Validate() error { + validate := validator.New() + validate.SetTagName("val") + + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := strings.SplitN(fld.Tag.Get("toml"), ",", 2)[0] + if name == "-" { + return "" + } + return name + }) + + validate.RegisterStructValidation( + publisherStructLevelValidation, + KafkaConfig{}, + EventhubsConfig{}, + PubsubConfig{}, + ServicebusConfig{}, + JetstreamConfig{}, + ) + + if err := validate.Struct(cfg); err != nil { + if _, ok := err.(*validator.InvalidValidationError); ok { + return err + } + + var errCombined error + for _, err := range err.(validator.ValidationErrors) { + // Trims prefix in order to correspond to TOML key path. + fieldName := strings.TrimPrefix(err.Namespace(), "Config.") + + switch err.Tag() { + case "required": + errCombined = multierr.Append(errCombined, errtemplates.RequiredTagFail(fieldName)) + case "required_if": + errCombined = multierr.Append(errCombined, errtemplates.RequiredTagFail(fieldName)) + case "file": + errCombined = multierr.Append(errCombined, errtemplates.FileTagFail(fieldName, err.Value())) + case "url": + errCombined = multierr.Append(errCombined, errtemplates.UrlTagFail(fieldName, err.Value())) + case "oneof": + errCombined = multierr.Append(errCombined, errtemplates.OneofTagFail(fieldName, err.Value())) + case "hostname_port": + errCombined = multierr.Append(errCombined, errtemplates.HostnamePortTagFail(fieldName, err.Value())) + default: + errCombined = multierr.Append(errCombined, err) + } + } + return errCombined + } + return nil +} + +// publisherStructLevelValidation is a custom validator which validates broker +// structure depending on which type of producer is required. +func publisherStructLevelValidation(sl validator.StructLevel) { + source := sl.Parent().Interface().(Config) + + validate := validator.New() + + switch producer := sl.Current().Interface().(type) { + case KafkaConfig: + if source.Type == "kafka" { + if err := validate.Var(producer.Address, "hostname_port"); err != nil { + sl.ReportValidationErrors("address", "", err.(validator.ValidationErrors)) + } + } + case EventhubsConfig: + if source.Type == "eventhubs" { + if err := validate.Var(producer.Address, "hostname_port"); err != nil { + sl.ReportValidationErrors("address", "", err.(validator.ValidationErrors)) + } + } + case PubsubConfig: + if source.Type == "pubsub" { + if err := validate.Var(producer.ProjectId, "required"); err != nil { + sl.ReportValidationErrors("project_id", "", err.(validator.ValidationErrors)) + } + } + case ServicebusConfig: + if source.Type == "servicebus" { + if err := validate.Var(producer.ConnectionString, "required"); err != nil { + sl.ReportValidationErrors("connection_string", "", err.(validator.ValidationErrors)) + } + } + case JetstreamConfig: + if source.Type == "jetstream" { + if err := validate.Var(producer.Url, "url"); err != nil { + sl.ReportValidationErrors("url", "", err.(validator.ValidationErrors)) + } + } + } +} diff --git a/validator/internal/producer/load.go b/validator/internal/producer/load.go new file mode 100644 index 0000000..e3d1801 --- /dev/null +++ b/validator/internal/producer/load.go @@ -0,0 +1,238 @@ +package producer + +import ( + "bytes" + "context" + "encoding/csv" + "io" + "log" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker" + + "github.com/pkg/errors" +) + +// IntoBrokerMessages converts the given ProcessEntry slice into a slice of broker.Message, by calling IntoBrokerMessage on each entry. +func IntoBrokerMessages(ctx context.Context, entries []ProcessedEntry, registry registry.SchemaRegistry) ([]broker.OutboundMessage, error) { + brokerMessages := make([]broker.OutboundMessage, len(entries)) + for i, curr := range entries { + message, err := IntoBrokerMessage(ctx, curr, registry) + if err != nil { + return nil, err + } + brokerMessages[i] = message + } + return brokerMessages, nil +} + +// IntoBrokerMessage converts the given ProcessedEntry into broker.Message, while also performing schema registration, depending +// on the value of ProcessedEntry.ShouldRegister. +func IntoBrokerMessage(ctx context.Context, entry ProcessedEntry, registry registry.SchemaRegistry) (broker.OutboundMessage, error) { + attributes := make(map[string]interface{}) + + attributes[janitor.AttributeFormat] = entry.Format + if entry.Version != "" { + attributes[janitor.AttributeSchemaVersion] = entry.Version + } + + if entry.ShouldRegister { + var schemaId, versionId string + var err error + schemaId, versionId, err = registry.Register(ctx, entry.Schema, entry.Format, entry.CompatibilityMode, entry.ValidityMode) + if err != nil { + return broker.OutboundMessage{}, err + } + + log.Printf("schema registered under %s/%s\n", schemaId, versionId) + + attributes[janitor.AttributeSchemaID] = schemaId + attributes[janitor.AttributeSchemaVersion] = versionId + + for k, v := range entry.AdditionalAttributes { + attributes[k] = v + } + } + + return broker.OutboundMessage{ + Data: entry.Message, + Attributes: attributes, + }, nil +} + +// ProcessedEntry is the processed version of Entry. +type ProcessedEntry struct { + Message []byte + Schema []byte + ShouldRegister bool + Format string + CompatibilityMode string + ValidityMode string + Version string + AdditionalAttributes map[string]interface{} +} + +// ProcessEntries processes the given Entry slice, by calling ProcessEntry on each Entry. +func ProcessEntries(baseDir string, entries []Entry) ([]ProcessedEntry, error) { + messageSchemaPairs := make([]ProcessedEntry, len(entries)) + var loaded ProcessedEntry + var err error + for i, curr := range entries { + loaded, err = ProcessEntry(baseDir, curr) + if err != nil { + return nil, err + } + messageSchemaPairs[i] = loaded + } + return messageSchemaPairs, nil +} + +// ProcessEntry processes the given Entry, by loading ProcessedEntry.Message and ProcessedEntry.Schema from the filenames +// in the relevant Entry fields. It is assumed that the correct absolute path of the given filename can be gained by calling +// filepath.Join with the given baseDir as the first argument. +func ProcessEntry(baseDir string, entry Entry) (ProcessedEntry, error) { + var message, schema []byte + var err error + + messageFilename := filepath.Join(baseDir, entry.BlobFilename) + log.Printf("loading message data from %s\n", messageFilename) + message, err = os.ReadFile(messageFilename) + if err != nil { + return ProcessedEntry{}, err + } + + if entry.SchemaFilename == "" { + if entry.ShouldRegister { + return ProcessedEntry{}, errors.New("invalid entry: can't register an entry since no file was given") + } + } else { + schemaFilename := filepath.Join(baseDir, entry.SchemaFilename) + log.Printf("loading schema data from %s\n", schemaFilename) + schema, err = os.ReadFile(schemaFilename) + if err != nil { + return ProcessedEntry{}, err + } + } + + return ProcessedEntry{ + Message: message, + Schema: schema, + ShouldRegister: entry.ShouldRegister, + Format: entry.Format, + CompatibilityMode: entry.CompatibilityMode, + ValidityMode: entry.ValidityMode, + Version: entry.Version, + AdditionalAttributes: entry.Attributes, + }, nil +} + +type Entry struct { + BlobFilename string + SchemaFilename string + ShouldRegister bool + Format string + CompatibilityMode string + ValidityMode string + Version string + Attributes map[string]interface{} +} + +// LoadEntries loads the entries from the given csv file. +func LoadEntries(filename string) ([]Entry, error) { + file, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + + return parseEntriesFile(bytes.NewReader(file)) +} + +// parseEntriesFile parses the given csv file. +func parseEntriesFile(file io.Reader) ([]Entry, error) { + reader := csv.NewReader(file) + + reader.Comma = ',' + + lines, err := reader.ReadAll() + if err != nil { + return nil, err + } + + entries := make([]Entry, len(lines)) + var curr Entry + for i, line := range lines { + if len(line) == 4 { + curr, err = parseLineNoSchema(line) + } else if len(line) == 5 { + curr, err = parseLineOneCCPerTopic(line) + } else { + curr, err = parseLine(line) + } + if err != nil { + return nil, err + } + entries[i] = curr + } + + return entries, nil +} + +// parseLine parses a given line of the csv file. +func parseLine(line []string) (Entry, error) { + shouldRegister, err := strconv.ParseBool(line[2]) + if err != nil { + return Entry{}, err + } + + var attributes = make(map[string]interface{}) + attrs := strings.Split(line[6], ";") + for _, at := range attrs { + if at == "" { + continue + } + pair := strings.SplitN(at, "=", 2) + attributes[pair[0]] = pair[1] + } + + return Entry{ + BlobFilename: line[0], + SchemaFilename: line[1], + ShouldRegister: shouldRegister, + Format: line[3], + CompatibilityMode: line[4], + ValidityMode: line[5], + Version: "", + Attributes: attributes, + }, nil +} + +func parseLineNoSchema(line []string) (Entry, error) { + return Entry{ + BlobFilename: line[0], + SchemaFilename: "", + ShouldRegister: false, + Format: line[1], + CompatibilityMode: line[2], + ValidityMode: line[3], + Version: "", + Attributes: nil, + }, nil +} + +func parseLineOneCCPerTopic(line []string) (Entry, error) { + return Entry{ + BlobFilename: line[0], + SchemaFilename: "", + ShouldRegister: false, + Version: line[1], + Format: line[2], + CompatibilityMode: line[3], + ValidityMode: line[4], + Attributes: nil, + }, nil +} diff --git a/validator/internal/producer/producer.go b/validator/internal/producer/producer.go new file mode 100644 index 0000000..c3fa037 --- /dev/null +++ b/validator/internal/producer/producer.go @@ -0,0 +1,124 @@ +package producer + +import ( + "context" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/pkg/errors" + "go.uber.org/ratelimit" + "log" + "math" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker" + + "golang.org/x/sync/errgroup" +) + +type Mode int + +const ( + Default Mode = iota + OneCCPerTopic +) + +// Producer models a producer used for schema registry and the publishing of the given dataset. +type Producer struct { + Registry registry.SchemaRegistry + Topic broker.Topic + Frequency int + Mode Mode + EncryptionKey string +} + +// New returns a new Producer instance. +func New(registry registry.SchemaRegistry, topic broker.Topic, rate int, mode Mode, encryptionKey string) *Producer { + return &Producer{ + Registry: registry, + Topic: topic, + Frequency: rate, + Mode: mode, + EncryptionKey: encryptionKey, + } +} + +// LoadAndProduce loads the dataset from the given filename, assuming the directory to the dataset is given with baseDir, +// (optionally) registers and publishes the loaded messages exactly n times. +func (p *Producer) LoadAndProduce(ctx context.Context, baseDir, filename string, n int) error { + log.Printf("loading entries from %s...\n", filename) + start := time.Now() + entries, err := LoadEntries(filename) + if err != nil { + return err + } + log.Println("entries loaded in", time.Since(start)) + + log.Println("loading messages and schemas...") + start = time.Now() + processedEntries, err := ProcessEntries(baseDir, entries) + if err != nil { + return err + } + log.Println("messages and schemas loaded in", time.Since(start)) + + log.Println("converting into broker messages...") + start = time.Now() + messages, err := IntoBrokerMessages(ctx, processedEntries, p.Registry) + if err != nil { + return err + } + log.Println("converted into broker messages in", time.Since(start)) + + log.Printf("publishing...") + start = time.Now() + if err = p.Publish(ctx, messages, n); err != nil { + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + return nil + } + return err + } + log.Println("published", n, "messages in", time.Since(start)) + return nil +} + +// Publish publishes the given broker.Message slice n times, in a round-robin way in case the size of the dataset is smaller +// than n. +func (p *Producer) Publish(ctx context.Context, messages []broker.OutboundMessage, n int) error { + datasetSize := len(messages) + + if n <= 0 { + n = math.MaxInt64 + } + + rl := ratelimit.NewUnlimited() + if p.Frequency > 0 { + // throws error if rate <= 0 + rl = ratelimit.New(p.Frequency) // per second + } + + eg, ctx := errgroup.WithContext(ctx) +LOOP: + for i := 0; i < n; i++ { + select { + case <-ctx.Done(): + break LOOP + default: + } + + message := messages[i%datasetSize] + if p.EncryptionKey != "" { + encryptedData, err := janitor.Encrypt(message.Data, p.EncryptionKey) + if err != nil { + return err + } + message.Data = encryptedData + } + + rl.Take() + eg.Go(func() error { + return p.Topic.Publish(ctx, message) + }) + + } + return eg.Wait() +} diff --git a/validator/internal/producer/producer_test.go b/validator/internal/producer/producer_test.go new file mode 100644 index 0000000..4f39b24 --- /dev/null +++ b/validator/internal/producer/producer_test.go @@ -0,0 +1,69 @@ +package producer + +import ( + "bytes" + "context" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker/inmem" +) + +func TestProducer(t *testing.T) { + publisher := inmem.Publisher{} + topic, _ := publisher.Topic("some-topic") + + _, b, _, _ := runtime.Caller(0) + dir := filepath.Dir(b) + testdataDir := filepath.Join(dir, "testdata") + + messageToRegister, err := os.ReadFile(filepath.Join(testdataDir, "data-1.json")) + if err != nil { + t.Fatal(err) + } + schemaToRegister, err := os.ReadFile(filepath.Join(testdataDir, "schema-1.json")) + if err != nil { + t.Fatal(err) + } + + schemaRegistry := registry.NewMock() + schemaRegistry.SetRegisterResponse(schemaToRegister, "1", "1", nil) + + encryptionKey := "" + producer := New(schemaRegistry, topic, 100, 0, encryptionKey) + + root := filepath.Join(dir, "../..") + dataset := filepath.Join(dir, "testdata/dataset.csv") + + if err = producer.LoadAndProduce(context.Background(), root, dataset, 5); err != nil { + t.Fatal(err) + } + + if len(publisher.Spawned[0].Published) != 5 { + t.Fatal("publish count not as expected") + } + for _, published := range publisher.Spawned[0].Published { + if published.Attributes[janitor.AttributeFormat] != "json" { + t.Fatal("format not as expected") + } + + if bytes.Equal(published.Data, messageToRegister) { + if published.Attributes[janitor.AttributeSchemaID] != "1" || + published.Attributes[janitor.AttributeSchemaVersion] != "1" { + t.Fatal("schema id and version not as expected") + } + } else { + if _, ok := published.Attributes[janitor.AttributeSchemaID]; ok { + t.Fatal("schema id not empty, empty expected") + } + if _, ok := published.Attributes[janitor.AttributeSchemaVersion]; ok { + t.Fatal("schema version not empty, empty expected") + } + } + } + +} diff --git a/validator/internal/producer/run.go b/validator/internal/producer/run.go new file mode 100644 index 0000000..4510c89 --- /dev/null +++ b/validator/internal/producer/run.go @@ -0,0 +1,175 @@ +package producer + +import ( + "context" + "crypto/tls" + "errors" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry/apicuriosr" + "log" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errcodes" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry/janitorsr" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-brokers/pkg/broker/jetstream" + "github.com/dataphos/lib-brokers/pkg/broker/kafka" + "github.com/dataphos/lib-brokers/pkg/broker/pubsub" + "github.com/dataphos/lib-brokers/pkg/broker/servicebus" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-shutdown/pkg/graceful" +) + +func Run(configFile string) { + var cfg Config + if err := cfg.Read(configFile); err != nil { + log.Fatal(err.Error()+" ", errcodes.ReadConfigFailure) + } + if err := cfg.Validate(); err != nil { + log.Fatal(err.Error()+" ", errcodes.ValidateConfigFailure) + } + + ctx := graceful.WithSignalShutdown(context.Background()) + + var sr registry.SchemaRegistry + var err error + switch cfg.RegistryConfig.Type { + case "apicurio": + sr, err = apicuriosr.New( + ctx, + cfg.RegistryConfig.URL, + apicuriosr.TimeoutSettings{ + GetTimeout: cfg.RegistryConfig.GetTimeout, + RegisterTimeout: cfg.RegistryConfig.RegisterTimeout, + UpdateTimeout: cfg.RegistryConfig.UpdateTimeout, + }, + cfg.RegistryConfig.GroupID, + ) + case "janitor": + sr, err = janitorsr.New( + ctx, + cfg.RegistryConfig.URL, + janitorsr.TimeoutSettings{ + GetTimeout: cfg.RegistryConfig.GetTimeout, + RegisterTimeout: cfg.RegistryConfig.RegisterTimeout, + UpdateTimeout: cfg.RegistryConfig.UpdateTimeout, + }, + cfg.RegistryConfig.GroupID, + ) + default: + sr, err = nil, errtemplates.UnsupportedRegistryType(cfg.Type) + } + if err != nil { + log.Fatal(err) + } + + publisher, err := selectPublisher(ctx, &cfg) + if err != nil { + log.Fatal(err) + } + + topic, err := publisher.Topic(cfg.TopicId) + if err != nil { + log.Fatal(err) + } + + if err = New(sr, topic, cfg.RateLimit, Mode(cfg.Mode), cfg.EncryptionKey).LoadAndProduce(ctx, cfg.BaseDir, cfg.FileName, cfg.NumberOfMessages); err != nil { + log.Fatal(err) + } + log.Println("done") +} + +func selectPublisher(ctx context.Context, cfg *Config) (broker.Publisher, error) { + switch cfg.Type { + case "pubsub": + return pubsub.NewPublisher( + ctx, + pubsub.PublisherConfig{ + ProjectID: cfg.Pubsub.ProjectId, + }, + pubsub.PublishSettings{ + DelayThreshold: cfg.Pubsub.Settings.DelayThreshold, + CountThreshold: cfg.Pubsub.Settings.CountThreshold, + ByteThreshold: cfg.Pubsub.Settings.ByteThreshold, + NumGoroutines: cfg.Pubsub.Settings.NumGoroutines, + Timeout: cfg.Pubsub.Settings.Timeout, + MaxOutstandingMessages: cfg.Pubsub.Settings.MaxOutstandingMessages, + MaxOutstandingBytes: cfg.Pubsub.Settings.MaxOutstandingBytes, + EnableMessageOrdering: cfg.Pubsub.Settings.EnableMessageOrdering, + }, + ) + case "kafka": + var tlsConfig *tls.Config + var krbConfig *kafka.KerberosConfig + if cfg.Kafka.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Kafka.TlsConfig.ClientCertFile, cfg.Kafka.TlsConfig.ClientKeyFile, cfg.Kafka.TlsConfig.CaCertFile) + if err != nil { + return nil, err + } + } + if cfg.Kafka.KrbConfig.Enabled { + krbConfig = &kafka.KerberosConfig{ + KeyTabPath: cfg.Kafka.KrbConfig.KrbKeyTabPath, + ConfigPath: cfg.Kafka.KrbConfig.KrbConfigPath, + Realm: cfg.Kafka.KrbConfig.KrbRealm, + Service: cfg.Kafka.KrbConfig.KrbServiceName, + Username: cfg.Kafka.KrbConfig.KrbUsername, + } + } + return kafka.NewPublisher( + ctx, + kafka.ProducerConfig{ + BrokerAddr: cfg.Kafka.Address, + TLS: tlsConfig, + Kerberos: krbConfig, + }, + kafka.ProducerSettings{ + BatchSize: cfg.Kafka.Settings.BatchSize, + BatchBytes: cfg.Kafka.Settings.BatchBytes, + Linger: cfg.Kafka.Settings.Linger, + }, + ) + case "eventhubs": + var tlsConfig *tls.Config + var saslConfig *kafka.PlainSASLConfig + if cfg.Eventhubs.TlsConfig.Enabled { + var err error + tlsConfig, err = httputil.NewTLSConfig(cfg.Eventhubs.TlsConfig.ClientCertFile, cfg.Eventhubs.TlsConfig.ClientKeyFile, cfg.Eventhubs.TlsConfig.CaCertFile) + if err != nil { + return nil, err + } + } + saslConfig = &kafka.PlainSASLConfig{ + User: cfg.Eventhubs.SaslConfig.User, + Pass: cfg.Eventhubs.SaslConfig.Password, + } + + return kafka.NewPublisher( + ctx, + kafka.ProducerConfig{ + BrokerAddr: cfg.Eventhubs.Address, + TLS: tlsConfig, + PlainSASL: saslConfig, + DisableCompression: true, + }, + kafka.ProducerSettings{ + BatchSize: cfg.Eventhubs.Settings.BatchSize, + BatchBytes: cfg.Eventhubs.Settings.BatchBytes, + Linger: cfg.Eventhubs.Settings.Linger, + }, + ) + case "servicebus": + return servicebus.NewPublisher(cfg.Servicebus.ConnectionString) + case "jetstream": + return jetstream.NewPublisher( + ctx, + cfg.Jetstream.Url, + jetstream.PublisherSettings{ + MaxPending: cfg.Jetstream.Settings.MaxInflightPending, + }, + ) + default: + return nil, errors.New("unsupported broker type") + } +} diff --git a/validator/internal/producer/testdata/data-1.json b/validator/internal/producer/testdata/data-1.json new file mode 100644 index 0000000..3fe0812 --- /dev/null +++ b/validator/internal/producer/testdata/data-1.json @@ -0,0 +1,5 @@ +{ + "firstName": "John", + "lastName": "Doe", + "age": 21 +} diff --git a/validator/internal/producer/testdata/data-2.json b/validator/internal/producer/testdata/data-2.json new file mode 100644 index 0000000..7d1ee16 --- /dev/null +++ b/validator/internal/producer/testdata/data-2.json @@ -0,0 +1,13 @@ +{ + "fruits": [ "apple", "orange", "pear" ], + "vegetables": [ + { + "veggieName": "potato", + "veggieLike": true + }, + { + "veggieName": "broccoli", + "veggieLike": false + } + ] +} diff --git a/validator/internal/producer/testdata/dataset.csv b/validator/internal/producer/testdata/dataset.csv new file mode 100644 index 0000000..b5bb5bd --- /dev/null +++ b/validator/internal/producer/testdata/dataset.csv @@ -0,0 +1,2 @@ +internal/producer/testdata/data-1.json,internal/producer/testdata/schema-1.json,true,json,none,none, +internal/producer/testdata/data-2.json,internal/producer/testdata/schema-2.json,false,json,none,none, diff --git a/validator/internal/producer/testdata/schema-1.json b/validator/internal/producer/testdata/schema-1.json new file mode 100644 index 0000000..687ae74 --- /dev/null +++ b/validator/internal/producer/testdata/schema-1.json @@ -0,0 +1,21 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/validator/internal/producer/testdata/schema-2.json b/validator/internal/producer/testdata/schema-2.json new file mode 100644 index 0000000..72ab606 --- /dev/null +++ b/validator/internal/producer/testdata/schema-2.json @@ -0,0 +1,34 @@ +{ + "$id": "https://example.com/arrays.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a person, company, organization, or place", + "type": "object", + "properties": { + "fruits": { + "type": "array", + "items": { + "type": "string" + } + }, + "vegetables": { + "type": "array", + "items": { "$ref": "#/$defs/veggie" } + } + }, + "$defs": { + "veggie": { + "type": "object", + "required": [ "veggieName", "veggieLike" ], + "properties": { + "veggieName": { + "type": "string", + "description": "The name of the vegetable." + }, + "veggieLike": { + "type": "boolean", + "description": "Do I like this vegetable?" + } + } + } + } +} diff --git a/validator/internal/publisher/mock.go b/validator/internal/publisher/mock.go new file mode 100644 index 0000000..e97519b --- /dev/null +++ b/validator/internal/publisher/mock.go @@ -0,0 +1,21 @@ +package publisher + +import ( + "golang.org/x/net/context" + + "github.com/dataphos/lib-brokers/pkg/broker" +) + +type MockPublisher struct { +} + +type MockTopic struct { +} + +func (*MockTopic) Publish(context.Context, broker.OutboundMessage) error { + return nil +} + +func (*MockPublisher) Topic(_ string) (broker.Topic, error) { + return &MockTopic{}, nil +} diff --git a/validator/internal/pullercleaner/pullercleaner.go b/validator/internal/pullercleaner/pullercleaner.go new file mode 100644 index 0000000..66415df --- /dev/null +++ b/validator/internal/pullercleaner/pullercleaner.go @@ -0,0 +1,149 @@ +// Package pullercleaner houses a pipeline over a message stream which attempts to generate and register new +// schemas and send the updated messages to a destination topic. +package pullercleaner + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-brokers/pkg/broker" + "github.com/dataphos/lib-logger/logger" +) + +// PullerCleaner models the pullercleaner process. +type PullerCleaner struct { + Publisher broker.Publisher + TopicIDs Topics + CleanerRouter janitor.CleanerRouter + cleanerRouterSem chan struct{} + topics map[string]broker.Topic + log logger.Log +} + +// Topics defines the standard destination topics, based on possible validation results. +type Topics struct { + Valid string + Deadletter string +} + +// RouterFlags defines logging levels for logging each routing decision. +type RouterFlags struct { + Valid bool + Deadletter bool +} + +const ( + csvFormat = "csv" + jsonFormat = "json" +) + +// New returns a new instance of PullerCleaner. +func New(schemaGenerators janitor.SchemaGenerators, registry registry.SchemaRegistry, validators janitor.Validators, publisher broker.Publisher, topicIds Topics, numCleaners int, log logger.Log, routerFlags RouterFlags) (*PullerCleaner, error) { + topics, err := setupTopics(topicIds, publisher) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.Deadletter)) + } + + return &PullerCleaner{ + Publisher: publisher, + TopicIDs: topicIds, + CleanerRouter: janitor.CleanerRouter{ + Cleaner: janitor.NewCachingCleaner(schemaGenerators, validators, registry), + Router: setupRoutingFunc(topicIds, routerFlags, log), + }, + cleanerRouterSem: make(chan struct{}, numCleaners), + topics: topics, + log: log, + }, nil +} + +// setupTopics maps Topics into instances of broker.Topic. +func setupTopics(topicIds Topics, publisher broker.Publisher) (map[string]broker.Topic, error) { + topics := make(map[string]broker.Topic) + + if topicIds.Valid != "" { + topic, err := publisher.Topic(topicIds.Valid) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.Valid)) + } + topics[topicIds.Valid] = topic + } + + if topicIds.Deadletter != "" { + topic, err := publisher.Topic(topicIds.Deadletter) + if err != nil { + return nil, errors.Wrap(err, errtemplates.CreatingTopicInstanceFailed(topicIds.Deadletter)) + } + topics[topicIds.Deadletter] = topic + } + return topics, nil +} + +// setupRoutingFunc sets up the janitor.LoggingRouter, by first checking if there's a need for logging any of the routing +// decisions (if any logging level flag is set). If none of the flags are set, standard IntoRoutingFunc is used, +// wrapping it with logging middleware otherwise. +func setupRoutingFunc(topicIDs Topics, routerFlags RouterFlags, log logger.Log) janitor.Router { + next := IntoRoutingFunc(topicIDs) + + if routerFlags.Valid || routerFlags.Deadletter { + return janitor.LoggingRouter( + log, + janitor.RouterFlags{ + Valid: routerFlags.Valid, + Deadletter: routerFlags.Deadletter, + }, + next, + ) + } + + return next +} + +// IntoRoutingFunc maps the given Topics into a janitor.LoggingRouter. +// +// If the janitor.Result is janitor.Deadletter, the message are routed to Topics.Deadletter. +// All valid messages are sent to Topics.Valid. +func IntoRoutingFunc(topics Topics) janitor.Router { + return janitor.RoutingFunc(func(result janitor.Result, _ janitor.Message) string { + switch result { + case janitor.Valid: + return topics.Valid + case janitor.Invalid, janitor.Deadletter, janitor.MissingSchema: + return topics.Deadletter + default: + return topics.Deadletter + } + }) +} + +func (pc *PullerCleaner) AsProcessor() *janitor.Processor { + return janitor.NewProcessor(pc, pc.topics, pc.TopicIDs.Deadletter, pc.log) +} + +func (pc *PullerCleaner) Handle(ctx context.Context, message janitor.Message) (janitor.MessageTopicPair, error) { + acquireIfSet(pc.cleanerRouterSem) + messageTopicPair, err := pc.CleanerRouter.CleanAndReroute(ctx, message) + if err != nil { + releaseIfSet(pc.cleanerRouterSem) + return janitor.MessageTopicPair{}, err + } + releaseIfSet(pc.cleanerRouterSem) + + return messageTopicPair, nil +} + +func acquireIfSet(sem chan struct{}) { + if sem != nil { + sem <- struct{}{} + } +} + +func releaseIfSet(sem chan struct{}) { + if sem != nil { + <-sem + } +} diff --git a/validator/internal/pullercleaner/pullercleaner_test.go b/validator/internal/pullercleaner/pullercleaner_test.go new file mode 100644 index 0000000..738d21f --- /dev/null +++ b/validator/internal/pullercleaner/pullercleaner_test.go @@ -0,0 +1,42 @@ +package pullercleaner + +import ( + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitor" +) + +func TestTopicsIntoRoutingFunc(t *testing.T) { + topics := Topics{ + Valid: "valid-topic", + Deadletter: "deadletter", + } + + tt := []struct { + name string + isValid janitor.Result + format string + destination string + }{ + {"valid json", janitor.Valid, jsonFormat, topics.Valid}, + {"invalid json", janitor.Invalid, jsonFormat, topics.Deadletter}, + {"deadletter json", janitor.Deadletter, jsonFormat, topics.Deadletter}, + {"missing schema json", janitor.MissingSchema, jsonFormat, topics.Deadletter}, + {"valid csv", janitor.Valid, csvFormat, topics.Valid}, + {"invalid csv", janitor.Invalid, csvFormat, topics.Deadletter}, + {"deadletter csv", janitor.Deadletter, csvFormat, topics.Deadletter}, + {"missing schema csv", janitor.MissingSchema, csvFormat, topics.Deadletter}, + } + + routingFunc := IntoRoutingFunc(topics) + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + destination := routingFunc.Route(tc.isValid, janitor.Message{Format: tc.format}) + if destination != tc.destination { + t.Errorf("expected and actual destination not the same (%s != %s)", tc.destination, destination) + } + }) + } +} diff --git a/validator/internal/registry/apicuriosr/apicuriosr.go b/validator/internal/registry/apicuriosr/apicuriosr.go new file mode 100644 index 0000000..6166ad3 --- /dev/null +++ b/validator/internal/registry/apicuriosr/apicuriosr.go @@ -0,0 +1,289 @@ +package apicuriosr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "github.com/dataphos/lib-retry/pkg/retry" + "io" + "log" + "net/http" + "strings" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-httputil/pkg/httputil" + + "github.com/pkg/errors" +) + +// SchemaRegistry is a proxy for communicating with the janitor schema registry server. +type SchemaRegistry struct { + Url string + Timeouts TimeoutSettings + GroupID string +} + +// TimeoutSettings defines the maximum amount of time for each get, register or update request. +type TimeoutSettings struct { + GetTimeout time.Duration + RegisterTimeout time.Duration + UpdateTimeout time.Duration +} + +var DefaultTimeoutSettings = TimeoutSettings{ + GetTimeout: 4 * time.Second, + RegisterTimeout: 10 * time.Second, + UpdateTimeout: 10 * time.Second, +} + +// New returns an instance of SchemaRegistry. +// +// Performs a health check to see if the schema registry is available, retrying periodically until the context is cancelled +// or the health check succeeds. +func New(ctx context.Context, url string, timeouts TimeoutSettings, groupID string) (*SchemaRegistry, error) { + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach schema registry at %s failed", url) + } + + return &SchemaRegistry{ + Url: url, + Timeouts: timeouts, + GroupID: groupID, + }, nil +} + +func (sr *SchemaRegistry) Get(ctx context.Context, id, version string) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.GetTimeout) + defer cancel() + + response, err := sr.sendGetRequest(ctx, id, version) + if err != nil { + return nil, err + } + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + if response.StatusCode != http.StatusOK { + if response.StatusCode == http.StatusNotFound { + return nil, errors.Wrapf(registry.ErrNotFound, "fetching schema %s/%s failed", id, version) + } + return nil, errors.Wrapf(errtemplates.BadHttpStatusCode(response.StatusCode), "fetching schema %s/%s resulted in a bad status code", id, version) + } + + return body, nil +} + +func (sr *SchemaRegistry) sendGetRequest(ctx context.Context, id string, version string) (*http.Response, error) { + url := fmt.Sprintf("%s/apis/registry/v2/groups/%s/artifacts/%s/versions/%s", sr.Url, sr.GroupID, id, version) + + request, err := httputil.Get(ctx, url) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodGet, url)) + } + + return response, nil +} + +func (sr *SchemaRegistry) GetLatest(ctx context.Context, id string) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.GetTimeout) + defer cancel() + + response, err := sr.sendGetLatestRequest(ctx, id) + if err != nil { + return nil, err + } + defer func() { + err := response.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + if response.StatusCode != http.StatusOK { + if response.StatusCode == http.StatusNotFound { + return nil, errors.Wrapf(registry.ErrNotFound, "fetching schema %s/latest failed", id) + } + return nil, errors.Wrapf(errtemplates.BadHttpStatusCode(response.StatusCode), "fetching schema %s/latest resulted in a bad status code", id) + } + + return body, nil +} + +func (sr *SchemaRegistry) sendGetLatestRequest(ctx context.Context, id string) (*http.Response, error) { + url := fmt.Sprintf("%s/apis/registry/v2/groups/%s/artifacts/%s/versions/latest", sr.Url, sr.GroupID, id) + + request, err := httputil.Get(ctx, url) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodGet, url)) + } + + return response, nil +} + +func (sr *SchemaRegistry) Register(ctx context.Context, schema []byte, schemaType, compMode, valMode string) (string, string, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.RegisterTimeout) + defer cancel() + + response, err := sr.sendRegisterRequest(ctx, schema, schemaType) + if err != nil { + return "", "", err + } + defer response.Body.Close() + + // this needs to be before checking the status code because the response body always needs to be read + body, err := io.ReadAll(response.Body) + if err != nil { + return "", "", errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + // the schema registry returns either 200, if the new schema version is successfully inserted, or 409 if + // the given schema already exists + if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusConflict { + return "", "", errtemplates.BadHttpStatusCode(response.StatusCode) + } + + var info insertInfo + if err = json.Unmarshal(body, &info); err != nil { + return "", "", errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + + compResponse, valResponse, err := sr.sendRulesRequest(ctx, info.Id, compMode, valMode) + if err != nil { + return "", "", err + } + defer compResponse.Body.Close() + defer valResponse.Body.Close() + + // the schema registry returns 204 if the new rule is successfully added + if compResponse.StatusCode != http.StatusNoContent { + return "", "", errtemplates.BadHttpStatusCode(compResponse.StatusCode) + } + if valResponse.StatusCode != http.StatusNoContent { + return "", "", errtemplates.BadHttpStatusCode(valResponse.StatusCode) + } + + return info.Id, info.Version, nil +} + +func (sr *SchemaRegistry) sendRegisterRequest(ctx context.Context, schema []byte, schemaType string) (*http.Response, error) { + url := fmt.Sprintf("%s/apis/registry/v2/groups/%s/artifacts", sr.Url, sr.GroupID) + + request, err := httputil.Post(ctx, url, fmt.Sprintf("application/json; artifactType=%s", strings.ToUpper(schemaType)), bytes.NewBuffer(schema)) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPost, url)) + } + + return response, nil +} + +type ruleRequest struct { + Type string `json:"type"` + Config string `json:"config"` +} + +func (sr *SchemaRegistry) sendRulesRequest(ctx context.Context, id, compMode, valMode string) (*http.Response, *http.Response, error) { + url := fmt.Sprintf("%s/apis/registry/v2/groups/%s/artifacts/%s/rules", sr.Url, sr.GroupID, id) + + // this can't generate an error, so it's safe to ignore + compRule, _ := json.Marshal(ruleRequest{Type: "COMPATIBILITY", Config: strings.ToUpper(compMode)}) + request, err := httputil.Post(ctx, url, "application/json", bytes.NewBuffer(compRule)) + if err != nil { + return nil, nil, err + } + + compResponse, err := http.DefaultClient.Do(request) + if err != nil { + return nil, nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPost, url)) + } + + // this can't generate an error, so it's safe to ignore + valRule, _ := json.Marshal(ruleRequest{Type: "VALIDITY", Config: strings.ToUpper(valMode)}) + request, err = httputil.Post(ctx, url, "application/json", bytes.NewBuffer(valRule)) + if err != nil { + return nil, nil, err + } + + valResponse, err := http.DefaultClient.Do(request) + if err != nil { + return nil, nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPost, url)) + } + + return compResponse, valResponse, nil +} + +func (sr *SchemaRegistry) Update(ctx context.Context, id string, schema []byte) (string, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.UpdateTimeout) + defer cancel() + + response, err := sr.sendUpdateRequest(ctx, id, schema) + if err != nil { + return "", err + } + defer response.Body.Close() + + // this needs to be before checking the status code because the response body always needs to be read + body, err := io.ReadAll(response.Body) + if err != nil { + return "", errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + // the schema registry returns 200, if the new schema version is successfully inserted + if response.StatusCode != http.StatusOK { + return "", errtemplates.BadHttpStatusCode(response.StatusCode) + } + + var info insertInfo + if err = json.Unmarshal(body, &info); err != nil { + return "", errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + + return info.Version, nil +} + +func (sr *SchemaRegistry) sendUpdateRequest(ctx context.Context, id string, schema []byte) (*http.Response, error) { + url := fmt.Sprintf("%s/apis/registry/v2/groups/%s/artifacts/%s", sr.Url, sr.GroupID, id) + + request, err := httputil.Put(ctx, url, "application/json", bytes.NewBuffer(schema)) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPut, url)) + } + + return response, nil +} diff --git a/validator/internal/registry/apicuriosr/apicuriosr_test.go b/validator/internal/registry/apicuriosr/apicuriosr_test.go new file mode 100644 index 0000000..4e02e07 --- /dev/null +++ b/validator/internal/registry/apicuriosr/apicuriosr_test.go @@ -0,0 +1,192 @@ +package apicuriosr + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "reflect" + "testing" + "time" + + "github.com/pkg/errors" +) + +func TestNew(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + healthChecked := false + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + healthChecked = true + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + _, err := New(context.Background(), srv.URL, DefaultTimeoutSettings, "default") + if err != nil { + t.Fatal(err) + } + if !healthChecked { + t.Fatal("health check not called") + } +} + +func TestNewTimeout(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + time.Sleep(2 * time.Minute) + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + _, err := New(ctx, srv.URL, DefaultTimeoutSettings, "default") + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatal("expected timeout") + } +} + +func TestGet(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + schema := []byte("some specification") + + id, version := "1", "1" + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodGet && request.URL.Path == fmt.Sprintf("/apis/registry/v2/groups/default/artifacts/%s/versions/%s", id, version) { + _, _ = writer.Write(schema) + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + spec, err := registry.Get(context.Background(), id, version) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(schema, spec) { + t.Fatalf("expected and actual spec not the same (%s != %s)", schema, spec) + } +} + +func TestRegister(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + schema := []byte("some specification") + schemaType := "json" + + requestResponse := insertInfo{ + Id: "1", + Version: "1", + } + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodPost && request.URL.Path == "/apis/registry/v2/groups/default/artifacts" { + defer request.Body.Close() + registration, err := io.ReadAll(request.Body) + if err != nil { + t.Fatal(err) + } + if string(registration) != string(schema) { + t.Fatal("expected and actual schema not the same") + } + + writer.WriteHeader(http.StatusOK) + if err := json.NewEncoder(writer).Encode(requestResponse); err != nil { + t.Fatal(err) + } + } else if request.Method == http.MethodPost && request.URL.Path == fmt.Sprintf("/apis/registry/v2/groups/default/artifacts/%s/rules", requestResponse.Id) { + writer.WriteHeader(http.StatusNoContent) + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + id, version, err := registry.Register(context.Background(), schema, schemaType, "none", "none") + if err != nil { + t.Fatal(err) + } + + if id != requestResponse.Id || version != requestResponse.Version { + t.Fatal("response not parsed correctly") + } +} + +func TestUpdate(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + schema := []byte("some specification") + schemaId := "1" + + requestResponse := insertInfo{ + Id: schemaId, + Version: "2", + } + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodPut && request.URL.Path == fmt.Sprintf("/apis/registry/v2/groups/default/artifacts/%s", schemaId) { + defer request.Body.Close() + registration, err := io.ReadAll(request.Body) + if err != nil { + t.Fatal(err) + } + if string(registration) != string(schema) { + t.Fatal("expected and actual schema not the same") + } + + writer.WriteHeader(http.StatusOK) + if err := json.NewEncoder(writer).Encode(requestResponse); err != nil { + t.Fatal(err) + } + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + version, err := registry.Update(context.Background(), schemaId, schema) + if err != nil { + t.Fatal(err) + } + + if version != requestResponse.Version { + t.Fatal("response not parsed correctly") + } +} diff --git a/validator/internal/registry/apicuriosr/dto.go b/validator/internal/registry/apicuriosr/dto.go new file mode 100644 index 0000000..4b6507c --- /dev/null +++ b/validator/internal/registry/apicuriosr/dto.go @@ -0,0 +1,20 @@ +package apicuriosr + +type insertInfo struct { + Name string `json:"name"` + Description string `json:"description"` + CreatedBy string `json:"createdBy"` + CreatedOn string `json:"createdOn"` + ModifiedBy string `json:"modifiedBy"` + ModifiedOn string `json:"modifiedOn"` + Id string `json:"id"` + Version string `json:"version"` + Type string `json:"type"` + GlobalId int64 `json:"globalId"` + State string `json:"state"` + GroupId string `json:"groupId"` + ContentId int64 `json:"contentId"` + Labels []string `json:"labels"` + Properties []interface{} `json:"properties"` + References []interface{} `json:"references"` +} diff --git a/validator/internal/registry/cache.go b/validator/internal/registry/cache.go new file mode 100644 index 0000000..3bd2894 --- /dev/null +++ b/validator/internal/registry/cache.go @@ -0,0 +1,69 @@ +package registry + +import ( + "context" + + lru "github.com/hashicorp/golang-lru" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "golang.org/x/sync/singleflight" +) + +var cachedHitsCount = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "schema_registry", + Name: "schemas_cache_hits_total", + Help: "The total number of schemas cache hits", +}) + +// cached decorates SchemaRegistry with a lru cache. +type cached struct { + SchemaRegistry + cache *lru.TwoQueueCache + group singleflight.Group +} + +// newCache returns a new cached. +func newCache(registry SchemaRegistry, size int) (*cached, error) { + cache, err := lru.New2Q(size) + if err != nil { + return nil, err + } + + return &cached{ + SchemaRegistry: registry, + cache: cache, + group: singleflight.Group{}, + }, nil +} + +// Get overrides the SchemaRegistry.Get method, caching each call to the underlying SchemaRegistry, while also +// making sure there's only one inflight request for the same key (if multiple goroutines request the same schema, +// only one request is actually sent down, the rest wait for the first one to share its result). +func (c *cached) Get(ctx context.Context, id, version string) ([]byte, error) { + // this should be faster than string concatenation + arrKey := [2]string{id, version} + + if v, ok := c.cache.Get(arrKey); ok { + // cache hit + cachedHitsCount.Inc() + return v.([]byte), nil + } + + // cache miss, we need a string version of the key to satisfy the singleflight.Group method signature + key := id + "_" + version + + v, err, _ := c.group.Do(key, func() (interface{}, error) { + schema, err := c.SchemaRegistry.Get(ctx, id, version) + if err != nil { + return nil, err + } + + c.cache.Add(arrKey, schema) + + return schema, nil + }) + if err != nil { + return nil, err + } + return v.([]byte), nil +} diff --git a/validator/internal/registry/cache_test.go b/validator/internal/registry/cache_test.go new file mode 100644 index 0000000..c54581d --- /dev/null +++ b/validator/internal/registry/cache_test.go @@ -0,0 +1,57 @@ +package registry + +import ( + "bytes" + "context" + "testing" + + "github.com/pkg/errors" +) + +func TestCacheGet(t *testing.T) { + t.Run("get returns the correct result", func(t *testing.T) { + sr := NewMock() + c, err := newCache(sr, 10) + if err != nil { + t.Error(err) + } + + id, version := "1", "1" + schema := []byte("schema stored in the registry") + sr.SetGetResponse(id, version, schema, nil) + + result, err := c.Get(context.Background(), id, version) + if err != nil { + t.Error(err) + } + + if !bytes.Equal(result, schema) { + t.Error("result and actual not the same") + } + + result1, err := c.Get(context.Background(), id, version) + if err != nil { + t.Error(err) + } + + if !bytes.Equal(result1, schema) { + t.Error("cached result and actual not the same") + } + }) + + t.Run("error propagation", func(t *testing.T) { + sr := NewMock() + c, err := newCache(sr, 10) + if err != nil { + t.Error(err) + } + + id, version := "1", "1" + sr.SetGetResponse(id, version, nil, errors.New("oops")) + + _, err = c.Get(context.Background(), id, version) + if err == nil { + t.Error("expected an error") + } + }) +} diff --git a/validator/internal/registry/janitorsr/dto.go b/validator/internal/registry/janitorsr/dto.go new file mode 100644 index 0000000..4256dd6 --- /dev/null +++ b/validator/internal/registry/janitorsr/dto.go @@ -0,0 +1,30 @@ +package janitorsr + +import "time" + +type VersionDetails struct { + VersionID string `json:"version_id,omitempty"` + Version string `json:"version"` + SchemaID string `json:"schema_id"` + Specification string `json:"specification"` + Description string `json:"description"` + SchemaHash string `json:"schema_hash"` + CreatedAt time.Time `json:"created_at"` + VersionDeactivated bool `json:"version_deactivated"` +} + +type registrationRequest struct { + Description string `json:"description"` + Specification string `json:"specification"` + Name string `json:"name"` + SchemaType string `json:"schema_type"` + CompatibilityMode string `json:"compatibility_mode"` + ValidityMode string `json:"validity_mode"` + GroupId string `json:"publisher_id"` +} + +type insertInfo struct { + Id string `json:"identification"` + Version string `json:"version"` + Message string `json:"message"` +} diff --git a/validator/internal/registry/janitorsr/janitorsr.go b/validator/internal/registry/janitorsr/janitorsr.go new file mode 100644 index 0000000..24e505b --- /dev/null +++ b/validator/internal/registry/janitorsr/janitorsr.go @@ -0,0 +1,286 @@ +package janitorsr + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/errtemplates" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/registry" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-retry/pkg/retry" + + "github.com/pkg/errors" +) + +// SchemaRegistry is a proxy for communicating with the janitor schema registry server. +type SchemaRegistry struct { + Url string + Timeouts TimeoutSettings + GroupID string +} + +// TimeoutSettings defines the maximum amount of time for each get, register or update request. +type TimeoutSettings struct { + GetTimeout time.Duration + RegisterTimeout time.Duration + UpdateTimeout time.Duration +} + +var DefaultTimeoutSettings = TimeoutSettings{ + GetTimeout: 4 * time.Second, + RegisterTimeout: 10 * time.Second, + UpdateTimeout: 10 * time.Second, +} + +// New returns an instance of SchemaRegistry. +// +// Performs a health check to see if the schema registry is available, retrying periodically until the context is cancelled +// or the health check succeeds. +func New(ctx context.Context, url string, timeouts TimeoutSettings, groupID string) (*SchemaRegistry, error) { + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach schema registry at %s failed", url) + } + + return &SchemaRegistry{ + Url: url, + Timeouts: timeouts, + GroupID: groupID, + }, nil +} + +func (sr *SchemaRegistry) Get(ctx context.Context, id, version string) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.GetTimeout) + defer cancel() + + response, err := sr.sendGetRequest(ctx, id, version) + if err != nil { + return nil, err + } + defer func() { + err := response.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + if response.StatusCode != http.StatusOK { + if response.StatusCode == http.StatusNotFound { + return nil, errors.Wrapf(registry.ErrNotFound, "fetching schema %s/%s failed", id, version) + } + return nil, errors.Wrapf(errtemplates.BadHttpStatusCode(response.StatusCode), "fetching schema %s/%s resulted in a bad status code", id, version) + } + + var schema VersionDetails + if err = json.Unmarshal(body, &schema); err != nil { + return nil, errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + + specification, err := base64.StdEncoding.DecodeString(schema.Specification) + if err != nil { + return nil, errors.Wrap(err, "decoding schema failed") + } + + return specification, nil +} + +func (sr *SchemaRegistry) sendGetRequest(ctx context.Context, id, version string) (*http.Response, error) { + url := fmt.Sprintf("%s/schemas/%s/versions/%s", sr.Url, id, version) + + request, err := httputil.Get(ctx, url) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodGet, url)) + } + + return response, nil +} + +// GetLatest returns latest version of schema +// +// Unlike Get, Register and Update methods, GetLatest returns whole schema with metadata, and not only +// schema specification +func (sr *SchemaRegistry) GetLatest(ctx context.Context, id string) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.GetTimeout) + defer cancel() + + response, err := sr.sendGetLatestRequest(ctx, id) + if err != nil { + return nil, err + } + defer func() { + err := response.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + if response.StatusCode != http.StatusOK { + if response.StatusCode == http.StatusNotFound { + return nil, errors.Wrapf(registry.ErrNotFound, "fetching schema %s/latest failed", id) + } + return nil, errors.Wrapf(errtemplates.BadHttpStatusCode(response.StatusCode), "fetching schema %s/latest resulted in a bad status code", id) + } + + return body, nil +} + +func (sr *SchemaRegistry) sendGetLatestRequest(ctx context.Context, id string) (*http.Response, error) { + url := fmt.Sprintf("%s/schemas/%s/versions/latest", sr.Url, id) + + request, err := httputil.Get(ctx, url) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodGet, url)) + } + + return response, nil +} + +func (sr *SchemaRegistry) Register(ctx context.Context, schema []byte, schemaType, compMode, valMode string) (string, string, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.RegisterTimeout) + defer cancel() + + response, err := sr.sendRegisterRequest(ctx, schema, schemaType, compMode, valMode) + if err != nil { + return "", "", err + } + defer func() { + err := response.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + + // this needs to be before checking the status code because the response body always needs to be read + body, err := io.ReadAll(response.Body) + if err != nil { + return "", "", errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + // the schema registry returns either 201, if the new schema version is successfully inserted, or 409 if + // the given schema already exists + if response.StatusCode != http.StatusCreated && response.StatusCode != http.StatusConflict { + return "", "", errtemplates.BadHttpStatusCode(response.StatusCode) + } + + var info insertInfo + if err = json.Unmarshal(body, &info); err != nil { + return "", "", errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + + return info.Id, info.Version, nil +} + +func (sr *SchemaRegistry) sendRegisterRequest(ctx context.Context, schema []byte, schemaType, compMode, valMode string) (*http.Response, error) { + // this can't generate an error, so it's safe to ignore + data, _ := json.Marshal(registrationRequest{ + Specification: string(schema), + SchemaType: schemaType, + CompatibilityMode: compMode, + ValidityMode: valMode, + GroupId: sr.GroupID, + }) + + url := fmt.Sprintf("%s/schemas", sr.Url) + + request, err := httputil.Post(ctx, url, "application/json", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPost, url)) + } + + return response, nil +} + +type schemaUpdateRequest struct { + Description string `json:"description"` + Specification string `json:"specification"` +} + +func (sr *SchemaRegistry) Update(ctx context.Context, id string, schema []byte) (string, error) { + ctx, cancel := context.WithTimeout(ctx, sr.Timeouts.UpdateTimeout) + defer cancel() + + response, err := sr.sendUpdateRequest(ctx, id, schema) + if err != nil { + return "", err + } + defer func() { + err := response.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + + // this needs to be before checking the status code because the response body always needs to be read + body, err := io.ReadAll(response.Body) + if err != nil { + return "", errors.Wrap(err, errtemplates.ReadingResponseBodyFailed) + } + + // the schema registry returns either 200, if the new schema version is successfully inserted, or 409 if + // the given schema already exists + if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusConflict { + return "", errtemplates.BadHttpStatusCode(response.StatusCode) + } + + var info insertInfo + if err = json.Unmarshal(body, &info); err != nil { + return "", errors.Wrap(err, errtemplates.UnmarshallingJSONFailed) + } + + return info.Version, nil +} + +func (sr *SchemaRegistry) sendUpdateRequest(ctx context.Context, id string, schema []byte) (*http.Response, error) { + // this can't generate an error, so it's safe to ignore + data, _ := json.Marshal(schemaUpdateRequest{Specification: string(schema)}) + + url := fmt.Sprintf("%s/schemas/%s", sr.Url, id) + + request, err := httputil.Put(ctx, url, "application/json", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, errtemplates.HttpRequestToUrlFailed(http.MethodPut, url)) + } + + return response, nil +} diff --git a/validator/internal/registry/janitorsr/janitorsr_test.go b/validator/internal/registry/janitorsr/janitorsr_test.go new file mode 100644 index 0000000..70788c5 --- /dev/null +++ b/validator/internal/registry/janitorsr/janitorsr_test.go @@ -0,0 +1,194 @@ +package janitorsr + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "log" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/pkg/errors" +) + +func TestNew(t *testing.T) { + healthChecked := false + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + healthChecked = true + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + _, err := New(context.Background(), srv.URL, DefaultTimeoutSettings, "default") + if err != nil { + t.Fatal(err) + } + if !healthChecked { + t.Fatal("health check not called") + } +} + +func TestNewTimeout(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + time.Sleep(2 * time.Minute) + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + _, err := New(ctx, srv.URL, DefaultTimeoutSettings, "default") + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatal("expected timeout") + } +} + +func TestGet(t *testing.T) { + schema := []byte("some specification") + + details := VersionDetails{ + VersionID: "1", + Version: "1", + SchemaID: "1", + Specification: base64.StdEncoding.EncodeToString(schema), + Description: "some description", + SchemaHash: "some schema hash", + CreatedAt: time.Now(), + VersionDeactivated: false, + } + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodGet && request.URL.Path == fmt.Sprintf("/schemas/%s/versions/%s", details.SchemaID, details.Version) { + _ = json.NewEncoder(writer).Encode(details) + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + spec, err := registry.Get(context.Background(), details.SchemaID, details.Version) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(schema, spec) { + t.Fatalf("expected and actual spec not the same (%s != %s)", schema, spec) + } +} + +func TestRegister(t *testing.T) { + schema := []byte("some specification") + schemaType := "json" + + requestResponse := insertInfo{ + Id: "1", + Version: "1", + } + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodPost && request.URL.Path == "/schemas" { + defer func() { + err := request.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + var registration registrationRequest + if err := json.NewDecoder(request.Body).Decode(®istration); err != nil { + t.Fatal(err) + } + if registration.Specification != string(schema) { + t.Fatal("expected and actual schema not the same") + } + + writer.WriteHeader(http.StatusCreated) + if err := json.NewEncoder(writer).Encode(requestResponse); err != nil { + t.Fatal(err) + } + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + id, version, err := registry.Register(context.Background(), schema, schemaType, "none", "none") + if err != nil { + t.Fatal(err) + } + + if id != requestResponse.Id || version != requestResponse.Version { + t.Fatal("response not parsed correctly") + } +} + +func TestUpdate(t *testing.T) { + schema := []byte("some specification") + schemaId := "1" + + requestResponse := insertInfo{ + Id: schemaId, + Version: "2", + } + + srv := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.Method == http.MethodPut && request.URL.Path == fmt.Sprintf("/schemas/%s", schemaId) { + defer func() { + err := request.Body.Close() + if err != nil { + log.Fatal(err) + } + }() + var registration registrationRequest + if err := json.NewDecoder(request.Body).Decode(®istration); err != nil { + t.Fatal(err) + } + if registration.Specification != string(schema) { + t.Fatal("expected and actual schema not the same") + } + + writer.WriteHeader(http.StatusOK) + if err := json.NewEncoder(writer).Encode(requestResponse); err != nil { + t.Fatal(err) + } + } else { + t.Fatal("wrong endpoint called") + } + })) + defer srv.Close() + + registry := SchemaRegistry{ + Url: srv.URL, + Timeouts: DefaultTimeoutSettings, + } + + version, err := registry.Update(context.Background(), schemaId, schema) + if err != nil { + t.Fatal(err) + } + + if version != requestResponse.Version { + t.Fatal("response not parsed correctly") + } +} diff --git a/validator/internal/registry/janitorsr/testdata/schema.avsc b/validator/internal/registry/janitorsr/testdata/schema.avsc new file mode 100644 index 0000000..bda4977 --- /dev/null +++ b/validator/internal/registry/janitorsr/testdata/schema.avsc @@ -0,0 +1,35 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "age", + "type": "int" + }, + { + "name": "collection", + "type": { + "type": "array", + "items": "string" + } + }, + { + "name": "foo", + "type": { + "name": "foo", + "type": "record", + "fields": [ + { + "name": "bar", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/validator/internal/registry/janitorsr/testdata/schema.csvs b/validator/internal/registry/janitorsr/testdata/schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/registry/janitorsr/testdata/schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/registry/janitorsr/testdata/schema.json b/validator/internal/registry/janitorsr/testdata/schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/registry/janitorsr/testdata/schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/registry/janitorsr/testdata/schema.xsd b/validator/internal/registry/janitorsr/testdata/schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/registry/janitorsr/testdata/schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/registry/mock.go b/validator/internal/registry/mock.go new file mode 100644 index 0000000..87eadf7 --- /dev/null +++ b/validator/internal/registry/mock.go @@ -0,0 +1,93 @@ +package registry + +import "context" + +type Mock struct { + getSchemaResponse map[string]mockGetSchemaResponse + getLatestSchemaResponse map[string]mockGetLatestSchemaResponse + registrationResponse map[string]mockRegisterResponse + updateResponse map[string]mockUpdateResponse +} + +type mockGetSchemaResponse struct { + schema []byte + err error +} + +type mockGetLatestSchemaResponse struct { + schema []byte + err error +} + +type mockRegisterResponse struct { + id string + version string + err error +} + +type mockUpdateResponse struct { + version string + err error +} + +func NewMock() *Mock { + return &Mock{ + getSchemaResponse: map[string]mockGetSchemaResponse{}, + getLatestSchemaResponse: map[string]mockGetLatestSchemaResponse{}, + registrationResponse: map[string]mockRegisterResponse{}, + updateResponse: map[string]mockUpdateResponse{}, + } +} + +func (m *Mock) SetGetResponse(id, version string, schema []byte, err error) { + key := id + "_" + version + m.getSchemaResponse[key] = mockGetSchemaResponse{ + schema: schema, + err: err, + } +} + +func (m *Mock) Get(_ context.Context, id, version string) ([]byte, error) { + key := id + "_" + version + response := m.getSchemaResponse[key] + return response.schema, response.err +} + +func (m *Mock) SetGetLatestResponse(id string, schema []byte, err error) { + key := id + m.getLatestSchemaResponse[key] = mockGetLatestSchemaResponse{ + schema: schema, + err: err, + } +} + +func (m *Mock) GetLatest(_ context.Context, id string) ([]byte, error) { + key := id + response := m.getLatestSchemaResponse[key] + return response.schema, response.err +} + +func (m *Mock) SetRegisterResponse(schema []byte, id, version string, err error) { + m.registrationResponse[string(schema)] = mockRegisterResponse{ + id: id, + version: version, + err: err, + } +} + +func (m *Mock) Register(_ context.Context, schema []byte, _, _, _ string) (string, string, error) { + response := m.registrationResponse[string(schema)] + return response.id, response.version, response.err +} + +func (m *Mock) SetUpdateResponse(id, version string, err error) { + m.updateResponse[id] = mockUpdateResponse{ + version: version, + err: err, + } +} + +func (m *Mock) Update(_ context.Context, id string, _ []byte) (string, error) { + response := m.updateResponse[id] + return response.version, response.err +} diff --git a/validator/internal/registry/registry.go b/validator/internal/registry/registry.go new file mode 100644 index 0000000..cb24aa0 --- /dev/null +++ b/validator/internal/registry/registry.go @@ -0,0 +1,35 @@ +// Package registry exposes common functionalities of all schema registries. +package registry + +import ( + "context" + + "github.com/pkg/errors" +) + +var ErrNotFound = errors.New("no schema registered under given id and version") + +// SchemaRegistry models schema registries. +type SchemaRegistry interface { + // Get returns the schema stored under the given id and version. + // If no schema exists, ErrNotFound must be returned. + Get(ctx context.Context, id, version string) ([]byte, error) + // Get(ctx context.Context, id, version string) ([]byte, error) + + // GetLatest returns the whole schema, including the metadata and all versions + // If no schema exists under specified id, ErrNotFound must be returned. + GetLatest(ctx context.Context, id string) ([]byte, error) + + // Register register a new schema and returns the id and version it was registered under. + Register(ctx context.Context, schema []byte, schemaType, compMode, valMode string) (string, string, error) + // Register(ctx context.Context, schema []byte, schemaType, compMode, valMode string) (string, string, error) + + // Update updates the schema stored under the given id, returns the version it was registered under. + Update(ctx context.Context, id string, schema []byte) (string, error) + // Update(ctx context.Context, id string, schema []byte) (string, error) +} + +// WithCache decorates the given SchemaRegistry with an in-memory cache of the given size. +func WithCache(registry SchemaRegistry, size int) (SchemaRegistry, error) { + return newCache(registry, size) +} diff --git a/validator/internal/schemagen/cmd.go b/validator/internal/schemagen/cmd.go new file mode 100644 index 0000000..827ece3 --- /dev/null +++ b/validator/internal/schemagen/cmd.go @@ -0,0 +1,23 @@ +package schemagen + +import ( + "bytes" + "os/exec" + + "github.com/pkg/errors" +) + +// ExternalCmdSchemaGenerator generates the schema by calling the given cmd and passing the data to its stdin. +func ExternalCmdSchemaGenerator(cmd *exec.Cmd, data []byte) ([]byte, error) { + cmd.Stdin = bytes.NewReader(data) + + output, err := cmd.CombinedOutput() + if err != nil { + return nil, errors.Wrap(err, string(output)) + } + if len(output) == 0 { + return nil, ErrDeadletter + } + + return output, nil +} diff --git a/validator/internal/schemagen/cmd_test.go b/validator/internal/schemagen/cmd_test.go new file mode 100644 index 0000000..62a99a0 --- /dev/null +++ b/validator/internal/schemagen/cmd_test.go @@ -0,0 +1,19 @@ +package schemagen + +import ( + "os" + "os/exec" + "testing" +) + +func TestOverScriptSchemaGenerator(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + cmd := exec.Command("python", "json/json_schema_gen.py") + _, err := ExternalCmdSchemaGenerator(cmd, []byte("{\n \"id\": 100,\n \"first_name\": \"syn jason\",\n \"last_name\": \"syn oblak\",\n \"email\": \"jsonsmail\"\n}")) + if err != nil { + t.Fatal(err) + } +} diff --git a/validator/internal/schemagen/csv/csv.go b/validator/internal/schemagen/csv/csv.go new file mode 100644 index 0000000..10b01e2 --- /dev/null +++ b/validator/internal/schemagen/csv/csv.go @@ -0,0 +1,49 @@ +package csv + +import ( + "bytes" + "encoding/csv" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + "io" + "strconv" + "strings" +) + +func New() schemagen.Generator { + return schemagen.Func(func(data []byte) ([]byte, error) { + reader := csv.NewReader(bytes.NewReader(data)) + + reader.ReuseRecord = true + reader.LazyQuotes = true + reader.Comma = ',' + + header, err := reader.Read() + if err != nil { + return nil, schemagen.ErrDeadletter + } + + schema := parseHeaderIntoSchema(header) + + for { + _, err = reader.Read() + if err != nil { + if err == io.EOF { + return schema, nil + } + return nil, schemagen.ErrDeadletter + } + } + }) +} + +func parseHeaderIntoSchema(header []string) []byte { + var schemaBuilder bytes.Buffer + + schemaBuilder.Write([]byte("version 1.0\n")) + schemaBuilder.Write([]byte("@totalColumns " + strconv.Itoa(len(header)) + "\n")) + for _, key := range header { + schemaBuilder.Write([]byte(strings.Trim(key, " ") + ":\n")) + } + + return schemaBuilder.Bytes() +} diff --git a/validator/internal/schemagen/csv/csv_test.go b/validator/internal/schemagen/csv/csv_test.go new file mode 100644 index 0000000..eecf98d --- /dev/null +++ b/validator/internal/schemagen/csv/csv_test.go @@ -0,0 +1,63 @@ +package csv + +import ( + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + "github.com/pkg/errors" + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +func TestGenerate(t *testing.T) { + gen := New() + + tt := []struct { + name string + dataFilename string + schemaFilename string + deadletter bool + }{ + {"data-1", "data-1.csv", "schema-1.csvs", false}, + {"deadletter-1", "deadletter-1-data.csv", "", true}, + {"deadletter-2", "deadletter-2-data.csv", "", true}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.dataFilename)) + if err != nil { + t.Errorf("data read error: %s", err) + } + + generated, err := gen.Generate(data) + if tc.deadletter { + if !errors.Is(err, schemagen.ErrDeadletter) { + t.Error("deadletter expected") + } + } else { + if err != nil { + t.Errorf("validator error: %s", err) + } + + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + + schemaStr := string(schema) + schemaStr = strings.ReplaceAll(schemaStr, "\r\n", "\n") + generatedStr := string(generated) + + if schemaStr != generatedStr { + t.Errorf("expected and generated schema not the same") + } + } + }) + } +} diff --git a/validator/internal/schemagen/csv/testdata/data-1.csv b/validator/internal/schemagen/csv/testdata/data-1.csv new file mode 100644 index 0000000..59c43f9 --- /dev/null +++ b/validator/internal/schemagen/csv/testdata/data-1.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,21,m +jure,19,f +stipano,57,m diff --git a/validator/internal/schemagen/csv/testdata/deadletter-1-data.csv b/validator/internal/schemagen/csv/testdata/deadletter-1-data.csv new file mode 100644 index 0000000..dd64322 --- /dev/null +++ b/validator/internal/schemagen/csv/testdata/deadletter-1-data.csv @@ -0,0 +1,6 @@ +{ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} diff --git a/validator/internal/schemagen/csv/testdata/deadletter-2-data.csv b/validator/internal/schemagen/csv/testdata/deadletter-2-data.csv new file mode 100644 index 0000000..d9ebf19 --- /dev/null +++ b/validator/internal/schemagen/csv/testdata/deadletter-2-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,m +jure,19 +stipano,57,m diff --git a/validator/internal/schemagen/csv/testdata/schema-1.csvs b/validator/internal/schemagen/csv/testdata/schema-1.csvs new file mode 100644 index 0000000..85bd1f5 --- /dev/null +++ b/validator/internal/schemagen/csv/testdata/schema-1.csvs @@ -0,0 +1,5 @@ +version 1.0 +@totalColumns 3 +name: +age: +gender: diff --git a/validator/internal/schemagen/json/json.go b/validator/internal/schemagen/json/json.go new file mode 100644 index 0000000..672ce58 --- /dev/null +++ b/validator/internal/schemagen/json/json.go @@ -0,0 +1,16 @@ +package json + +import ( + "os/exec" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" +) + +func New(filename string) schemagen.Generator { + return schemagen.Func(func(data []byte) ([]byte, error) { + // #nosec G204 this would usually be a security concern because of remote code execution, + // but it's fine here since we execute a python script from a file, so the attacker would need to have + // full access to the vm to execute the script, and in that case, they could just execute the script themselves + return schemagen.ExternalCmdSchemaGenerator(exec.Command("python", filename), data) + }) +} diff --git a/validator/internal/schemagen/json/json_schema_gen.py b/validator/internal/schemagen/json/json_schema_gen.py new file mode 100644 index 0000000..8696871 --- /dev/null +++ b/validator/internal/schemagen/json/json_schema_gen.py @@ -0,0 +1,22 @@ +import json + +import sys +from genson import SchemaBuilder + + +def main(): + data_file = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin + data = data_file.read() + to_add = {"additionalProperties": False} + builder = SchemaBuilder() + try: + builder.add_schema(to_add) + builder.add_object(json.loads(data)) + result_schema = builder.to_json(indent=2) + except ValueError: + result_schema = "" + sys.stdout.write(result_schema) + + +if __name__ == "__main__": + main() diff --git a/validator/internal/schemagen/json/json_test.go b/validator/internal/schemagen/json/json_test.go new file mode 100644 index 0000000..05710f7 --- /dev/null +++ b/validator/internal/schemagen/json/json_test.go @@ -0,0 +1,62 @@ +package json + +import ( + "bytes" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/schemagen" + + "github.com/pkg/errors" +) + +func TestGenerate(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + gen := New("json_schema_gen.py") + + tt := []struct { + name string + dataFilename string + schemaFilename string + deadletter bool + }{ + {"deadletter-1", "deadletter-1-data.json", "", true}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.dataFilename)) + if err != nil { + t.Errorf("data read error: %s", err) + } + + generated, err := gen.Generate(data) + if tc.deadletter { + if !errors.Is(err, schemagen.ErrDeadletter) { + t.Error("deadletter expected") + } + } else { + if err != nil { + t.Errorf("validator error: %s", err) + } + + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + if !bytes.Equal(schema, generated) { + t.Errorf("expected and generated schema not the same") + } + } + }) + } +} diff --git a/validator/internal/schemagen/json/testdata/deadletter-1-data.json b/validator/internal/schemagen/json/testdata/deadletter-1-data.json new file mode 100644 index 0000000..ec3bdf2 --- /dev/null +++ b/validator/internal/schemagen/json/testdata/deadletter-1-data.json @@ -0,0 +1,5 @@ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} diff --git a/validator/internal/schemagen/schemagen.go b/validator/internal/schemagen/schemagen.go new file mode 100644 index 0000000..ba1dd7b --- /dev/null +++ b/validator/internal/schemagen/schemagen.go @@ -0,0 +1,22 @@ +// Package schemagen exposes common functionalities of all schema generators. +package schemagen + +import "github.com/pkg/errors" + +// ErrDeadletter is a special error type to mark that schema generation was unsuccessful, +// due to the fact that the given message isn't even the right format. +var ErrDeadletter = errors.New("deadletter") + +// Generator defines schema generators. +type Generator interface { + // Generate takes data of some assumed format and returns the schema inferred from that data + Generate([]byte) ([]byte, error) +} + +// Func convenience type which is the functional equivalent of Generator. +type Func func(data []byte) ([]byte, error) + +// Generate implements Generate by forwarding the call to the underlying Func. +func (f Func) Generate(data []byte) ([]byte, error) { + return f(data) +} diff --git a/validator/internal/validator/avro/avro.go b/validator/internal/validator/avro/avro.go new file mode 100644 index 0000000..2aad657 --- /dev/null +++ b/validator/internal/validator/avro/avro.go @@ -0,0 +1,30 @@ +package avro + +import ( + "bytes" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/hamba/avro" +) + +func New() validator.Validator { + return validator.Func(func(message, schema []byte, _, _ string) (bool, error) { + parsedSchema, err := avro.Parse(string(schema)) + if err != nil { + return false, validator.ErrDeadletter + } + + var data interface{} + if err = avro.Unmarshal(parsedSchema, message, &data); err != nil { + return false, nil + } + + reserializedMessage, err := avro.Marshal(parsedSchema, data) + if err != nil { + return false, nil + } + + return bytes.Equal(reserializedMessage, message), nil + }) +} diff --git a/validator/internal/validator/avro/avro_test.go b/validator/internal/validator/avro/avro_test.go new file mode 100644 index 0000000..dfea54b --- /dev/null +++ b/validator/internal/validator/avro/avro_test.go @@ -0,0 +1,209 @@ +package avro + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/hamba/avro" +) + +func TestAvroValidator_Validate(t *testing.T) { + avroV := New() + + tt := []struct { + name string + data interface{} + serializationSchemaFilename string + validationSchemaFilename string + valid bool + }{ + { + "valid-1", + struct { + Name string `avro:"name"` + Age int `avro:"age"` + Collection interface{} `avro:"collection"` + Foo interface{} `avro:"foo"` + }{ + "Syntio", + 4, + []string{"data engineering", "avro"}, + struct { + Bar string `avro:"bar"` + }{ + "hello world", + }, + }, + "valid-1-serialization-schema.avsc", + "valid-1-validation-schema.avsc", + true, + }, + { + "invalid-1", + struct { + Name string `avro:"name"` + Age int `avro:"age"` + Collection interface{} `avro:"collection"` + }{ + "Syntio", + 4, + []string{"data engineering", "avro"}, + }, + "invalid-1-serialization-schema.avsc", + "invalid-1-validation-schema.avsc", + false, + }, + { + "invalid-2", + struct { + Age int `avro:"age"` + Tall bool `avro:"tall"` + Handsome bool `avro:"handsome"` + }{ + 2, + true, + true, + }, + "invalid-2-serialization-schema.avsc", + "invalid-2-validation-schema.avsc", + // IT IS FUNDAMENTALLY IMPOSSIBLE TO COVER THIS CASE + // BECAUSE OF THE WAY AVRO WORKS + // THIS IS A KNOWN AND ACCEPTABLE LIMITATION + true, + }, + { + "invalid-3", + struct { + Age int `avro:"age"` + Tall bool `avro:"tall"` + Handsome bool `avro:"handsome"` + }{ + 2, + true, + false, + }, + "invalid-3-serialization-schema.avsc", + "invalid-3-validation-schema.avsc", + // IT IS FUNDAMENTALLY IMPOSSIBLE TO COVER THIS CASE + // BECAUSE OF THE WAY AVRO WORKS + // THIS IS A KNOWN AND ACCEPTABLE LIMITATION + true, + }, + { + "invalid-4", + struct { + Age int `avro:"age"` + Height int `avro:"height"` + Length int `avro:"length"` + }{ + 4, + 64, + -65, + }, + "invalid-4-serialization-schema.avsc", + "invalid-4-validation-schema.avsc", + // IT IS FUNDAMENTALLY IMPOSSIBLE TO COVER THIS CASE + // BECAUSE OF THE WAY AVRO WORKS + // THIS IS A KNOWN AND ACCEPTABLE LIMITATION + true, + }, + { + "invalid-5", + struct { + Age int `avro:"age"` + Pos0 int `avro:"pos0"` + Pos1 int `avro:"pos1"` + Pos2 int `avro:"pos2"` + Pos3 int `avro:"pos3"` + Pos4 int `avro:"pos4"` + }{ + 5, + // 36, // H + // -35, // E + // 38, // L + // 38, // L + // -40, // O + 40, // P + -44, // W + 39, // N + -35, // E + 34, // D + }, + "invalid-5-serialization-schema.avsc", + "invalid-5-validation-schema.avsc", + // IT IS FUNDAMENTALLY IMPOSSIBLE TO COVER THIS CASE + // BECAUSE OF THE WAY AVRO WORKS + // THIS IS A KNOWN AND ACCEPTABLE LIMITATION + true, + }, + { + "invalid-6", + struct { + Pos1 string `avro:"pos1"` + Pos0 string `avro:"pos0"` + }{ + "SYNTIO!", + "HELLO, ", + }, + "invalid-6-serialization-schema.avsc", + "invalid-6-validation-schema.avsc", + // IT IS FUNDAMENTALLY IMPOSSIBLE TO COVER THIS CASE + // BECAUSE OF THE WAY AVRO WORKS + // THIS IS A KNOWN AND ACCEPTABLE LIMITATION + true, + }, + { + "invalid-7", + struct { + Pos0 string `avro:"pos0"` + }{ + "HELLO", + }, + "invalid-7-serialization-schema.avsc", + "invalid-7-validation-schema.avsc", + false, + }, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + serializationSchemaTxt, err := os.ReadFile(filepath.Join(testdataDir, tc.serializationSchemaFilename)) + if err != nil { + t.Fatalf("serialization schema read error") + } + + serializationSchema, err := avro.Parse(string(serializationSchemaTxt)) + if err != nil { + t.Fatalf("avro serialization parse error: %s", err) + } + + data, err := avro.Marshal(serializationSchema, tc.data) + if err != nil { + t.Fatalf("avro serialization error: %s", err) + } + + validationSchema, err := os.ReadFile(filepath.Join(testdataDir, tc.validationSchemaFilename)) + if err != nil { + t.Fatalf("validation schema read error") + } + + valid, err := avroV.Validate(data, validationSchema, "", "") + if err != nil { + t.Fatalf("validator error: %s", err) + } + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + }) + } +} diff --git a/validator/internal/validator/avro/testdata/invalid-1-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-1-serialization-schema.avsc new file mode 100644 index 0000000..fa04ae2 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-1-serialization-schema.avsc @@ -0,0 +1,22 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "age", + "type": "int" + }, + { + "name": "collection", + "type": { + "type": "array", + "items": "string" + } + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-1-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-1-validation-schema.avsc new file mode 100644 index 0000000..bda4977 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-1-validation-schema.avsc @@ -0,0 +1,35 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "age", + "type": "int" + }, + { + "name": "collection", + "type": { + "type": "array", + "items": "string" + } + }, + { + "name": "foo", + "type": { + "name": "foo", + "type": "record", + "fields": [ + { + "name": "bar", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/validator/internal/validator/avro/testdata/invalid-2-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-2-serialization-schema.avsc new file mode 100644 index 0000000..f5bfaae --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-2-serialization-schema.avsc @@ -0,0 +1,19 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "age", + "type": "int" + }, + { + "name": "tall", + "type": "boolean" + }, + { + "name": "handsome", + "type": "boolean" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-2-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-2-validation-schema.avsc new file mode 100644 index 0000000..8437e17 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-2-validation-schema.avsc @@ -0,0 +1,11 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "bytes" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-3-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-3-serialization-schema.avsc new file mode 100644 index 0000000..f5bfaae --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-3-serialization-schema.avsc @@ -0,0 +1,19 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "age", + "type": "int" + }, + { + "name": "tall", + "type": "boolean" + }, + { + "name": "handsome", + "type": "boolean" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-3-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-3-validation-schema.avsc new file mode 100644 index 0000000..aec54f7 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-3-validation-schema.avsc @@ -0,0 +1,19 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "age", + "type": "int" + }, + { + "name": "grade", + "type": "int" + }, + { + "name": "height", + "type": "int" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-4-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-4-serialization-schema.avsc new file mode 100644 index 0000000..f585663 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-4-serialization-schema.avsc @@ -0,0 +1,19 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "age", + "type": "int" + }, + { + "name": "height", + "type": "int" + }, + { + "name": "length", + "type": "int" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-4-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-4-validation-schema.avsc new file mode 100644 index 0000000..8437e17 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-4-validation-schema.avsc @@ -0,0 +1,11 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "bytes" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-5-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-5-serialization-schema.avsc new file mode 100644 index 0000000..68fc7e8 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-5-serialization-schema.avsc @@ -0,0 +1,31 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "age", + "type": "int" + }, + { + "name": "pos0", + "type": "int" + }, + { + "name": "pos1", + "type": "int" + }, + { + "name": "pos2", + "type": "int" + }, + { + "name": "pos3", + "type": "int" + }, + { + "name": "pos4", + "type": "int" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-5-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-5-validation-schema.avsc new file mode 100644 index 0000000..52dba1d --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-5-validation-schema.avsc @@ -0,0 +1,11 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "message", + "type": "string" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-6-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-6-serialization-schema.avsc new file mode 100644 index 0000000..dd2fb24 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-6-serialization-schema.avsc @@ -0,0 +1,15 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "pos1", + "type": "string" + }, + { + "name": "pos0", + "type": "string" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-6-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-6-validation-schema.avsc new file mode 100644 index 0000000..701ce27 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-6-validation-schema.avsc @@ -0,0 +1,15 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "pos0", + "type": "string" + }, + { + "name": "pos1", + "type": "string" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-7-serialization-schema.avsc b/validator/internal/validator/avro/testdata/invalid-7-serialization-schema.avsc new file mode 100644 index 0000000..2fbe0d0 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-7-serialization-schema.avsc @@ -0,0 +1,11 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "pos0", + "type": "string" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/invalid-7-validation-schema.avsc b/validator/internal/validator/avro/testdata/invalid-7-validation-schema.avsc new file mode 100644 index 0000000..701ce27 --- /dev/null +++ b/validator/internal/validator/avro/testdata/invalid-7-validation-schema.avsc @@ -0,0 +1,15 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "pos0", + "type": "string" + }, + { + "name": "pos1", + "type": "string" + } + ] +} diff --git a/validator/internal/validator/avro/testdata/valid-1-serialization-schema.avsc b/validator/internal/validator/avro/testdata/valid-1-serialization-schema.avsc new file mode 100644 index 0000000..bda4977 --- /dev/null +++ b/validator/internal/validator/avro/testdata/valid-1-serialization-schema.avsc @@ -0,0 +1,35 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "age", + "type": "int" + }, + { + "name": "collection", + "type": { + "type": "array", + "items": "string" + } + }, + { + "name": "foo", + "type": { + "name": "foo", + "type": "record", + "fields": [ + { + "name": "bar", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/validator/internal/validator/avro/testdata/valid-1-validation-schema.avsc b/validator/internal/validator/avro/testdata/valid-1-validation-schema.avsc new file mode 100644 index 0000000..bda4977 --- /dev/null +++ b/validator/internal/validator/avro/testdata/valid-1-validation-schema.avsc @@ -0,0 +1,35 @@ +{ + "name": "Test", + "type": "record", + "namespace": "hr.syntio", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "age", + "type": "int" + }, + { + "name": "collection", + "type": { + "type": "array", + "items": "string" + } + }, + { + "name": "foo", + "type": { + "name": "foo", + "type": "record", + "fields": [ + { + "name": "bar", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/validator/internal/validator/csv/csv.go b/validator/internal/validator/csv/csv.go new file mode 100644 index 0000000..8b570ab --- /dev/null +++ b/validator/internal/validator/csv/csv.go @@ -0,0 +1,68 @@ +package csv + +import ( + "bytes" + "context" + "encoding/csv" + "io" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-retry/pkg/retry" + + "github.com/pkg/errors" +) + +type Validator struct { + Url string + TimeoutBase time.Duration +} + +const DefaultTimeoutBase = 2 * time.Second + +// New returns a new validator which validates CSV messages against a schema. +// +// Performs a health check to see if the validator is available, retrying periodically until the context is cancelled +// or the health check succeeds. +func New(ctx context.Context, url string, timeoutBase time.Duration) (validator.Validator, error) { + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach csv validator at %s failed", url) + } + + return &Validator{ + Url: url, + TimeoutBase: timeoutBase, + }, nil +} + +func (v *Validator) Validate(message, schema []byte, _, _ string) (bool, error) { + if !IsCSV(message) { + return false, validator.ErrDeadletter + } + + ctx, cancel := context.WithTimeout(context.Background(), validator.EstimateHTTPTimeout(len(message), v.TimeoutBase)) + defer cancel() + + return validator.ValidateOverHTTP(ctx, message, schema, v.Url) +} + +// IsCSV checks if the given data is valid csv. +// +// The data is assumed to use ',' as delimiter. +func IsCSV(data []byte) bool { + reader := csv.NewReader(bytes.NewReader(data)) + + reader.ReuseRecord = true + reader.Comma = ',' + reader.LazyQuotes = true + + for { + _, err := reader.Read() + if err != nil { + return err == io.EOF + } + } +} diff --git a/validator/internal/validator/csv/csv_test.go b/validator/internal/validator/csv/csv_test.go new file mode 100644 index 0000000..1e2d20b --- /dev/null +++ b/validator/internal/validator/csv/csv_test.go @@ -0,0 +1,121 @@ +package csv + +import ( + "context" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/pkg/errors" +) + +func TestNew(t *testing.T) { + healthChecked := false + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + healthChecked = true + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + _, err := New(context.Background(), srv.URL, DefaultTimeoutBase) + if err != nil { + t.Fatal(err) + } + if !healthChecked { + t.Error("health check not called") + } +} + +func TestNewTimeout(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + time.Sleep(2 * time.Minute) + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + _, err := New(ctx, srv.URL, DefaultTimeoutBase) + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatal("expected timeout") + } +} + +func TestCSVValidator_Validate(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + csvV, err := New(context.Background(), "http://localhost:8088", DefaultTimeoutBase) + if err != nil { + t.Fatal(err) + } + + tt := []struct { + name string + dataFilename string + schemaFilename string + valid bool + deadletter bool + }{ + {"valid-1", "valid-1-data.csv", "valid-1-schema.csvs", true, false}, + {"valid-2", "valid-2-data.csv", "valid-2-schema.csvs", true, false}, + {"valid-3", "valid-3-data.csv", "valid-3-schema.csvs", true, false}, + {"valid-4", "valid-4-data.csv", "valid-4-schema.csvs", true, false}, + {"invalid-1", "invalid-1-data.csv", "invalid-1-schema.csvs", false, false}, + {"invalid-2", "invalid-2-data.csv", "invalid-2-schema.csvs", false, false}, + {"invalid-3", "invalid-3-data.csv", "invalid-3-schema.csvs", false, false}, + {"deadletter-1", "deadletter-1-data.csv", "deadletter-1-schema.csvs", false, true}, + {"deadletter-2", "deadletter-2-data.csv", "deadletter-2-schema.csvs", false, true}, + {"deadletter-3", "deadletter-3-data.csv", "deadletter-3-schema.csvs", false, true}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.dataFilename)) + if err != nil { + t.Fatalf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Fatalf("schema read error: %s", err) + } + + valid, err := csvV.Validate(data, schema, "", "") + if tc.deadletter { + if !errors.Is(err, validator.ErrDeadletter) { + t.Error("deadletter expected") + } + } else { + if err != nil { + t.Errorf("validator error: %s", err) + } + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + } + }) + } +} diff --git a/validator/internal/validator/csv/testdata/deadletter-1-data.csv b/validator/internal/validator/csv/testdata/deadletter-1-data.csv new file mode 100644 index 0000000..2b3d598 --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-1-data.csv @@ -0,0 +1,6 @@ +{ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} diff --git a/validator/internal/validator/csv/testdata/deadletter-1-schema.csvs b/validator/internal/validator/csv/testdata/deadletter-1-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-1-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/deadletter-2-data.csv b/validator/internal/validator/csv/testdata/deadletter-2-data.csv new file mode 100644 index 0000000..b80607f --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-2-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,m +jure,19,f +stipano,57,m diff --git a/validator/internal/validator/csv/testdata/deadletter-2-schema.csvs b/validator/internal/validator/csv/testdata/deadletter-2-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-2-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/deadletter-3-data.csv b/validator/internal/validator/csv/testdata/deadletter-3-data.csv new file mode 100644 index 0000000..3f95ae0 --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-3-data.csv @@ -0,0 +1,4 @@ +name,gender +miana,20,m +jure,19,f +stipano,57,m diff --git a/validator/internal/validator/csv/testdata/deadletter-3-schema.csvs b/validator/internal/validator/csv/testdata/deadletter-3-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/deadletter-3-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/invalid-1-data.csv b/validator/internal/validator/csv/testdata/invalid-1-data.csv new file mode 100644 index 0000000..58646a0 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-1-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,4 years,m +jure,19,f +mia,57,male \ No newline at end of file diff --git a/validator/internal/validator/csv/testdata/invalid-1-schema.csvs b/validator/internal/validator/csv/testdata/invalid-1-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-1-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/invalid-2-data.csv b/validator/internal/validator/csv/testdata/invalid-2-data.csv new file mode 100644 index 0000000..163b688 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-2-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,sixty years,m +jure,19,male +mia,57,female \ No newline at end of file diff --git a/validator/internal/validator/csv/testdata/invalid-2-schema.csvs b/validator/internal/validator/csv/testdata/invalid-2-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-2-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/invalid-3-data.csv b/validator/internal/validator/csv/testdata/invalid-3-data.csv new file mode 100644 index 0000000..b6097f2 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-3-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,0 years,male +jure,19,female +mia,0 years,female \ No newline at end of file diff --git a/validator/internal/validator/csv/testdata/invalid-3-schema.csvs b/validator/internal/validator/csv/testdata/invalid-3-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/invalid-3-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/valid-1-data.csv b/validator/internal/validator/csv/testdata/valid-1-data.csv new file mode 100644 index 0000000..59c43f9 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-1-data.csv @@ -0,0 +1,4 @@ +name,age,gender +miana,21,m +jure,19,f +stipano,57,m diff --git a/validator/internal/validator/csv/testdata/valid-1-schema.csvs b/validator/internal/validator/csv/testdata/valid-1-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-1-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/valid-2-data.csv b/validator/internal/validator/csv/testdata/valid-2-data.csv new file mode 100644 index 0000000..60933fb --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-2-data.csv @@ -0,0 +1,4 @@ +name,age,gender +wow,22,f +wew,99,f +stipano,57,f \ No newline at end of file diff --git a/validator/internal/validator/csv/testdata/valid-2-schema.csvs b/validator/internal/validator/csv/testdata/valid-2-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-2-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/valid-3-data.csv b/validator/internal/validator/csv/testdata/valid-3-data.csv new file mode 100644 index 0000000..f00f516 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-3-data.csv @@ -0,0 +1,4 @@ +name,age,gender +muchname,50,m +suchname,20,m +name3,57,m diff --git a/validator/internal/validator/csv/testdata/valid-3-schema.csvs b/validator/internal/validator/csv/testdata/valid-3-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-3-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/csv/testdata/valid-4-data.csv b/validator/internal/validator/csv/testdata/valid-4-data.csv new file mode 100644 index 0000000..955e446 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-4-data.csv @@ -0,0 +1,4 @@ +name,age,gender +num2,21,m +name3,19,f +mamam,57,m \ No newline at end of file diff --git a/validator/internal/validator/csv/testdata/valid-4-schema.csvs b/validator/internal/validator/csv/testdata/valid-4-schema.csvs new file mode 100644 index 0000000..635dc83 --- /dev/null +++ b/validator/internal/validator/csv/testdata/valid-4-schema.csvs @@ -0,0 +1,5 @@ +version 1.1 +@totalColumns 3 +name: notEmpty +age: range(0, 120) +gender: is("m") or is("f") or is("t") or is("n") diff --git a/validator/internal/validator/external/csv-validator/.gitignore b/validator/internal/validator/external/csv-validator/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/validator/internal/validator/external/csv-validator/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/validator/internal/validator/external/csv-validator/pom.xml b/validator/internal/validator/external/csv-validator/pom.xml new file mode 100644 index 0000000..1b31fad --- /dev/null +++ b/validator/internal/validator/external/csv-validator/pom.xml @@ -0,0 +1,219 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.1.1 + + + + net.syntio + csv-validator + 0.0.1-SNAPSHOT + csv-validator + CSV validator service + + + 11 + 3.0.2 + 6.0.4 + 10.1.5 + + + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-websocket + ${tomcat.version} + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat.version} + + + + + org.springframework.boot + spring-boot-starter-web + ${springframework.boot.version} + + + org.springframework.boot + spring-boot + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${springframework.boot.version} + + + + org.springframework.boot + spring-boot-devtools + runtime + true + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-test + test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-json + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-logging + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-tomcat + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test-autoconfigure + ${springframework.boot.version} + + + + + org.springframework + spring-web + ${springframework.version} + + + org.springframework + spring-core + ${springframework.version} + + + org.springframework + spring-aop + ${springframework.version} + + + org.springframework + spring-beans + ${springframework.version} + + + org.springframework + spring-context + ${springframework.version} + + + org.springframework + spring-expression + ${springframework.version} + + + org.springframework + spring-jcl + ${springframework.version} + + + org.springframework + spring-test + ${springframework.version} + + + org.springframework + spring-webmvc + ${springframework.version} + + + + ch.qos.logback + logback-classic + 1.4.8 + + + ch.qos.logback + logback-core + 1.4.8 + + + + org.slf4j + slf4j-api + 2.0.7 + + + org.slf4j + slf4j-simple + 2.0.7 + + + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + + + + org.yaml + snakeyaml + 2.0 + + + + uk.gov.nationalarchives + csv-validator-java-api + 1.1.5 + + + com.gilt + gfc-semver_2.11 + + + + + + com.gilt + gfc-semver_2.11 + 0.0.5 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/CsvValidatorApplication.java b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/CsvValidatorApplication.java new file mode 100644 index 0000000..a1bdf35 --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/CsvValidatorApplication.java @@ -0,0 +1,12 @@ +package net.syntio.csvvalidator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CsvValidatorApplication { + + public static void main(String[] args) { + SpringApplication.run(CsvValidatorApplication.class, args); + } +} diff --git a/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/controller/ValidatorController.java b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/controller/ValidatorController.java new file mode 100644 index 0000000..0ec7a3b --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/controller/ValidatorController.java @@ -0,0 +1,37 @@ +package net.syntio.csvvalidator.controller; + +import net.syntio.csvvalidator.dto.ValidationRequestDto; +import net.syntio.csvvalidator.dto.ValidatorResponseDto; +import net.syntio.csvvalidator.validator.CsvValidator; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ValidatorController { + + @PostMapping(value = "/") + public ResponseEntity validate(@RequestBody ValidationRequestDto req) { + String data = req.getData().replaceAll("\r\n", "\n"); + String schema = req.getSchema().replaceAll("\r\n", "\n"); + try { + boolean validation = CsvValidator.validate(data, schema); + ValidatorResponseDto res = new ValidatorResponseDto(validation); + if (validation) { + res.setInfo("Data is valid"); + return ResponseEntity.ok(res); + } + res.setInfo("Data is invalid"); + return ResponseEntity.ok(res); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + } + + @GetMapping(value = "/health") + public ResponseEntity healthCheck() { + return ResponseEntity.ok().build(); + } +} diff --git a/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidationRequestDto.java b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidationRequestDto.java new file mode 100644 index 0000000..585130e --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidationRequestDto.java @@ -0,0 +1,19 @@ +package net.syntio.csvvalidator.dto; + +public class ValidationRequestDto { + private final String data; + private final String schema; + + public ValidationRequestDto(String data, String schema) { + this.data = data; + this.schema = schema; + } + + public String getData() { + return data; + } + + public String getSchema() { + return schema; + } +} diff --git a/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidatorResponseDto.java b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidatorResponseDto.java new file mode 100644 index 0000000..206451e --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/dto/ValidatorResponseDto.java @@ -0,0 +1,22 @@ +package net.syntio.csvvalidator.dto; + +public class ValidatorResponseDto { + private final boolean validation; + private String info; + + public ValidatorResponseDto(boolean validation) { + this.validation = validation; + } + + public boolean getValidation() { + return validation; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/validator/CsvValidator.java b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/validator/CsvValidator.java new file mode 100644 index 0000000..07e8410 --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/main/java/net/syntio/csvvalidator/validator/CsvValidator.java @@ -0,0 +1,21 @@ +package net.syntio.csvvalidator.validator; +import uk.gov.nationalarchives.csv.validator.api.java.FailMessage; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +public class CsvValidator { + public static boolean validate(String data, String schema) { + Reader dataReader = new StringReader(data); + Reader schemaReader = new StringReader(schema); + + List messages = uk.gov.nationalarchives.csv.validator.api.java.CsvValidator.validate(dataReader, schemaReader, + false, + new ArrayList<>(), + true, + false); + + return messages.isEmpty(); + } +} diff --git a/validator/internal/validator/external/csv-validator/src/test/java/net/syntio/csvvalidator/CsvValidatorApplicationTests.java b/validator/internal/validator/external/csv-validator/src/test/java/net/syntio/csvvalidator/CsvValidatorApplicationTests.java new file mode 100644 index 0000000..c53b474 --- /dev/null +++ b/validator/internal/validator/external/csv-validator/src/test/java/net/syntio/csvvalidator/CsvValidatorApplicationTests.java @@ -0,0 +1,13 @@ +package net.syntio.csvvalidator; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class CsvValidatorApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/validator/internal/validator/external/xml-validator/cloudbuild.yaml b/validator/internal/validator/external/xml-validator/cloudbuild.yaml new file mode 100644 index 0000000..766d43e --- /dev/null +++ b/validator/internal/validator/external/xml-validator/cloudbuild.yaml @@ -0,0 +1,5 @@ +steps: + - name: 'gcr.io/cloud-builders/docker' + args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/xml_validator', '.' ] + - name: 'gcr.io/cloud-builders/docker' + args: [ 'push', 'gcr.io/$PROJECT_ID/xml_validator' ] diff --git a/validator/internal/validator/external/xml-validator/main.py b/validator/internal/validator/external/xml-validator/main.py new file mode 100644 index 0000000..8bbd3e6 --- /dev/null +++ b/validator/internal/validator/external/xml-validator/main.py @@ -0,0 +1,57 @@ +# Package handles xml schema validation +import http +import json + +import xmlschema +from flask import Response, Flask, request +from waitress import serve + +app = Flask(__name__) + + +@app.route("/", methods=["POST"]) +def http_validation_handler(): + request_json = request.get_json(silent=True) + is_valid = False + + if request_json and "data" in request_json and "schema" in request_json: + data = request_json["data"] + schema = request_json["schema"] + try: + is_valid = validate(data, schema) + response = make_response(is_valid, "successful validation", 200) + except: + response = make_response( + is_valid, "invalid json: can't resolve 'data' and 'schema' fields", 400 + ) + else: + response = make_response( + False, "invalid request, needs 'data' and 'schema' fields.", 400 + ) + + return response + + +@app.route("/health", methods=["GET"]) +def http_health_handler(): + response = Response(status=http.HTTPStatus.OK) + return response + + +def validate(data, schema): + schema = xmlschema.XMLSchema(schema) + return schema.is_valid(data) + + +def make_response(validation, info, status): + response_data = {"validation": validation, "info": info} + + response = Response() + response.data = json.dumps(response_data) + response.status_code = status + return response + + +if __name__ == "__main__": + print("* Serving app main") + serve(app=app, host="0.0.0.0", port=8081) diff --git a/validator/internal/validator/external/xml-validator/requirements.txt b/validator/internal/validator/external/xml-validator/requirements.txt new file mode 100644 index 0000000..ca7a4d7 --- /dev/null +++ b/validator/internal/validator/external/xml-validator/requirements.txt @@ -0,0 +1,11 @@ +click==8.0.1 +colorama==0.4.4 +elementpath==2.2.3 +Flask==2.2.5 +itsdangerous==2.0.1 +Jinja2==3.0.1 +MarkupSafe==2.1.1 +waitress==2.1.1 +Werkzeug==2.2.3 +xmlschema==1.7.0 +setuptools==65.5.1 diff --git a/validator/internal/validator/http.go b/validator/internal/validator/http.go new file mode 100644 index 0000000..07fc17a --- /dev/null +++ b/validator/internal/validator/http.go @@ -0,0 +1,85 @@ +package validator + +import ( + "bytes" + "context" + "encoding/json" + "io" + "math" + "net/http" + "time" + + "github.com/dataphos/lib-httputil/pkg/httputil" + + "github.com/pkg/errors" +) + +// HTTPTimeoutBytesUnit the base amount of bytes used by EstimateHTTPTimeout. +const HTTPTimeoutBytesUnit = 1024 * 100 + +// EstimateHTTPTimeout calculates the expected timeout, by dividing the size given in bytes with HTTPTimeoutBytesUnit, and then +// multiplying the coefficient with the given time duration. +// +// If the given size is less than HTTPTimeoutBytesUnit, base is returned, to avoid problems due to the http overhead which isn't fully linear. +func EstimateHTTPTimeout(size int, base time.Duration) time.Duration { + coef := int(math.Round(float64(size) / float64(HTTPTimeoutBytesUnit))) + if coef <= 1 { + return base + } + + return time.Duration(coef) * base +} + +// ValidateOverHTTP requests a message validation over HTTP. +// Function returns the validation boolean result. +func ValidateOverHTTP(ctx context.Context, message, schema []byte, url string) (bool, error) { + response, err := sendValidationRequest(ctx, message, schema, url) + if err != nil { + return false, err + } + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + if err != nil { + return false, err + } + + var parsedBody validationResponse + if err = json.Unmarshal(body, &parsedBody); err != nil { + return false, err + } + + switch response.StatusCode { + case http.StatusOK: + return parsedBody.Validation, nil + case http.StatusBadRequest: + return false, ErrDeadletter + default: + return false, errors.Errorf("error: status code [%v]", response.StatusCode) + } +} + +func sendValidationRequest(ctx context.Context, message, schema []byte, url string) (*http.Response, error) { + // this can't generate an error, so it's safe to ignore + data, _ := json.Marshal(validationRequest{Data: string(message), Schema: string(schema)}) + + request, err := httputil.Post(ctx, url, "application/json", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + return http.DefaultClient.Do(request) +} + +// validationRequest contains the message and schema which are used by the validator. The structure represents an HTTP +// request body. +type validationRequest struct { + Data string `json:"data"` + Schema string `json:"schema"` +} + +// validationResponse contains the validation result and an info message. The structure represents an HTTP response body. +type validationResponse struct { + Validation bool `json:"validation"` + Info string `json:"info"` +} diff --git a/validator/internal/validator/http_test.go b/validator/internal/validator/http_test.go new file mode 100644 index 0000000..f671db5 --- /dev/null +++ b/validator/internal/validator/http_test.go @@ -0,0 +1,120 @@ +package validator + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" +) + +func TestEstimateHTTPTimeout(t *testing.T) { + tt := []struct { + name string + size int + timeout time.Duration + adjustedTimeout time.Duration + }{ + {"lower than base", 99 * 1024, 1 * time.Second, 1 * time.Second}, + {"1 byte", 1, 1 * time.Second, 1 * time.Second}, + {"equal to base", HTTPTimeoutBytesUnit, 1 * time.Second, 1 * time.Second}, + {"closer to 1", 149 * 1024, 1 * time.Second, 1 * time.Second}, + {"closer to 2", 151 * 1024, 1 * time.Second, 2 * time.Second}, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + adjusted := EstimateHTTPTimeout(tc.size, tc.timeout) + if adjusted != tc.adjustedTimeout { + t.Error("calculated timeout not the same as expected") + } + }) + } +} + +func TestValidateOverHttp(t *testing.T) { + tt := []struct { + name string + expectedRequest validationRequest + expectedResponse []byte + statusCode int + isValid bool + }{ + { + "valid with status code 200", + validationRequest{ + Data: "data sent as the request for validation", + Schema: "schema for the data to be validated against", + }, + []byte("{\"validation\":true,\"info\":\"\"}"), + http.StatusOK, + true, + }, + { + "invalid with status code 200", + validationRequest{ + Data: "data sent as the request for validation", + Schema: "schema for the data to be validated against", + }, + []byte("{\"validation\":false,\"info\":\"\"}"), + http.StatusOK, + false, + }, + { + "bad request", + validationRequest{ + Data: "data sent as the request for validation", + Schema: "schema for the data to be validated against", + }, + []byte("{\"validation\":false,\"info\":\"\"}"), + http.StatusBadRequest, + false, + }, + { + "valid but malformed response because json is missing closing bracket", + validationRequest{ + Data: "data sent as the request for validation", + Schema: "schema for the data to be validated against", + }, + []byte("{\"validation\":true,\"info\":\"\""), + http.StatusBadRequest, + false, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + defer request.Body.Close() + + var receivedRequest validationRequest + if err := json.NewDecoder(request.Body).Decode(&receivedRequest); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(receivedRequest, tc.expectedRequest) { + t.Fatal("expected and actual request not the same") + } + + writer.WriteHeader(tc.statusCode) + writer.Write(tc.expectedResponse) + }) + srv := httptest.NewServer(handler) + defer srv.Close() + + isValid, err := ValidateOverHTTP(context.Background(), []byte(tc.expectedRequest.Data), []byte(tc.expectedRequest.Schema), srv.URL) + if err != nil { + if tc.statusCode == http.StatusOK { + t.Fatal("error not expected", err) + } + } + + if isValid != tc.isValid { + t.Fatal("expected and actual validation result not the same") + } + }) + } +} diff --git a/validator/internal/validator/json/json.go b/validator/internal/validator/json/json.go new file mode 100644 index 0000000..3d56ab4 --- /dev/null +++ b/validator/internal/validator/json/json.go @@ -0,0 +1,133 @@ +package json + +import ( + "bytes" + "encoding/json" + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + lru "github.com/hashicorp/golang-lru" + "github.com/santhosh-tekuri/jsonschema/v5" + _ "github.com/santhosh-tekuri/jsonschema/v5/httploader" + "github.com/xeipuuv/gojsonschema" +) + +func New() validator.Validator { + return validator.Func(func(message, schema []byte, _, _ string) (bool, error) { + var v interface{} + if err := json.Unmarshal(message, &v); err != nil { + errBroken := errors.WithMessage(validator.ErrBrokenMessage, "Message is not in a valid format - "+err.Error()) + return false, errBroken + } + + compiledSchema, err := compileSchema(schema) + if err != nil { + errCompile := errors.WithMessage(validator.ErrWrongCompile, err.Error()) + return false, errCompile + } + + if err = compiledSchema.Validate(v); err != nil { + errValidation := errors.WithMessage(validator.ErrFailedValidation, err.Error()) + return false, errValidation + + } + return true, nil + }) +} + +func NewCached(size int) validator.Validator { + cache, _ := lru.NewARC(size) + + return validator.Func(func(message, schema []byte, id, version string) (bool, error) { + var parsedMessage interface{} + if err := json.Unmarshal(message, &parsedMessage); err != nil { + errBroken := errors.WithMessage(validator.ErrBrokenMessage, "Message is not in a valid format - "+err.Error()) + return false, errBroken + } + + var compiledSchema *jsonschema.Schema + key := id + "_" + version + v, ok := cache.Get(key) + if !ok { + var err error + compiledSchema, err = compileSchema(schema) + if err != nil { + errCompile := errors.WithMessage(validator.ErrWrongCompile, err.Error()) + return false, errCompile + } + cache.Add(key, compiledSchema) + } else { + compiledSchema = v.(*jsonschema.Schema) + } + + if err := compiledSchema.Validate(parsedMessage); err != nil { + errValidation := errors.WithMessage(validator.ErrFailedValidation, err.Error()) + return false, errValidation + } + return true, nil + }) +} + +func compileSchema(schema []byte) (*jsonschema.Schema, error) { + compiler := jsonschema.NewCompiler() + if err := compiler.AddResource("schema.json", bytes.NewReader(schema)); err != nil { + return nil, err + } + compiled, err := compiler.Compile("schema.json") + if err != nil { + return nil, err + } + return compiled, nil +} + +func NewGoJsonSchemaValidator() validator.Validator { + return validator.Func(func(message, schema []byte, _, _ string) (bool, error) { + if !json.Valid(message) { + return false, validator.ErrDeadletter + } + + schemaValidator, err := gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schema)) + if err != nil { + return false, validator.ErrDeadletter + } + + result, err := schemaValidator.Validate(gojsonschema.NewBytesLoader(message)) + if err != nil { + return false, err + } + + return result.Valid(), nil + }) +} + +func NewCachedGoJsonSchemaValidator(size int) validator.Validator { + cache, _ := lru.NewARC(size) + + return validator.Func(func(message, schema []byte, id, version string) (bool, error) { + if !json.Valid(message) { + return false, validator.ErrDeadletter + } + + var compiledSchema *gojsonschema.Schema + key := id + "_" + version + v, ok := cache.Get(key) + if !ok { + var err error + compiledSchema, err = gojsonschema.NewSchema(gojsonschema.NewBytesLoader(schema)) + if err != nil { + return false, validator.ErrDeadletter + } + cache.Add(key, compiledSchema) + } else { + compiledSchema = v.(*gojsonschema.Schema) + } + + result, err := compiledSchema.Validate(gojsonschema.NewBytesLoader(message)) + if err != nil { + return false, err + } + + return result.Valid(), nil + }) +} diff --git a/validator/internal/validator/json/json_test.go b/validator/internal/validator/json/json_test.go new file mode 100644 index 0000000..c3d9ba0 --- /dev/null +++ b/validator/internal/validator/json/json_test.go @@ -0,0 +1,301 @@ +package json + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/pkg/errors" +) + +func TestJSONValidator_Validate(t *testing.T) { + jsonV := New() + + tt := []struct { + name string + dataFilename string + schemaFilename string + valid bool + deadletter bool + }{ + {"valid-1", "valid-1-data.json", "valid-1-schema.json", true, false}, + {"valid-2", "valid-2-data.json", "valid-2-schema.json", true, false}, + {"valid-3", "valid-3-data.json", "valid-3-schema.json", true, false}, + {"valid-4", "valid-4-data.json", "valid-4-schema.json", true, false}, + // {"invalid-1", "invalid-1-data.json", "invalid-1-schema.json", false, false}, + // {"invalid-2", "invalid-2-data.json", "invalid-2-schema.json", false, false}, + // {"invalid-3", "invalid-3-data.json", "invalid-3-schema.json", false, false}, + {"deadletter-1", "deadletter-1-data.json", "deadletter-1-schema.json", false, true}, + {"deadletter-2", "deadletter-2-data.json", "deadletter-2-schema.json", false, true}, + {"data-1", "data-1.json", "schema-1.json", true, false}, + {"data-2", "data-2.json", "schema-2.json", true, false}, + {"data-3", "data-3.json", "schema-3.json", true, false}, + {"data-4", "data-4.json", "schema-4.json", true, false}, + + {"ref-1", "ref-data-1.json", "ref-1.json", true, false}, + {"ref-2", "ref-data-2.json", "ref-2.json", true, false}, + {"ref-3", "ref-data-3.json", "ref-3.json", true, false}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.dataFilename)) + if err != nil { + t.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + + valid, err := jsonV.Validate(data, schema, "", "") + if tc.deadletter { + if !(errors.Is(err, validator.ErrDeadletter) || errors.Is(err, validator.ErrFailedValidation) || errors.Is(err, validator.ErrWrongCompile) || errors.Is(err, validator.ErrMissingSchema) || errors.Is(err, validator.ErrBrokenMessage)) { + t.Error("deadletter expected") + } + } else { + if err != nil { + t.Errorf("validator error: %s", err) + } + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + } + }) + } +} + +func BenchmarkValidateStandardImplementation(b *testing.B) { + v := New() + + tt := []struct { + dataFilename string + schemaFilename string + data []byte + schema []byte + }{ + {dataFilename: "valid-1-data.json", schemaFilename: "valid-1-schema.json"}, + {dataFilename: "valid-2-data.json", schemaFilename: "valid-2-schema.json"}, + {dataFilename: "valid-3-data.json", schemaFilename: "valid-3-schema.json"}, + {dataFilename: "valid-4-data.json", schemaFilename: "valid-4-schema.json"}, + {dataFilename: "data-1.json", schemaFilename: "schema-1.json"}, + {dataFilename: "data-2.json", schemaFilename: "schema-2.json"}, + {dataFilename: "data-3.json", schemaFilename: "schema-3.json"}, + {dataFilename: "data-4.json", schemaFilename: "schema-4.json"}, + } + + _, base, _, _ := runtime.Caller(0) + basepath := filepath.Dir(base) + testdataDir := filepath.Join(basepath, "testdata") + for i := range tt { + data, err := os.ReadFile(filepath.Join(testdataDir, tt[i].dataFilename)) + if err != nil { + b.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tt[i].schemaFilename)) + if err != nil { + b.Errorf("schema read error: %s", err) + } + + tt[i].data = data + tt[i].schema = schema + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, "", "") + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + } +} + +func BenchmarkValidateCachedImplementation(b *testing.B) { + v := NewCached(100) + + tt := []struct { + dataFilename string + schemaFilename string + id string + version string + data []byte + schema []byte + }{ + {dataFilename: "valid-1-data.json", schemaFilename: "valid-1-schema.json", id: "1", version: "1"}, + {dataFilename: "valid-2-data.json", schemaFilename: "valid-2-schema.json", id: "2", version: "1"}, + {dataFilename: "valid-3-data.json", schemaFilename: "valid-3-schema.json", id: "3", version: "1"}, + {dataFilename: "valid-4-data.json", schemaFilename: "valid-4-schema.json", id: "4", version: "1"}, + {dataFilename: "data-1.json", schemaFilename: "schema-1.json", id: "5", version: "1"}, + {dataFilename: "data-2.json", schemaFilename: "schema-2.json", id: "6", version: "1"}, + {dataFilename: "data-3.json", schemaFilename: "schema-3.json", id: "7", version: "1"}, + {dataFilename: "data-4.json", schemaFilename: "schema-4.json", id: "8", version: "1"}, + } + + _, base, _, _ := runtime.Caller(0) + basepath := filepath.Dir(base) + testdataDir := filepath.Join(basepath, "testdata") + for i := range tt { + data, err := os.ReadFile(filepath.Join(testdataDir, tt[i].dataFilename)) + if err != nil { + b.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tt[i].schemaFilename)) + if err != nil { + b.Errorf("schema read error: %s", err) + } + + tt[i].data = data + tt[i].schema = schema + } + + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, tc.id, tc.version) + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, tc.id, tc.version) + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + } +} + +func BenchmarkValidateGoJsonSchema(b *testing.B) { + v := NewGoJsonSchemaValidator() + + tt := []struct { + dataFilename string + schemaFilename string + data []byte + schema []byte + }{ + {dataFilename: "valid-1-data.json", schemaFilename: "valid-1-schema.json"}, + {dataFilename: "valid-2-data.json", schemaFilename: "valid-2-schema.json"}, + {dataFilename: "valid-3-data.json", schemaFilename: "valid-3-schema.json"}, + {dataFilename: "valid-4-data.json", schemaFilename: "valid-4-schema.json"}, + {dataFilename: "data-1.json", schemaFilename: "schema-1.json"}, + {dataFilename: "data-2.json", schemaFilename: "schema-2.json"}, + {dataFilename: "data-3.json", schemaFilename: "schema-3.json"}, + {dataFilename: "data-4.json", schemaFilename: "schema-4.json"}, + } + + _, base, _, _ := runtime.Caller(0) + basepath := filepath.Dir(base) + testdataDir := filepath.Join(basepath, "testdata") + for i := range tt { + data, err := os.ReadFile(filepath.Join(testdataDir, tt[i].dataFilename)) + if err != nil { + b.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tt[i].schemaFilename)) + if err != nil { + b.Errorf("schema read error: %s", err) + } + + tt[i].data = data + tt[i].schema = schema + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, "", "") + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + } +} + +func BenchmarkValidateCachedGoJsonSchema(b *testing.B) { + v := NewCachedGoJsonSchemaValidator(100) + + tt := []struct { + dataFilename string + schemaFilename string + id string + version string + data []byte + schema []byte + }{ + {dataFilename: "valid-1-data.json", schemaFilename: "valid-1-schema.json", id: "1", version: "1"}, + {dataFilename: "valid-2-data.json", schemaFilename: "valid-2-schema.json", id: "2", version: "1"}, + {dataFilename: "valid-3-data.json", schemaFilename: "valid-3-schema.json", id: "3", version: "1"}, + {dataFilename: "valid-4-data.json", schemaFilename: "valid-4-schema.json", id: "4", version: "1"}, + {dataFilename: "data-1.json", schemaFilename: "schema-1.json", id: "5", version: "1"}, + {dataFilename: "data-2.json", schemaFilename: "schema-2.json", id: "6", version: "1"}, + {dataFilename: "data-3.json", schemaFilename: "schema-3.json", id: "7", version: "1"}, + {dataFilename: "data-4.json", schemaFilename: "schema-4.json", id: "8", version: "1"}, + } + + _, base, _, _ := runtime.Caller(0) + basepath := filepath.Dir(base) + testdataDir := filepath.Join(basepath, "testdata") + for i := range tt { + data, err := os.ReadFile(filepath.Join(testdataDir, tt[i].dataFilename)) + if err != nil { + b.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tt[i].schemaFilename)) + if err != nil { + b.Errorf("schema read error: %s", err) + } + + tt[i].data = data + tt[i].schema = schema + } + + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, tc.id, tc.version) + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, tc := range tt { + valid, err := v.Validate(tc.data, tc.schema, tc.id, tc.version) + if err != nil { + b.Errorf("schema read error: %s", err) + } + if !valid { + b.Errorf("expected valid") + } + } + } +} diff --git a/validator/internal/validator/json/testdata/data-1.json b/validator/internal/validator/json/testdata/data-1.json new file mode 100644 index 0000000..3fe0812 --- /dev/null +++ b/validator/internal/validator/json/testdata/data-1.json @@ -0,0 +1,5 @@ +{ + "firstName": "John", + "lastName": "Doe", + "age": 21 +} diff --git a/validator/internal/validator/json/testdata/data-2.json b/validator/internal/validator/json/testdata/data-2.json new file mode 100644 index 0000000..7d1ee16 --- /dev/null +++ b/validator/internal/validator/json/testdata/data-2.json @@ -0,0 +1,13 @@ +{ + "fruits": [ "apple", "orange", "pear" ], + "vegetables": [ + { + "veggieName": "potato", + "veggieLike": true + }, + { + "veggieName": "broccoli", + "veggieLike": false + } + ] +} diff --git a/validator/internal/validator/json/testdata/data-3.json b/validator/internal/validator/json/testdata/data-3.json new file mode 100644 index 0000000..68e8620 --- /dev/null +++ b/validator/internal/validator/json/testdata/data-3.json @@ -0,0 +1,13 @@ +{ + "id": 7, + "name": "John Doe", + "age": 22, + "hobbies": { + "indoor": [ + "Chess" + ], + "outdoor": [ + "BasketballStand-up Comedy" + ] + } +} diff --git a/validator/internal/validator/json/testdata/data-4.json b/validator/internal/validator/json/testdata/data-4.json new file mode 100644 index 0000000..1ee80eb --- /dev/null +++ b/validator/internal/validator/json/testdata/data-4.json @@ -0,0 +1,100 @@ +{ + "web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500 + } + }, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2" + } + }, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet" + }, + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet" + }, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true + } + } + ], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*" + }, + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld" + } + } +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/deadletter-1-data.json b/validator/internal/validator/json/testdata/deadletter-1-data.json new file mode 100644 index 0000000..ec3bdf2 --- /dev/null +++ b/validator/internal/validator/json/testdata/deadletter-1-data.json @@ -0,0 +1,5 @@ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} diff --git a/validator/internal/validator/json/testdata/deadletter-1-schema.json b/validator/internal/validator/json/testdata/deadletter-1-schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/validator/json/testdata/deadletter-1-schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/deadletter-2-data.json b/validator/internal/validator/json/testdata/deadletter-2-data.json new file mode 100644 index 0000000..241d4ce --- /dev/null +++ b/validator/internal/validator/json/testdata/deadletter-2-data.json @@ -0,0 +1,6 @@ +{ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/deadletter-2-schema.json b/validator/internal/validator/json/testdata/deadletter-2-schema.json new file mode 100644 index 0000000..162468a --- /dev/null +++ b/validator/internal/validator/json/testdata/deadletter-2-schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/invalid-1-data.json b/validator/internal/validator/json/testdata/invalid-1-data.json new file mode 100644 index 0000000..05a84de --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-1-data.json @@ -0,0 +1,7 @@ +{ + "id": 100, + "first_name": "Syntio Martina", + "last_name": "Syntio surname", + "email": "businessEmail@syntio.net", + "phone": "090 111 222 33" +} diff --git a/validator/internal/validator/json/testdata/invalid-1-schema.json b/validator/internal/validator/json/testdata/invalid-1-schema.json new file mode 100644 index 0000000..8865b61 --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-1-schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": true, + "required": [ + "id", + "first_name", + "last_name", + "email", + "phone", + "address" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + }, + "phone": { + "type": "string", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "090 111 222 33" + ] + }, + "address": { + "type": "string", + "title": "The Address Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio Building, Zagreb" + ] + } + } +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/invalid-2-data.json b/validator/internal/validator/json/testdata/invalid-2-data.json new file mode 100644 index 0000000..35dc8c3 --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-2-data.json @@ -0,0 +1,9 @@ +{ + "id": 100, + "first_name": "Syntsreeertina", + "last_name": "Syntio sdjjsurname", + "email": "busiddddnessEmail@syntio.net", + "phone": "090 111 222 33", + "address": "Syntio Building, Zagreb 2", + "additionalProperty": "not allowed" +} diff --git a/validator/internal/validator/json/testdata/invalid-2-schema.json b/validator/internal/validator/json/testdata/invalid-2-schema.json new file mode 100644 index 0000000..71b7472 --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-2-schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email", + "phone", + "address" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + }, + "phone": { + "type": "string", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "090 111 222 33" + ] + }, + "address": { + "type": "string", + "title": "The Address Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio Building, Zagreb" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/invalid-3-data.json b/validator/internal/validator/json/testdata/invalid-3-data.json new file mode 100644 index 0000000..fe89e0b --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-3-data.json @@ -0,0 +1,16 @@ +{ + "data": { + "id": 101, + "first_name": "name", + "last_name": "surname", + "email": "businessEmail@company.net", + "phone": "090 111 222 33", + "address": "Company Building, Town", + "home number": "33a" + }, + "attributes": { + "schemaId": "ShZjhdu76jjstre", + "versionId": 2, + "format": "json" + } +} diff --git a/validator/internal/validator/json/testdata/invalid-3-schema.json b/validator/internal/validator/json/testdata/invalid-3-schema.json new file mode 100644 index 0000000..8865b61 --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-3-schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": true, + "required": [ + "id", + "first_name", + "last_name", + "email", + "phone", + "address" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + }, + "phone": { + "type": "string", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "090 111 222 33" + ] + }, + "address": { + "type": "string", + "title": "The Address Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio Building, Zagreb" + ] + } + } +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/invalid-4-data.json b/validator/internal/validator/json/testdata/invalid-4-data.json new file mode 100644 index 0000000..05a84de --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-4-data.json @@ -0,0 +1,7 @@ +{ + "id": 100, + "first_name": "Syntio Martina", + "last_name": "Syntio surname", + "email": "businessEmail@syntio.net", + "phone": "090 111 222 33" +} diff --git a/validator/internal/validator/json/testdata/invalid-4-schema.json b/validator/internal/validator/json/testdata/invalid-4-schema.json new file mode 100644 index 0000000..cf350a1 --- /dev/null +++ b/validator/internal/validator/json/testdata/invalid-4-schema.json @@ -0,0 +1,74 @@ +{ + SYNTAX + ERROR + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": true, + "required": [ + "id", + "first_name", + "last_name", + "email", + "phone", + "address" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + }, + "phone": { + "type": "string", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "090 111 222 33" + ] + }, + "address": { + "type": "string", + "title": "The Address Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio Building, Zagreb" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/ref-1-child.json b/validator/internal/validator/json/testdata/ref-1-child.json new file mode 100644 index 0000000..8328bc7 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-1-child.json @@ -0,0 +1,48 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://schema.my-site.org/geometry.json", + "type": "object", + "title": "The Address Schema", + "description": "Reusable Address schema", + "default": {}, + "additionalProperties": false, + "required": [ + "street", + "zip", + "city", + "country" + ], + "properties": { + "street": { + "type": "string", + "title": "Street name" + }, + "streetNo": { + "type": "string", + "title": "House/Apartment number" + }, + "place": { + "type": "string", + "title": "Place name", + "default": "" + }, + "zip": { + "type": "string", + "title": "Zip code", + "default": "" + }, + "city": { + "type": "string", + "title": "City name", + "default": "" + }, + "region": { + "type": "string", + "title": "Region name" + }, + "country": { + "type": "string", + "title": "Country name" + } + } +} diff --git a/validator/internal/validator/json/testdata/ref-1.json b/validator/internal/validator/json/testdata/ref-1.json new file mode 100644 index 0000000..bfe8bc9 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-1.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Customer master data", + "description": "Customer MDM schema", + "default": {}, + "additionalProperties": true, + "required": [ + "name", + "personalid", + "address" + ], + "properties": { + "name": { + "type": "string", + "title": "Customer name" + }, + "personalid": { + "type": "string", + "title": "Personal document ID number" + }, + "address": { + "$ref": "./testdata/ref-1-child.json" + } + } +} diff --git a/validator/internal/validator/json/testdata/ref-2-child.json b/validator/internal/validator/json/testdata/ref-2-child.json new file mode 100644 index 0000000..24f5ebf --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-2-child.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "url": { + "id": "url", + "type": "string", + "format": "uri" + }, + "name": { + "id": "name", + "type": "string" + } + }, + "required": ["name"] +} diff --git a/validator/internal/validator/json/testdata/ref-2.json b/validator/internal/validator/json/testdata/ref-2.json new file mode 100644 index 0000000..90adc06 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-2.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "allOf": [ + { "$ref": "./testdata/ref-2-child.json" }, + { + "type": "object", + "properties": { + "gender": { + "id": "gender", + "type": "string", + "enum": ["F", "M"] + }, + "nationality": { + "id": "nationality", + "type": "string" + }, + "birthDate": { + "id": "birthDate", + "type": "string", + "format": "date-time" + } + }, + "required": ["gender"] + } + ] +} diff --git a/validator/internal/validator/json/testdata/ref-3-child.json b/validator/internal/validator/json/testdata/ref-3-child.json new file mode 100644 index 0000000..b8a7c46 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-3-child.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Address Schema", + "description": "Reusable Address schema", + "default": {}, + "additionalProperties": false, + "required": [ + "street" + ], + "properties": { + "street": { + "type": "string", + "title": "Street name" + }, + "city": { + "type": "string", + "title": "City name", + "default": "" + } + } +} diff --git a/validator/internal/validator/json/testdata/ref-3.json b/validator/internal/validator/json/testdata/ref-3.json new file mode 100644 index 0000000..e4e9750 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-3.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Customer master data", + "description": "Customer MDM schema", + "default": {}, + "additionalProperties": true, + "required": [ + "name", + "address" + ], + "properties": { + "name": { + "type": "string", + "title": "Customer name" + }, + "address": { + "$ref": "./testdata/ref-3-child.json" + } + } +} diff --git a/validator/internal/validator/json/testdata/ref-data-1.json b/validator/internal/validator/json/testdata/ref-data-1.json new file mode 100644 index 0000000..69a8390 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-data-1.json @@ -0,0 +1,10 @@ +{ + "name": "Pero", + "personalid": "123", + "address": { + "street": "123", + "zip": "123", + "city": "asd", + "country": "asd" + } +} diff --git a/validator/internal/validator/json/testdata/ref-data-2.json b/validator/internal/validator/json/testdata/ref-data-2.json new file mode 100644 index 0000000..4701e49 --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-data-2.json @@ -0,0 +1,4 @@ +{ + "name": "Pero", + "gender": "M" +} diff --git a/validator/internal/validator/json/testdata/ref-data-3.json b/validator/internal/validator/json/testdata/ref-data-3.json new file mode 100644 index 0000000..58080aa --- /dev/null +++ b/validator/internal/validator/json/testdata/ref-data-3.json @@ -0,0 +1,7 @@ +{ + "name": "jade", + "address": { + "street": "7th street", + "city": "zagreb" + } +} diff --git a/validator/internal/validator/json/testdata/schema-1.json b/validator/internal/validator/json/testdata/schema-1.json new file mode 100644 index 0000000..687ae74 --- /dev/null +++ b/validator/internal/validator/json/testdata/schema-1.json @@ -0,0 +1,21 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} diff --git a/validator/internal/validator/json/testdata/schema-2.json b/validator/internal/validator/json/testdata/schema-2.json new file mode 100644 index 0000000..72ab606 --- /dev/null +++ b/validator/internal/validator/json/testdata/schema-2.json @@ -0,0 +1,34 @@ +{ + "$id": "https://example.com/arrays.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a person, company, organization, or place", + "type": "object", + "properties": { + "fruits": { + "type": "array", + "items": { + "type": "string" + } + }, + "vegetables": { + "type": "array", + "items": { "$ref": "#/$defs/veggie" } + } + }, + "$defs": { + "veggie": { + "type": "object", + "required": [ "veggieName", "veggieLike" ], + "properties": { + "veggieName": { + "type": "string", + "description": "The name of the vegetable." + }, + "veggieLike": { + "type": "boolean", + "description": "Do I like this vegetable?" + } + } + } + } +} diff --git a/validator/internal/validator/json/testdata/schema-3.json b/validator/internal/validator/json/testdata/schema-3.json new file mode 100644 index 0000000..3a8ad3f --- /dev/null +++ b/validator/internal/validator/json/testdata/schema-3.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$id": "https://example.com/employee.schema.json", + "title": "Record of employee", + "description": "This document records the details of an employee", + "type": "object", + "properties": { + "id": { + "description": "A unique identifier for an employee", + "type": "number" + }, + "name": { + "description": "Full name of the employee", + "type": "string" + }, + "age": { + "description": "Age of the employee", + "type": "number" + }, + "hobbies": { + "description": "Hobbies of the employee", + "type": "object", + "properties": { + "indoor": { + "type": "array", + "items": { + "description": "List of indoor hobbies", + "type": "string" + } + }, + "outdoor": { + "type": "array", + "items": { + "description": "List of outdoor hobbies", + "type": "string" + } + } + } + } + } +} diff --git a/validator/internal/validator/json/testdata/schema-4.json b/validator/internal/validator/json/testdata/schema-4.json new file mode 100644 index 0000000..f46f61d --- /dev/null +++ b/validator/internal/validator/json/testdata/schema-4.json @@ -0,0 +1,253 @@ +{ + "$schema": "http://json-schema.org/schema#", + "additionalProperties": false, + "type": "object", + "properties": { + "web-app": { + "type": "object", + "properties": { + "servlet": { + "type": "array", + "items": { + "type": "object", + "properties": { + "servlet-name": { + "type": "string" + }, + "servlet-class": { + "type": "string" + }, + "init-param": { + "type": "object", + "properties": { + "configGlossary:installationAt": { + "type": "string" + }, + "configGlossary:adminEmail": { + "type": "string" + }, + "configGlossary:poweredBy": { + "type": "string" + }, + "configGlossary:poweredByIcon": { + "type": "string" + }, + "configGlossary:staticPath": { + "type": "string" + }, + "templateProcessorClass": { + "type": "string" + }, + "templateLoaderClass": { + "type": "string" + }, + "templatePath": { + "type": "string" + }, + "templateOverridePath": { + "type": "string" + }, + "defaultListTemplate": { + "type": "string" + }, + "defaultFileTemplate": { + "type": "string" + }, + "useJSP": { + "type": "boolean" + }, + "jspListTemplate": { + "type": "string" + }, + "jspFileTemplate": { + "type": "string" + }, + "cachePackageTagsTrack": { + "type": "integer" + }, + "cachePackageTagsStore": { + "type": "integer" + }, + "cachePackageTagsRefresh": { + "type": "integer" + }, + "cacheTemplatesTrack": { + "type": "integer" + }, + "cacheTemplatesStore": { + "type": "integer" + }, + "cacheTemplatesRefresh": { + "type": "integer" + }, + "cachePagesTrack": { + "type": "integer" + }, + "cachePagesStore": { + "type": "integer" + }, + "cachePagesRefresh": { + "type": "integer" + }, + "cachePagesDirtyRead": { + "type": "integer" + }, + "searchEngineListTemplate": { + "type": "string" + }, + "searchEngineFileTemplate": { + "type": "string" + }, + "searchEngineRobotsDb": { + "type": "string" + }, + "useDataStore": { + "type": "boolean" + }, + "dataStoreClass": { + "type": "string" + }, + "redirectionClass": { + "type": "string" + }, + "dataStoreName": { + "type": "string" + }, + "dataStoreDriver": { + "type": "string" + }, + "dataStoreUrl": { + "type": "string" + }, + "dataStoreUser": { + "type": "string" + }, + "dataStorePassword": { + "type": "string" + }, + "dataStoreTestQuery": { + "type": "string" + }, + "dataStoreLogFile": { + "type": "string" + }, + "dataStoreInitConns": { + "type": "integer" + }, + "dataStoreMaxConns": { + "type": "integer" + }, + "dataStoreConnUsageLimit": { + "type": "integer" + }, + "dataStoreLogLevel": { + "type": "string" + }, + "maxUrlLength": { + "type": "integer" + }, + "mailHost": { + "type": "string" + }, + "mailHostOverride": { + "type": "string" + }, + "log": { + "type": "integer" + }, + "logLocation": { + "type": "string" + }, + "logMaxSize": { + "type": "string" + }, + "dataLog": { + "type": "integer" + }, + "dataLogLocation": { + "type": "string" + }, + "dataLogMaxSize": { + "type": "string" + }, + "removePageCache": { + "type": "string" + }, + "removeTemplateCache": { + "type": "string" + }, + "fileTransferFolder": { + "type": "string" + }, + "lookInContext": { + "type": "integer" + }, + "adminGroupID": { + "type": "integer" + }, + "betaServer": { + "type": "boolean" + } + } + } + }, + "required": [ + "servlet-class", + "servlet-name" + ] + } + }, + "servlet-mapping": { + "type": "object", + "properties": { + "cofaxCDS": { + "type": "string" + }, + "cofaxEmail": { + "type": "string" + }, + "cofaxAdmin": { + "type": "string" + }, + "fileServlet": { + "type": "string" + }, + "cofaxTools": { + "type": "string" + } + }, + "required": [ + "cofaxAdmin", + "cofaxCDS", + "cofaxEmail", + "cofaxTools", + "fileServlet" + ] + }, + "taglib": { + "type": "object", + "properties": { + "taglib-uri": { + "type": "string" + }, + "taglib-location": { + "type": "string" + } + }, + "required": [ + "taglib-location", + "taglib-uri" + ] + } + }, + "required": [ + "servlet", + "servlet-mapping", + "taglib" + ] + } + }, + "required": [ + "web-app" + ] +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/valid-1-data.json b/validator/internal/validator/json/testdata/valid-1-data.json new file mode 100644 index 0000000..241d4ce --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-1-data.json @@ -0,0 +1,6 @@ +{ + "id": 100, + "first_name": "syn jason", + "last_name": "syn oblak", + "email": "jsonsmail" +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/valid-1-schema.json b/validator/internal/validator/json/testdata/valid-1-schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-1-schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/valid-2-data.json b/validator/internal/validator/json/testdata/valid-2-data.json new file mode 100644 index 0000000..fa08e34 --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-2-data.json @@ -0,0 +1,6 @@ +{ + "id": 67, + "first_name": "syn mia", + "last_name": "syn oblakyy", + "email": "miasmail" +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/valid-2-schema.json b/validator/internal/validator/json/testdata/valid-2-schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-2-schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/valid-3-data.json b/validator/internal/validator/json/testdata/valid-3-data.json new file mode 100644 index 0000000..a22878d --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-3-data.json @@ -0,0 +1,6 @@ +{ + "id": 32, + "first_name": "syn ena", + "last_name": "syn dyy", + "email": "enasmail" +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/valid-3-schema.json b/validator/internal/validator/json/testdata/valid-3-schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-3-schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/json/testdata/valid-4-data.json b/validator/internal/validator/json/testdata/valid-4-data.json new file mode 100644 index 0000000..ef71bbd --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-4-data.json @@ -0,0 +1,6 @@ +{ + "id": 12, + "first_name": "syn jure", + "last_name": "syn koma", + "email": "juresmail" +} \ No newline at end of file diff --git a/validator/internal/validator/json/testdata/valid-4-schema.json b/validator/internal/validator/json/testdata/valid-4-schema.json new file mode 100644 index 0000000..e38e3b0 --- /dev/null +++ b/validator/internal/validator/json/testdata/valid-4-schema.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "object", + "title": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": false, + "required": [ + "id", + "first_name", + "last_name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "title": "The Id Schema", + "description": "An explanation about the purpose of this instance.", + "default": 0, + "examples": [ + 100.0 + ] + }, + "first_name": { + "type": "string", + "title": "The First_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio name" + ] + }, + "last_name": { + "type": "string", + "title": "The Last_name Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "Syntio surname" + ] + }, + "email": { + "type": "string", + "title": "The Email Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "businessEmail@syntio.net" + ] + } + } +} diff --git a/validator/internal/validator/protobuf/protobuf.go b/validator/internal/validator/protobuf/protobuf.go new file mode 100644 index 0000000..b303a30 --- /dev/null +++ b/validator/internal/validator/protobuf/protobuf.go @@ -0,0 +1,170 @@ +package protobuf + +import ( + "bufio" + "os" + "path/filepath" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + lru "github.com/hashicorp/golang-lru" + "github.com/jhump/protoreflect/desc" + "github.com/jhump/protoreflect/desc/protoparse" + "github.com/jhump/protoreflect/dynamic" + "github.com/pkg/errors" + "golang.org/x/sync/singleflight" +) + +type Validator struct { + Dir string + group singleflight.Group + cache *lru.TwoQueueCache +} + +// New returns a new instance of a protobuf validator.Validator. +// +// Since the validator needs to write to disk, a path to the used directory is needed, as well +// as a cache size which will be used to avoid writing to disk for each validation request. +func New(dir string, cacheSize int) (validator.Validator, error) { + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return nil, err + } + + cache, err := lru.New2Q(cacheSize) + if err != nil { + return nil, err + } + + return &Validator{ + Dir: dir, + cache: cache, + }, nil +} + +func (v *Validator) Validate(message, schema []byte, id, version string) (bool, error) { + filename := id + "_" + version + ".txt" + descriptor, err := v.getMainMessageDescriptor(filename, schema) + if err != nil { + return false, err + } + + if err = descriptor.Unmarshal(message); err != nil { + return false, nil + } + + if hasUnknownFields(descriptor) { + return false, nil + } + if err = descriptor.ValidateRecursive(); err != nil { + return false, nil + } + + return true, nil +} + +// getMainMessageDescriptor returns a fresh dynamic.Message instance for the given schema. +// +// Because the used libraries require schemas to be read from disk, a lru cache is used to avoid I/O operations +// for each validation request. This in turn means every cache miss requires checking if the schema is stored to disk, +// (storing it if necessary), then reading and caching it. +func (v *Validator) getMainMessageDescriptor(filename string, schema []byte) (*dynamic.Message, error) { + var descriptor *desc.FileDescriptor + var err error + + path := filepath.Join(v.Dir, filename) + // try to retrieve the processed .proto message from the cache + val, ok := v.cache.Get(path) + if !ok { + // if it isn't in the cache, check if it is already written to disk + if _, err = os.Stat(path); errors.Is(err, os.ErrNotExist) { + if err = v.writeSchemaToFile(path, schema); err != nil { + return nil, err + } + } + + // now we can load the written .proto schema into a message descriptor + descriptor, err = loadSchemaIntoDescriptor(v.Dir, filename) + if err != nil { + return nil, err + } + + v.cache.Add(path, descriptor) + } else { + descriptor = val.(*desc.FileDescriptor) + } + + return parseDescriptor(descriptor) +} + +// writeSchemaToFile writes the given schema under the given path. +// +// A singleflight.Group is used to ensure concurrent request for the same schema only write +// the schema once (I/O is expensive). +func (v *Validator) writeSchemaToFile(path string, schema []byte) error { + _, err, _ := v.group.Do(path, func() (interface{}, error) { + f, err := os.Create(path) + if err != nil { + return nil, err + } + + w := bufio.NewWriter(f) + if _, err = w.Write(schema); err != nil { + return nil, err + } + if err = w.Flush(); err != nil { + return nil, err + } + + return nil, f.Close() + }) + if err != nil { + return err + } + + return nil +} + +// loadSchemaIntoDescriptor retrieves a file descriptor of a .proto file stored under filename, +// under the given import path. +func loadSchemaIntoDescriptor(importPath, filename string) (*desc.FileDescriptor, error) { + parser := protoparse.Parser{ + ImportPaths: []string{importPath}, + } + fileDescriptors, err := parser.ParseFiles(filename) + if err != nil { + return nil, err + } + + return fileDescriptors[0], nil +} + +// parseDescriptor parses the given file descriptor into a dynamic.Message instance, returning an error +// if there are multiple top-level messages defined in the given descriptor. +func parseDescriptor(descriptor *desc.FileDescriptor) (*dynamic.Message, error) { + messageDescriptors := descriptor.GetMessageTypes() + if len(messageDescriptors) == 0 { + return nil, errors.Wrap(validator.ErrDeadletter, "no message definitions were found in the .proto file") + } + if len(messageDescriptors) > 1 { + return nil, errors.Wrap(validator.ErrDeadletter, ".proto file must have exactly 1 top level message") + } + return dynamic.NewMessage(messageDescriptors[0]), nil +} + +// hasUnknownFields recursively checks for unknown fields of the given dynamic.Message. +func hasUnknownFields(message *dynamic.Message) bool { + if len(message.GetUnknownFields()) > 0 { + return true + } + + for _, v := range message.GetKnownFields() { + field := message.GetField(v) + if fieldMessage, ok := field.(*dynamic.Message); ok { + if hasUnknownFields(fieldMessage) { + return true + } + } + } + + return false +} diff --git a/validator/internal/validator/protobuf/protobuf_test.go b/validator/internal/validator/protobuf/protobuf_test.go new file mode 100644 index 0000000..eb08d50 --- /dev/null +++ b/validator/internal/validator/protobuf/protobuf_test.go @@ -0,0 +1,340 @@ +package protobuf + +import ( + "bufio" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/protobuf/testdata/person" + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator/protobuf/testdata/testpb3" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestValidate(t *testing.T) { + dir := "./schemas" + v, err := New(dir, 10) + if err != nil { + t.Fatal(err) + } + defer func() { + _ = os.RemoveAll(dir) + }() + + tt := []struct { + name string + data string + schemaId string + schemaVersion string + schemaFilename string + valid bool + }{ + { + "Proto2-valid-1", + "valid2-1.pb", + "1", + "1", + "schema2-1.proto", + true, + }, + { + "Proto2-valid-2", + "valid2-2.pb", + "1", + "1", + "schema2-1.proto", + true, + }, + { + "Proto2-valid-3", + "valid2-3.pb", + "1", + "1", + "schema2-1.proto", + true, + }, + { + "Proto2-valid-4", + "valid2-4.pb", + "1", + "1", + "schema2-1.proto", + true, + }, + { + "Proto2-invalid-1", + "invalid2-1.pb", + "1", + "1", + "schema2-1.proto", + false, + }, + { + "Proto2-invalid-2", + "invalid2-2.pb", + "1", + "1", + "schema2-1.proto", + false, + }, + { + "Proto2-invalid-3", + "valid3-8.pb", + "1", + "1", + "schema2-1.proto", + false, + }, + { + "Proto3-valid-1", + "valid3-1.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-2", + "valid3-2.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-3", + "valid3-3.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-4", + "valid3-4.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-5", + "valid3-5.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-6", + "valid3-6.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-valid-7", + "valid3-7.pb", + "2", + "1", + "schema3-1.proto", + true, + }, + { + "Proto3-invalid-1", + "valid3-8.pb", + "2", + "1", + "schema3-1.proto", + false, + }, + { + "Proto3-valid-8", + "valid3-8.pb", + "3", + "1", + "schema3-2.proto", + true, + }, + { + "Proto3-invalid-2", + "valid3-8.pb", + "2", + "1", + "schema3-1.proto", + false, + }, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.data)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + + valid, err := v.Validate(data, schema, tc.schemaId, tc.schemaVersion) + if err != nil { + t.Error(err) + } + + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + }) + } +} + +//nolint:deadcode,unused +func generateData() error { + r1 := &testpb3.Record{ + Name: "test1", + Age: 1, + Collection: []string{"1", "2", "3"}, + Foo: &testpb3.Record_Foo{Bar: "bar1"}, + } + data1, err := proto.Marshal(r1) + if err != nil { + return err + } + if err = saveToFile(data1, "testdata/valid3-1.pb"); err != nil { + return err + } + + r2 := &testpb3.Record{ + Name: "test2", + Collection: []string{"1", "2"}, + Foo: &testpb3.Record_Foo{Bar: "bar2"}, + } + data2, err := proto.Marshal(r2) + if err != nil { + return err + } + if err = saveToFile(data2, "testdata/valid3-2.pb"); err != nil { + return err + } + + r3 := &testpb3.Record{ + Name: "test3", + Collection: []string{"1", "3"}, + Foo: &testpb3.Record_Foo{}, + } + data3, err := proto.Marshal(r3) + if err != nil { + return err + } + if err = saveToFile(data3, "testdata/valid3-3.pb"); err != nil { + return err + } + + r4 := &testpb3.Record{ + Name: "test4", + Collection: []string{"1", "3"}, + Foo: &testpb3.Record_Foo{}, + } + data4, err := proto.Marshal(r4) + if err != nil { + return err + } + if err = saveToFile(data4, "testdata/valid3-4.pb"); err != nil { + return err + } + + r5 := &testpb3.Record{ + Name: "test5", + Foo: &testpb3.Record_Foo{}, + } + data5, err := proto.Marshal(r5) + if err != nil { + return err + } + if err = saveToFile(data5, "testdata/valid3-5.pb"); err != nil { + return err + } + + r6 := &testpb3.Record{ + Collection: []string{"1", "3"}, + Foo: &testpb3.Record_Foo{}, + } + data6, err := proto.Marshal(r6) + if err != nil { + return err + } + if err = saveToFile(data6, "testdata/valid3-6.pb"); err != nil { + return err + } + + r7 := &testpb3.Record{ + Name: "test7", + Collection: []string{"1", "3"}, + Foo: &testpb3.Record_Foo{}, + } + data7, err := proto.Marshal(r7) + if err != nil { + return err + } + if err = saveToFile(data7, "testdata/valid3-7.pb"); err != nil { + return err + } + + p := &person.Person{ + Name: "person", + Id: 1, + Email: "person@real.human", + Phones: []*person.Person_PhoneNumber{ + { + Number: "123456", + Type: person.Person_HOME, + }, + { + Number: "123457", + Type: person.Person_WORK, + }, + }, + LastUpdated: timestamppb.Now(), + } + data8, err := proto.Marshal(p) + if err != nil { + return err + } + if err = saveToFile(data8, "testdata/valid3-8.pb"); err != nil { + return err + } + + return nil +} + +//nolint:deadcode,unused +func saveToFile(data []byte, filename string) error { + file, err := os.Create(filename) + if err != nil { + return err + } + + w := bufio.NewWriter(file) + if _, err = w.Write(data); err != nil { + return err + } + if err = w.Flush(); err != nil { + return err + } + + return file.Close() +} diff --git a/validator/internal/validator/protobuf/testdata/invalid2-1.pb b/validator/internal/validator/protobuf/testdata/invalid2-1.pb new file mode 100644 index 0000000..c7fd144 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/invalid2-1.pb @@ -0,0 +1,2 @@ + +st5 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/invalid2-2.pb b/validator/internal/validator/protobuf/testdata/invalid2-2.pb new file mode 100644 index 0000000..e69de29 diff --git a/validator/internal/validator/protobuf/testdata/invalid3-1.pb b/validator/internal/validator/protobuf/testdata/invalid3-1.pb new file mode 100644 index 0000000..5466760 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/invalid3-1.pb @@ -0,0 +1,6 @@ + +personperson@real.human.com" + +123456" + +123457* Àà°Žàü×ê \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/person/schema3-2.pb.go b/validator/internal/validator/protobuf/testdata/person/schema3-2.pb.go new file mode 100644 index 0000000..aa93df4 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/person/schema3-2.pb.go @@ -0,0 +1,321 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.1 +// source: lib/validator/protobuf/testdata/schema3-2.proto + +package person + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Person_PhoneType int32 + +const ( + Person_MOBILE Person_PhoneType = 0 + Person_HOME Person_PhoneType = 1 + Person_WORK Person_PhoneType = 2 +) + +// Enum value maps for Person_PhoneType. +var ( + Person_PhoneType_name = map[int32]string{ + 0: "MOBILE", + 1: "HOME", + 2: "WORK", + } + Person_PhoneType_value = map[string]int32{ + "MOBILE": 0, + "HOME": 1, + "WORK": 2, + } +) + +func (x Person_PhoneType) Enum() *Person_PhoneType { + p := new(Person_PhoneType) + *p = x + return p +} + +func (x Person_PhoneType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Person_PhoneType) Descriptor() protoreflect.EnumDescriptor { + return file_lib_validator_protobuf_testdata_schema3_2_proto_enumTypes[0].Descriptor() +} + +func (Person_PhoneType) Type() protoreflect.EnumType { + return &file_lib_validator_protobuf_testdata_schema3_2_proto_enumTypes[0] +} + +func (x Person_PhoneType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Person_PhoneType.Descriptor instead. +func (Person_PhoneType) EnumDescriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescGZIP(), []int{0, 0} +} + +type Person struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Id int32 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` // Unique MessageID number for this person. + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Phones []*Person_PhoneNumber `protobuf:"bytes,4,rep,name=phones,proto3" json:"phones,omitempty"` + LastUpdated *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=last_updated,json=lastUpdated,proto3" json:"last_updated,omitempty"` +} + +func (x *Person) Reset() { + *x = Person{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Person) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Person) ProtoMessage() {} + +func (x *Person) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Person.ProtoReflect.Descriptor instead. +func (*Person) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescGZIP(), []int{0} +} + +func (x *Person) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Person) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Person) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *Person) GetPhones() []*Person_PhoneNumber { + if x != nil { + return x.Phones + } + return nil +} + +func (x *Person) GetLastUpdated() *timestamppb.Timestamp { + if x != nil { + return x.LastUpdated + } + return nil +} + +type Person_PhoneNumber struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` + Type Person_PhoneType `protobuf:"varint,2,opt,name=type,proto3,enum=testdata3.Person_PhoneType" json:"type,omitempty"` +} + +func (x *Person_PhoneNumber) Reset() { + *x = Person_PhoneNumber{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Person_PhoneNumber) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Person_PhoneNumber) ProtoMessage() {} + +func (x *Person_PhoneNumber) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Person_PhoneNumber.ProtoReflect.Descriptor instead. +func (*Person_PhoneNumber) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Person_PhoneNumber) GetNumber() string { + if x != nil { + return x.Number + } + return "" +} + +func (x *Person_PhoneNumber) GetType() Person_PhoneType { + if x != nil { + return x.Type + } + return Person_MOBILE +} + +var File_lib_validator_protobuf_testdata_schema3_2_proto protoreflect.FileDescriptor + +var file_lib_validator_protobuf_testdata_schema3_2_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, + 0x61, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x33, 0x2d, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x09, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x33, 0x1a, 0x1f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbd, 0x02, + 0x0a, 0x06, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x12, 0x35, 0x0a, 0x06, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x33, 0x2e, 0x50, + 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x06, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0c, 0x6c, 0x61, 0x73, + 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6c, 0x61, 0x73, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x56, 0x0a, 0x0b, 0x50, 0x68, 0x6f, 0x6e, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x33, 0x2e, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, + 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x2b, 0x0a, 0x09, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, + 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, + 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x42, 0x0a, 0x5a, + 0x08, 0x2e, 0x2f, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescOnce sync.Once + file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescData = file_lib_validator_protobuf_testdata_schema3_2_proto_rawDesc +) + +func file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescGZIP() []byte { + file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescOnce.Do(func() { + file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescData = protoimpl.X.CompressGZIP(file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescData) + }) + return file_lib_validator_protobuf_testdata_schema3_2_proto_rawDescData +} + +var file_lib_validator_protobuf_testdata_schema3_2_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_lib_validator_protobuf_testdata_schema3_2_proto_goTypes = []interface{}{ + (Person_PhoneType)(0), // 0: testdata3.Person.PhoneType + (*Person)(nil), // 1: testdata3.Person + (*Person_PhoneNumber)(nil), // 2: testdata3.Person.PhoneNumber + (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp +} +var file_lib_validator_protobuf_testdata_schema3_2_proto_depIdxs = []int32{ + 2, // 0: testdata3.Person.phones:type_name -> testdata3.Person.PhoneNumber + 3, // 1: testdata3.Person.last_updated:type_name -> google.protobuf.Timestamp + 0, // 2: testdata3.Person.PhoneNumber.type:type_name -> testdata3.Person.PhoneType + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_lib_validator_protobuf_testdata_schema3_2_proto_init() } +func file_lib_validator_protobuf_testdata_schema3_2_proto_init() { + if File_lib_validator_protobuf_testdata_schema3_2_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Person); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Person_PhoneNumber); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_lib_validator_protobuf_testdata_schema3_2_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_lib_validator_protobuf_testdata_schema3_2_proto_goTypes, + DependencyIndexes: file_lib_validator_protobuf_testdata_schema3_2_proto_depIdxs, + EnumInfos: file_lib_validator_protobuf_testdata_schema3_2_proto_enumTypes, + MessageInfos: file_lib_validator_protobuf_testdata_schema3_2_proto_msgTypes, + }.Build() + File_lib_validator_protobuf_testdata_schema3_2_proto = out.File + file_lib_validator_protobuf_testdata_schema3_2_proto_rawDesc = nil + file_lib_validator_protobuf_testdata_schema3_2_proto_goTypes = nil + file_lib_validator_protobuf_testdata_schema3_2_proto_depIdxs = nil +} diff --git a/validator/internal/validator/protobuf/testdata/schema2-1.proto b/validator/internal/validator/protobuf/testdata/schema2-1.proto new file mode 100644 index 0000000..f5890d2 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/schema2-1.proto @@ -0,0 +1,18 @@ +syntax = "proto2"; +package testdata2; + +option go_package = "./testpb2"; + +message Record { + required string name = 1; + optional int32 age = 2; + repeated string collection = 3; + + message Foo { + optional string bar = 1; + } + + optional Foo foo = 4; +} + + diff --git a/validator/internal/validator/protobuf/testdata/schema3-1.proto b/validator/internal/validator/protobuf/testdata/schema3-1.proto new file mode 100644 index 0000000..e5e7c91 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/schema3-1.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package testdata3; + +option go_package = "./testpb3"; + +message Record { + string name = 1; + int32 age = 2; + repeated string collection = 3; + + message Foo { + string bar = 1; + } + + Foo foo = 4; +} diff --git a/validator/internal/validator/protobuf/testdata/schema3-2.proto b/validator/internal/validator/protobuf/testdata/schema3-2.proto new file mode 100644 index 0000000..57ff06d --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/schema3-2.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package testdata3; + +option go_package = "./person"; + +import "google/protobuf/timestamp.proto"; + +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + string number = 1; + PhoneType type = 2; + } + + repeated PhoneNumber phones = 4; + + google.protobuf.Timestamp last_updated = 5; +} diff --git a/validator/internal/validator/protobuf/testdata/testpb2/schema2-1.pb.go b/validator/internal/validator/protobuf/testdata/testpb2/schema2-1.pb.go new file mode 100644 index 0000000..bce342a --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/testpb2/schema2-1.pb.go @@ -0,0 +1,235 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.1 +// source: lib/validator/protobuf/testdata/schema2-1.proto + +package testpb2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Record struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` + Age *int32 `protobuf:"varint,2,opt,name=age" json:"age,omitempty"` + Collection []string `protobuf:"bytes,3,rep,name=collection" json:"collection,omitempty"` + Foo *Record_Foo `protobuf:"bytes,4,opt,name=foo" json:"foo,omitempty"` +} + +func (x *Record) Reset() { + *x = Record{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Record) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Record) ProtoMessage() {} + +func (x *Record) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Record.ProtoReflect.Descriptor instead. +func (*Record) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescGZIP(), []int{0} +} + +func (x *Record) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *Record) GetAge() int32 { + if x != nil && x.Age != nil { + return *x.Age + } + return 0 +} + +func (x *Record) GetCollection() []string { + if x != nil { + return x.Collection + } + return nil +} + +func (x *Record) GetFoo() *Record_Foo { + if x != nil { + return x.Foo + } + return nil +} + +type Record_Foo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bar *string `protobuf:"bytes,1,opt,name=bar" json:"bar,omitempty"` +} + +func (x *Record_Foo) Reset() { + *x = Record_Foo{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Record_Foo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Record_Foo) ProtoMessage() {} + +func (x *Record_Foo) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Record_Foo.ProtoReflect.Descriptor instead. +func (*Record_Foo) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Record_Foo) GetBar() string { + if x != nil && x.Bar != nil { + return *x.Bar + } + return "" +} + +var File_lib_validator_protobuf_testdata_schema2_1_proto protoreflect.FileDescriptor + +var file_lib_validator_protobuf_testdata_schema2_1_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, + 0x61, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x32, 0x2d, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x09, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x32, 0x22, 0x90, 0x01, 0x0a, + 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, + 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x64, 0x61, 0x74, 0x61, 0x32, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x46, 0x6f, + 0x6f, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x1a, 0x17, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x12, 0x10, 0x0a, + 0x03, 0x62, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x62, 0x61, 0x72, 0x42, + 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x32, +} + +var ( + file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescOnce sync.Once + file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescData = file_lib_validator_protobuf_testdata_schema2_1_proto_rawDesc +) + +func file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescGZIP() []byte { + file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescOnce.Do(func() { + file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescData = protoimpl.X.CompressGZIP(file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescData) + }) + return file_lib_validator_protobuf_testdata_schema2_1_proto_rawDescData +} + +var file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_lib_validator_protobuf_testdata_schema2_1_proto_goTypes = []interface{}{ + (*Record)(nil), // 0: testdata2.Record + (*Record_Foo)(nil), // 1: testdata2.Record.Foo +} +var file_lib_validator_protobuf_testdata_schema2_1_proto_depIdxs = []int32{ + 1, // 0: testdata2.Record.foo:type_name -> testdata2.Record.Foo + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_lib_validator_protobuf_testdata_schema2_1_proto_init() } +func file_lib_validator_protobuf_testdata_schema2_1_proto_init() { + if File_lib_validator_protobuf_testdata_schema2_1_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Record); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Record_Foo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_lib_validator_protobuf_testdata_schema2_1_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_lib_validator_protobuf_testdata_schema2_1_proto_goTypes, + DependencyIndexes: file_lib_validator_protobuf_testdata_schema2_1_proto_depIdxs, + MessageInfos: file_lib_validator_protobuf_testdata_schema2_1_proto_msgTypes, + }.Build() + File_lib_validator_protobuf_testdata_schema2_1_proto = out.File + file_lib_validator_protobuf_testdata_schema2_1_proto_rawDesc = nil + file_lib_validator_protobuf_testdata_schema2_1_proto_goTypes = nil + file_lib_validator_protobuf_testdata_schema2_1_proto_depIdxs = nil +} diff --git a/validator/internal/validator/protobuf/testdata/testpb3/schema3-1.pb.go b/validator/internal/validator/protobuf/testdata/testpb3/schema3-1.pb.go new file mode 100644 index 0000000..d44646b --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/testpb3/schema3-1.pb.go @@ -0,0 +1,236 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.1 +// source: lib/validator/protobuf/testdata/schema3-1.proto + +package testpb3 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Record struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"` + Collection []string `protobuf:"bytes,3,rep,name=collection,proto3" json:"collection,omitempty"` + Foo *Record_Foo `protobuf:"bytes,4,opt,name=foo,proto3" json:"foo,omitempty"` +} + +func (x *Record) Reset() { + *x = Record{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Record) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Record) ProtoMessage() {} + +func (x *Record) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Record.ProtoReflect.Descriptor instead. +func (*Record) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescGZIP(), []int{0} +} + +func (x *Record) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Record) GetAge() int32 { + if x != nil { + return x.Age + } + return 0 +} + +func (x *Record) GetCollection() []string { + if x != nil { + return x.Collection + } + return nil +} + +func (x *Record) GetFoo() *Record_Foo { + if x != nil { + return x.Foo + } + return nil +} + +type Record_Foo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bar string `protobuf:"bytes,1,opt,name=bar,proto3" json:"bar,omitempty"` +} + +func (x *Record_Foo) Reset() { + *x = Record_Foo{} + if protoimpl.UnsafeEnabled { + mi := &file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Record_Foo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Record_Foo) ProtoMessage() {} + +func (x *Record_Foo) ProtoReflect() protoreflect.Message { + mi := &file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Record_Foo.ProtoReflect.Descriptor instead. +func (*Record_Foo) Descriptor() ([]byte, []int) { + return file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Record_Foo) GetBar() string { + if x != nil { + return x.Bar + } + return "" +} + +var File_lib_validator_protobuf_testdata_schema3_1_proto protoreflect.FileDescriptor + +var file_lib_validator_protobuf_testdata_schema3_1_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, + 0x61, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x33, 0x2d, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x09, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x33, 0x22, 0x90, 0x01, 0x0a, + 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, + 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x64, 0x61, 0x74, 0x61, 0x33, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x46, 0x6f, + 0x6f, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x1a, 0x17, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x12, 0x10, 0x0a, + 0x03, 0x62, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x62, 0x61, 0x72, 0x42, + 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x33, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescOnce sync.Once + file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescData = file_lib_validator_protobuf_testdata_schema3_1_proto_rawDesc +) + +func file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescGZIP() []byte { + file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescOnce.Do(func() { + file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescData = protoimpl.X.CompressGZIP(file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescData) + }) + return file_lib_validator_protobuf_testdata_schema3_1_proto_rawDescData +} + +var file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_lib_validator_protobuf_testdata_schema3_1_proto_goTypes = []interface{}{ + (*Record)(nil), // 0: testdata3.Record + (*Record_Foo)(nil), // 1: testdata3.Record.Foo +} +var file_lib_validator_protobuf_testdata_schema3_1_proto_depIdxs = []int32{ + 1, // 0: testdata3.Record.foo:type_name -> testdata3.Record.Foo + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_lib_validator_protobuf_testdata_schema3_1_proto_init() } +func file_lib_validator_protobuf_testdata_schema3_1_proto_init() { + if File_lib_validator_protobuf_testdata_schema3_1_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Record); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Record_Foo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_lib_validator_protobuf_testdata_schema3_1_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_lib_validator_protobuf_testdata_schema3_1_proto_goTypes, + DependencyIndexes: file_lib_validator_protobuf_testdata_schema3_1_proto_depIdxs, + MessageInfos: file_lib_validator_protobuf_testdata_schema3_1_proto_msgTypes, + }.Build() + File_lib_validator_protobuf_testdata_schema3_1_proto = out.File + file_lib_validator_protobuf_testdata_schema3_1_proto_rawDesc = nil + file_lib_validator_protobuf_testdata_schema3_1_proto_goTypes = nil + file_lib_validator_protobuf_testdata_schema3_1_proto_depIdxs = nil +} diff --git a/validator/internal/validator/protobuf/testdata/valid2-1.pb b/validator/internal/validator/protobuf/testdata/valid2-1.pb new file mode 100644 index 0000000..a7372c4 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid2-1.pb @@ -0,0 +1,3 @@ + +test1123" +bar1 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/valid2-2.pb b/validator/internal/validator/protobuf/testdata/valid2-2.pb new file mode 100644 index 0000000..6054f72 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid2-2.pb @@ -0,0 +1,3 @@ + +test212" +bar2 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/valid2-3.pb b/validator/internal/validator/protobuf/testdata/valid2-3.pb new file mode 100644 index 0000000000000000000000000000000000000000..8cbf14280aa1d8d521a946f3a538627ae5b38588 GIT binary patch literal 15 Wcmd;LElDjdF_vO9lwveiVgLXdF9N>+ literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid2-4.pb b/validator/internal/validator/protobuf/testdata/valid2-4.pb new file mode 100644 index 0000000..f4a180d --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid2-4.pb @@ -0,0 +1,2 @@ + +test413 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/valid3-1.pb b/validator/internal/validator/protobuf/testdata/valid3-1.pb new file mode 100644 index 0000000..a7372c4 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid3-1.pb @@ -0,0 +1,3 @@ + +test1123" +bar1 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/valid3-2.pb b/validator/internal/validator/protobuf/testdata/valid3-2.pb new file mode 100644 index 0000000..6054f72 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid3-2.pb @@ -0,0 +1,3 @@ + +test212" +bar2 \ No newline at end of file diff --git a/validator/internal/validator/protobuf/testdata/valid3-3.pb b/validator/internal/validator/protobuf/testdata/valid3-3.pb new file mode 100644 index 0000000000000000000000000000000000000000..8cbf14280aa1d8d521a946f3a538627ae5b38588 GIT binary patch literal 15 Wcmd;LElDjdF_vO9lwveiVgLXdF9N>+ literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid3-4.pb b/validator/internal/validator/protobuf/testdata/valid3-4.pb new file mode 100644 index 0000000000000000000000000000000000000000..d64acfc049b0d89b4d8855724d9fbe6dde266d7f GIT binary patch literal 15 Wcmd;LElDjdF_B_4lwveiVgLXdI0C=` literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid3-5.pb b/validator/internal/validator/protobuf/testdata/valid3-5.pb new file mode 100644 index 0000000000000000000000000000000000000000..a3e0ccf430cc7615a8f1c0a944b5148d849fa925 GIT binary patch literal 9 Qcmd;LElDjdF;!v!01F2KCjbBd literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid3-6.pb b/validator/internal/validator/protobuf/testdata/valid3-6.pb new file mode 100644 index 0000000000000000000000000000000000000000..f808bb2a9bcfca5ac6b23843acecee94e939593b GIT binary patch literal 8 Pcmb1QG?ZdAR$>4E184xf literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid3-7.pb b/validator/internal/validator/protobuf/testdata/valid3-7.pb new file mode 100644 index 0000000000000000000000000000000000000000..2550f2679923cec948359505c686ac3e97453c62 GIT binary patch literal 15 Wcmd;LElDjdF_&UAlwveiVgLXdQv$;P literal 0 HcmV?d00001 diff --git a/validator/internal/validator/protobuf/testdata/valid3-8.pb b/validator/internal/validator/protobuf/testdata/valid3-8.pb new file mode 100644 index 0000000..7d288a1 --- /dev/null +++ b/validator/internal/validator/protobuf/testdata/valid3-8.pb @@ -0,0 +1,6 @@ + +personperson@real.human" + +123456" + +123457* ŽìðŽàˆ¹` \ No newline at end of file diff --git a/validator/internal/validator/validator.go b/validator/internal/validator/validator.go new file mode 100644 index 0000000..5f169b2 --- /dev/null +++ b/validator/internal/validator/validator.go @@ -0,0 +1,37 @@ +// Package validator exposes common functionalities of all schema validators. +package validator + +import "github.com/pkg/errors" + +// ErrDeadletter is a special error type to help distinguish between invalid and broken messages. +var ErrDeadletter = errors.New("deadletter") + +// ErrBrokenMessage is a special error type to help distinguish broken messages. +var ErrBrokenMessage = errors.New("Message is not in valid format") + +// ErrWrongCompile is a special error type to help distinguish messages that had fault while compiling. +var ErrWrongCompile = errors.New("There is an error while compiling.") + +// ErrMissingSchema is a special error type to help distinguish messages that are missing schema. +var ErrMissingSchema = errors.New("Message is missing a schema") + +// ErrFailedValidation is a special error type to help distinguish messages that have failed in validation. +var ErrFailedValidation = errors.New("An error occured while validating message.") + +// Validator is the interface used to model message validators. +type Validator interface { + // Validate takes a message and a schema (along with schema id and version, in case they are needed for optimization purposes) + // and returns a bool value with the validation result. + // Returns an error in case the implementation encounters an unrecoverable issue. + // If the unrecoverable issue is a broken message or schema (for example, the given message isn't even in the + // valid format), ErrDeadletter MUST be returned. + Validate(message, schema []byte, id string, version string) (bool, error) +} + +// Func convenience type which is the functional equivalent of Validator. +type Func func(message, schema []byte, id string, version string) (bool, error) + +// Validate implements Validate by forwarding the call to the underlying ValidationFunc. +func (f Func) Validate(message, schema []byte, id string, version string) (bool, error) { + return f(message, schema, id, version) +} diff --git a/validator/internal/validator/xml/testdata/data-1.xml b/validator/internal/validator/xml/testdata/data-1.xml new file mode 100644 index 0000000..7e12b61 --- /dev/null +++ b/validator/internal/validator/xml/testdata/data-1.xml @@ -0,0 +1,24 @@ + + + + John Smith + + Ola Nordmann +

Langgt 23
+ 4000 Stavanger + Norway + + + Empire Burlesque + Special Edition + 1 + 10.90 + + + Hide your heart + 1 + 9.90 + + diff --git a/validator/internal/validator/xml/testdata/data-2.xml b/validator/internal/validator/xml/testdata/data-2.xml new file mode 100644 index 0000000..3c214b0 --- /dev/null +++ b/validator/internal/validator/xml/testdata/data-2.xml @@ -0,0 +1,9 @@ + + + All + my boss + Me + my boss + A new message xml format + lalalalalala + diff --git a/validator/internal/validator/xml/testdata/data-3.xml b/validator/internal/validator/xml/testdata/data-3.xml new file mode 100644 index 0000000..4a76903 --- /dev/null +++ b/validator/internal/validator/xml/testdata/data-3.xml @@ -0,0 +1,7 @@ + + + My Readers + Chaitanya + A Message to my readers + Welcome to beginnersbook.com + diff --git a/validator/internal/validator/xml/testdata/deadletter-1-data.xml b/validator/internal/validator/xml/testdata/deadletter-1-data.xml new file mode 100644 index 0000000..c91f644 --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-1-data.xml @@ -0,0 +1,7 @@ + +beginnersbook> + My Readers + Chaitanya + A Message to my readers + Welcome to beginnersbook.com + diff --git a/validator/internal/validator/xml/testdata/deadletter-1-schema.xsd b/validator/internal/validator/xml/testdata/deadletter-1-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-1-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/deadletter-2-data.xml b/validator/internal/validator/xml/testdata/deadletter-2-data.xml new file mode 100644 index 0000000..4a76903 --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-2-data.xml @@ -0,0 +1,7 @@ + + + My Readers + Chaitanya + A Message to my readers + Welcome to beginnersbook.com + diff --git a/validator/internal/validator/xml/testdata/deadletter-2-schema.xsd b/validator/internal/validator/xml/testdata/deadletter-2-schema.xsd new file mode 100644 index 0000000..3ee3ef8 --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-2-schema.xsd @@ -0,0 +1,15 @@ + + elementFormDefault="qualified"> + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/deadletter-3-data.xml b/validator/internal/validator/xml/testdata/deadletter-3-data.xml new file mode 100644 index 0000000..1ec13da --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-3-data.xml @@ -0,0 +1,8 @@ + + + My Readers + Chaitanya + A Message to my readers + Welcome to beginnersbook.com + +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/validator/internal/validator/xml/testdata/deadletter-3-schema.xsd b/validator/internal/validator/xml/testdata/deadletter-3-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/deadletter-3-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/invalid-1-data.xml b/validator/internal/validator/xml/testdata/invalid-1-data.xml new file mode 100644 index 0000000..3c214b0 --- /dev/null +++ b/validator/internal/validator/xml/testdata/invalid-1-data.xml @@ -0,0 +1,9 @@ + + + All + my boss + Me + my boss + A new message xml format + lalalalalala + diff --git a/validator/internal/validator/xml/testdata/invalid-1-schema.xsd b/validator/internal/validator/xml/testdata/invalid-1-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/invalid-1-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/invalid-2-data.xml b/validator/internal/validator/xml/testdata/invalid-2-data.xml new file mode 100644 index 0000000..6f1d49a --- /dev/null +++ b/validator/internal/validator/xml/testdata/invalid-2-data.xml @@ -0,0 +1,5 @@ + + + Myb invalid msg + l53222a + diff --git a/validator/internal/validator/xml/testdata/invalid-2-schema.xsd b/validator/internal/validator/xml/testdata/invalid-2-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/invalid-2-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/schema-1.xsd b/validator/internal/validator/xml/testdata/schema-1.xsd new file mode 100644 index 0000000..22a30db --- /dev/null +++ b/validator/internal/validator/xml/testdata/schema-1.xsd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/schema-2.xsd b/validator/internal/validator/xml/testdata/schema-2.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/schema-2.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/schema-3.xsd b/validator/internal/validator/xml/testdata/schema-3.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/schema-3.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/valid-1-data.xml b/validator/internal/validator/xml/testdata/valid-1-data.xml new file mode 100644 index 0000000..4a76903 --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-1-data.xml @@ -0,0 +1,7 @@ + + + My Readers + Chaitanya + A Message to my readers + Welcome to beginnersbook.com + diff --git a/validator/internal/validator/xml/testdata/valid-1-schema.xsd b/validator/internal/validator/xml/testdata/valid-1-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-1-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/valid-2-data.xml b/validator/internal/validator/xml/testdata/valid-2-data.xml new file mode 100644 index 0000000..984f1d9 --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-2-data.xml @@ -0,0 +1,7 @@ + + + My team + myselfmeandI + Test subject idk + I luv you myteam + diff --git a/validator/internal/validator/xml/testdata/valid-2-schema.xsd b/validator/internal/validator/xml/testdata/valid-2-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-2-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/testdata/valid-3-data.xml b/validator/internal/validator/xml/testdata/valid-3-data.xml new file mode 100644 index 0000000..5aad282 --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-3-data.xml @@ -0,0 +1,7 @@ + + + All + Me + A new message xml format + lalalalalala + diff --git a/validator/internal/validator/xml/testdata/valid-3-schema.xsd b/validator/internal/validator/xml/testdata/valid-3-schema.xsd new file mode 100644 index 0000000..629ae9f --- /dev/null +++ b/validator/internal/validator/xml/testdata/valid-3-schema.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/validator/internal/validator/xml/xml.go b/validator/internal/validator/xml/xml.go new file mode 100644 index 0000000..ccd03a2 --- /dev/null +++ b/validator/internal/validator/xml/xml.go @@ -0,0 +1,61 @@ +package xml + +import ( + "bytes" + "context" + "encoding/xml" + "io" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-retry/pkg/retry" + + "github.com/pkg/errors" +) + +type Validator struct { + Url string + TimeoutBase time.Duration +} + +const DefaultTimeoutBase = 3 * time.Second + +// New returns a new validator which validates XML messages against a schema. +// +// Performs a health check to see if the validator is available, retrying periodically until the context is cancelled +// or the health check succeeds. +func New(ctx context.Context, url string, timeoutBase time.Duration) (validator.Validator, error) { + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach xml validator at %s failed", url) + } + + return &Validator{ + Url: url, + TimeoutBase: timeoutBase, + }, nil +} + +func (v *Validator) Validate(message, schema []byte, _, _ string) (bool, error) { + if !IsXML(message) || !IsXML(schema) { + return false, validator.ErrDeadletter + } + + ctx, cancel := context.WithTimeout(context.Background(), validator.EstimateHTTPTimeout(len(message), v.TimeoutBase)) + defer cancel() + + return validator.ValidateOverHTTP(ctx, message, schema, v.Url) +} + +// IsXML checks if given data is valid XML. +func IsXML(data []byte) bool { + decoder := xml.NewDecoder(bytes.NewReader(data)) + for { + _, err := decoder.Token() + if err != nil { + return err == io.EOF + } + } +} diff --git a/validator/internal/validator/xml/xml_test.go b/validator/internal/validator/xml/xml_test.go new file mode 100644 index 0000000..49838f8 --- /dev/null +++ b/validator/internal/validator/xml/xml_test.go @@ -0,0 +1,128 @@ +package xml + +import ( + "context" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-internal/internal/validator" + + "github.com/pkg/errors" +) + +func TestNew(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + healthChecked := false + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + healthChecked = true + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + _, err := New(context.Background(), srv.URL, DefaultTimeoutBase) + if err != nil { + t.Fatal(err) + } + if !healthChecked { + t.Error("health check not called") + } +} + +func TestNewTimeout(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet && r.URL.Path == "/health" { + time.Sleep(2 * time.Minute) + w.WriteHeader(http.StatusOK) + } else { + t.Fatal("wrong endpoint hit") + } + })) + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + _, err := New(ctx, srv.URL, DefaultTimeoutBase) + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatal("expected timeout") + } +} + +func TestXMLValidator_Validate(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + + xmlV, err := New(context.Background(), "http://localhost:8089", DefaultTimeoutBase) + if err != nil { + t.Fatal("validator constructor error", err) + } + + tt := []struct { + name string + dataFilename string + schemaFilename string + valid bool + deadletter bool + }{ + {"valid-1", "valid-1-data.xml", "valid-1-schema.xsd", true, false}, + {"valid-2", "valid-2-data.xml", "valid-2-schema.xsd", true, false}, + {"valid-3", "valid-3-data.xml", "valid-3-schema.xsd", true, false}, + {"invalid-1", "invalid-1-data.xml", "invalid-1-schema.xsd", false, false}, + {"invalid-2", "invalid-2-data.xml", "invalid-2-schema.xsd", false, false}, + {"deadletter-1", "deadletter-1-data.xml", "deadletter-1-schema.xsd", false, true}, + {"deadletter-2", "deadletter-2-data.xml", "deadletter-2-schema.xsd", false, true}, + {"deadletter-3", "deadletter-3-data.xml", "deadletter-3-schema.xsd", false, true}, + {"data-1", "data-1.xml", "schema-1.xsd", true, false}, + {"data-2", "data-2.xml", "schema-2.xsd", false, false}, + {"data-3", "data-3.xml", "schema-3.xsd", true, false}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + data, err := os.ReadFile(filepath.Join(testdataDir, tc.dataFilename)) + if err != nil { + t.Errorf("data read error: %s", err) + } + schema, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Errorf("schema read error: %s", err) + } + + valid, err := xmlV.Validate(data, schema, "", "") + if tc.deadletter { + if !errors.Is(err, validator.ErrDeadletter) { + t.Error("deadletter expected") + } + } else { + if err != nil { + t.Errorf("validator error: %s", err) + } + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + } + }) + } +} diff --git a/validator/licenses/LICENSE-3RD-PARTY.md b/validator/licenses/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..92f761d --- /dev/null +++ b/validator/licenses/LICENSE-3RD-PARTY.md @@ -0,0 +1,62 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + +| software | license link | license | +|---------------------------------|------------------------------------------------------------------|--------------| +| cloud.google.com/go/compute/metadata | https://github.com/googleapis/google-cloud-go/blob/compute/v1.7.0/compute/LICENSE | Apache-2.0 | +| cloud.google.com/go/iam | https://github.com/googleapis/google-cloud-go/blob/iam/v0.3.0/iam/LICENSE | Apache-2.0 | +| cloud.google.com/go/internal | https://github.com/googleapis/google-cloud-go/blob/v0.102.1/LICENSE | Apache-2.0 | +| cloud.google.com/go/pubsub | https://github.com/googleapis/google-cloud-go/blob/pubsub/v1.24.0/pubsub/LICENSE | Apache-2.0 | +| github.com/Azure/azure-sdk-for-go/sdk/azcore | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azcore/v1.0.0/sdk/azcore/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/internal | https://github.com/Azure/azure-sdk-for-go/blob/sdk/internal/v1.0.0/sdk/internal/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v1.1.0/sdk/messaging/azservicebus/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus/internal/go-amqp | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v1.1.0/sdk/messaging/azservicebus/internal\go-amqp\LICENSE | MIT | +| github.com/go-playground/locales | https://github.com/go-playground/locales/blob/v0.14.0/LICENSE | MIT | +| github.com/go-playground/universal-translator | https://github.com/go-playground/universal-translator/blob/v0.18.0/LICENSE | MIT | +| github.com/go-playground/validator/v10 | https://github.com/go-playground/validator/blob/v10.11.0/LICENSE | MIT | +| github.com/golang/groupcache/lru | https://github.com/golang/groupcache/blob/8c9f03a8e57e/LICENSE | Apache-2.0 | +| github.com/golang/protobuf | https://github.com/golang/protobuf/blob/v1.5.2/LICENSE | BSD-3-Clause | +| github.com/google/go-cmp/cmp | https://github.com/google/go-cmp/blob/v0.5.8/LICENSE | BSD-3-Clause | +| github.com/googleapis/enterprise-certificate-proxy/client | https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.1.0/LICENSE | Apache-2.0 | +| github.com/googleapis/gax-go/v2 | https://github.com/googleapis/gax-go/blob/v2.4.0/v2/LICENSE | BSD-3-Clause | +| github.com/hamba/avro | https://github.com/hamba/avro/blob/v1.8.0/LICENCE | MIT | +| github.com/hashicorp/golang-lru | https://github.com/hashicorp/golang-lru/blob/v0.5.4/LICENSE | MPL-2.0 | +| github.com/jhump/protoreflect | https://github.com/jhump/protoreflect/blob/v1.12.0/LICENSE | Apache-2.0 | +| github.com/json-iterator/go | https://github.com/json-iterator/go/blob/v1.1.12/LICENSE | MIT | +| github.com/kkyr/fig | https://github.com/kkyr/fig/blob/v0.3.0/LICENSE | Apache-2.0 | +| github.com/klauspost/compress | https://github.com/klauspost/compress/blob/v1.15.9/LICENSE | Apache-2.0 | +| github.com/klauspost/compress/internal/snapref | https://github.com/klauspost/compress/blob/v1.15.9/internal\snapref\LICENSE | BSD-3-Clause | +| github.com/klauspost/compress/s2 | https://github.com/klauspost/compress/blob/v1.15.9/s2\LICENSE | BSD-3-Clause | +| github.com/klauspost/compress/zstd/internal/xxhash | https://github.com/klauspost/compress/blob/v1.15.9/zstd\internal\xxhash\LICENSE.txt | MIT | +| github.com/leodido/go-urn | https://github.com/leodido/go-urn/blob/v1.2.1/LICENSE | MIT | +| github.com/mitchellh/mapstructure | https://github.com/mitchellh/mapstructure/blob/v1.4.1/LICENSE | MIT | +| github.com/modern-go/concurrent | https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE | Apache-2.0 | +| github.com/modern-go/reflect2 | https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE | Apache-2.0 | +| github.com/nats-io/nats.go | https://github.com/nats-io/nats.go/blob/v1.16.0/LICENSE | Apache-2.0 | +| github.com/nats-io/nkeys | https://github.com/nats-io/nkeys/blob/v0.3.0/LICENSE | Apache-2.0 | +| github.com/nats-io/nuid | https://github.com/nats-io/nuid/blob/v1.0.1/LICENSE | Apache-2.0 | +| github.com/pelletier/go-toml | https://github.com/pelletier/go-toml/blob/v1.9.3/LICENSE | Apache-2.0 | +| github.com/pierrec/lz4/v4 | https://github.com/pierrec/lz4/blob/v4.1.15/LICENSE | BSD-3-Clause | +| github.com/pkg/errors | https://github.com/pkg/errors/blob/v0.9.1/LICENSE | BSD-2-Clause | +| github.com/santhosh-tekuri/jsonschema/v5 | https://github.com/santhosh-tekuri/jsonschema/blob/v5.0.0/LICENSE | Apache-2.0 | +| github.com/twmb/franz-go/pkg | https://github.com/twmb/franz-go/blob/v1.7.0/LICENSE | BSD-3-Clause | +| github.com/twmb/franz-go/pkg/kmsg | https://github.com/twmb/franz-go/blob/pkg/kmsg/v1.2.0/pkg/kmsg/LICENSE | BSD-3-Clause | +| github.com/xeipuuv/gojsonpointer | https://github.com/xeipuuv/gojsonpointer/blob/4e3ac2762d5f/LICENSE-APACHE-2.0.txt | Apache-2.0 | +| github.com/xeipuuv/gojsonreference | https://github.com/xeipuuv/gojsonreference/blob/bd5ef7bd5415/LICENSE-APACHE-2.0.txt | Apache-2.0 | +| github.com/xeipuuv/gojsonschema | https://github.com/xeipuuv/gojsonschema/blob/v1.2.0/LICENSE-APACHE-2.0.txt | Apache-2.0 | +| go.opencensus.io | https://github.com/census-instrumentation/opencensus-go/blob/v0.23.0/LICENSE | Apache-2.0 | +| go.uber.org/atomic | https://github.com/uber-go/atomic/blob/v1.7.0/LICENSE.txt | MIT | +| go.uber.org/multierr | https://github.com/uber-go/multierr/blob/v1.6.0/LICENSE.txt | MIT | +| go.uber.org/zap | https://github.com/uber-go/zap/blob/v1.16.0/LICENSE.txt | MIT | +| golang.org/x/crypto | https://cs.opensource.google/go/x/crypto/+/bc19a97f:LICENSE | BSD-3-Clause | +| golang.org/x/net | https://cs.opensource.google/go/x/net/+/c90051bb:LICENSE | BSD-3-Clause | +| golang.org/x/oauth2 | https://cs.opensource.google/go/x/oauth2/+/fd043fe5:LICENSE | BSD-3-Clause | +| golang.org/x/sync | https://cs.opensource.google/go/x/sync/+/886fb937:LICENSE | BSD-3-Clause | +| golang.org/x/text | https://cs.opensource.google/go/x/text/+/v0.3.7:LICENSE | BSD-3-Clause | +| google.golang.org/api | https://github.com/googleapis/google-api-go-client/blob/v0.91.0/LICENSE | BSD-3-Clause | +| google.golang.org/api/internal/third_party/uritemplates | https://github.com/googleapis/google-api-go-client/blob/v0.91.0/internal hird_party\uritemplates\LICENSE | BSD-3-Clause | +| google.golang.org/genproto | https://github.com/googleapis/go-genproto/blob/8cd45d7dbd1f/LICENSE | Apache-2.0 | +| google.golang.org/grpc | https://github.com/grpc/grpc-go/blob/v1.48.0/LICENSE | Apache-2.0 | +| google.golang.org/protobuf | https://github.com/protocolbuffers/protobuf-go/blob/v1.28.1/LICENSE | BSD-3-Clause | +| gopkg.in/yaml.v2 | https://github.com/go-yaml/yaml/blob/v2.4.0/LICENSE | Apache-2.0 | diff --git a/validator/licenses/csv-validator/LICENSE-3RD-PARTY.md b/validator/licenses/csv-validator/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..4489b2a --- /dev/null +++ b/validator/licenses/csv-validator/LICENSE-3RD-PARTY.md @@ -0,0 +1,84 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - http://logback.qos.ch/logback-classic) + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.2.3 - http://logback.qos.ch/logback-core) + (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.11.4 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.11.4 - https://github.com/FasterXML/jackson-core) + (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.11.4 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) + (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) + (The Apache Software License, Version 2.0) Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) + (MIT) gfc-semver (com.gilt:gfc-semver_2.11:0.0.5 - https://github.com/gilt/gfc-semver) + (Scala License) scala-io-core (com.github.scala-incubator.io:scala-io-core_2.11:0.4.3-1 - http://jesseeichar.github.com/scala-io-doc/index.html) + (Scala License) scala-io-file (com.github.scala-incubator.io:scala-io-file_2.11:0.4.3-1 - http://jesseeichar.github.com/scala-io-doc/index.html) + (The Apache Software License, Version 2.0) project ':json-path' (com.jayway.jsonpath:json-path:2.4.0 - https://github.com/jayway/JsonPath) + (BSD-Style) scala-arm (com.madgag:scala-arm_2.11:1.3.4 - http://jsuereth.com/scala-arm) + (Apache 2) opencsv (com.opencsv:opencsv:3.3 - http://opencsv.sf.net) + (Apache License 2.0) JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk) + (The Apache Software License, Version 2.0) Commons IO (commons-io:commons-io:1.3.2 - http://jakarta.apache.org/commons/io/) + (EDL 1.0) Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) + (EPL 2.0) (GPL2 w/ CPE) Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca) + (Eclipse Distribution License - v 1.0) Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) + (Apache 2) Joda time (joda-time:joda-time:1.6.2 - http://joda-time.sourceforge.net) + (Apache License, Version 2.0) Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.10.22 - https://bytebuddy.net/byte-buddy) + (Apache License, Version 2.0) Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.10.22 - https://bytebuddy.net/byte-buddy-agent) + (The Apache Software License, Version 2.0) ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/) + (The Apache Software License, Version 2.0) JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/) + (Apache License, Version 2.0) Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/) + (Apache License, Version 2.0) Apache Log4j API (org.apache.logging.log4j:log4j-api:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-api/) + (Apache License, Version 2.0) Apache Log4j to SLF4J Adapter (org.apache.logging.log4j:log4j-to-slf4j:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-to-slf4j/) + (Apache License, Version 2.0) tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.44 - https://tomcat.apache.org/) + (Apache License, Version 2.0) tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.44 - https://tomcat.apache.org/) + (The Apache License, Version 2.0) org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.0 - https://github.com/apiguardian-team/apiguardian) + (Apache License, Version 2.0) AssertJ fluent assertions (org.assertj:assertj-core:3.18.1 - https://assertj.github.io/doc/assertj-core/) + (EPL 2.0) (GPL2 w/ CPE) Jakarta Expression Language 3.0 (org.glassfish:jakarta.el:3.0.3 - https://projects.eclipse.org/projects/ee4j.el) + (BSD License 3) Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/) + (Eclipse Public License v2.0) JUnit Jupiter (Aggregator) (org.junit.jupiter:junit-jupiter:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter API (org.junit.jupiter:junit-jupiter-api:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Engine (org.junit.jupiter:junit-jupiter-engine:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Params (org.junit.jupiter:junit-jupiter-params:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Commons (org.junit.platform:junit-platform-commons:1.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Engine API (org.junit.platform:junit-platform-engine:1.7.1 - https://junit.org/junit5/) + (The MIT License) mockito-core (org.mockito:mockito-core:3.6.28 - https://github.com/mockito/mockito) + (The MIT License) mockito-junit-jupiter (org.mockito:mockito-junit-jupiter:3.6.28 - https://github.com/mockito/mockito) + (Apache License, Version 2.0) Objenesis (org.objenesis:objenesis:3.1 - http://objenesis.org) + (The Apache License, Version 2.0) org.opentest4j:opentest4j (org.opentest4j:opentest4j:1.2.0 - https://github.com/ota4j-team/opentest4j) + (BSD) ASM Core (org.ow2.asm:asm:5.0.4 - http://asm.objectweb.org/asm/) + (BSD 3-Clause) Scala Library (org.scala-lang:scala-library:2.11.7 - http://www.scala-lang.org/) + (BSD 3-clause) scala-parser-combinators (org.scala-lang.modules:scala-parser-combinators_2.11:1.0.1 - http://www.scala-lang.org/) + (BSD 3-clause) scala-continuations-library (org.scala-lang.plugins:scala-continuations-library_2.11:1.0.1 - http://www.scala-lang.org/) + (BSD-style) scalaz-concurrent (org.scalaz:scalaz-concurrent_2.11:7.2.0 - http://scalaz.org) + (BSD-style) scalaz-core (org.scalaz:scalaz-core_2.11:7.2.0 - http://scalaz.org) + (BSD-style) scalaz-effect (org.scalaz:scalaz-effect_2.11:7.2.0 - http://scalaz.org) + (MIT) scalaz-stream (org.scalaz.stream:scalaz-stream_2.11:0.7.3a - https://github.com/scalaz/scalaz-stream) + (Three-clause BSD-style) scodec-bits (org.scodec:scodec-bits_2.11:1.0.6 - http://github.com/scodec/scodec-bits) + (The Apache Software License, Version 2.0) JSONassert (org.skyscreamer:jsonassert:1.5.0 - https://github.com/skyscreamer/JSONassert) + (MIT License) JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.30 - http://www.slf4j.org) + (MIT License) SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org) + (Apache License, Version 2.0) Spring AOP (org.springframework:spring-aop:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Beans (org.springframework:spring-beans:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Context (org.springframework:spring-context:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Core (org.springframework:spring-core:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring TestContext Framework (org.springframework:spring-test:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web (org.springframework:spring-web:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web MVC (org.springframework:spring-webmvc:5.3.5 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) spring-boot (org.springframework.boot:spring-boot:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-devtools (org.springframework.boot:spring-boot-devtools:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter (org.springframework.boot:spring-boot-starter:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-logging (org.springframework.boot:spring-boot-starter-logging:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test (org.springframework.boot:spring-boot-test:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (The Apache Software License, Version 2.0) org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.7.0 - https://www.xmlunit.org/) + (Apache License, Version 2.0) SnakeYAML (org.yaml:snakeyaml:1.27 - http://www.snakeyaml.org) + (The Mozilla Public License Version 2.0) csv-validator-core (uk.gov.nationalarchives:csv-validator-core:1.1.5 - http://digital-preservation.github.com/csv-validator/csv-validator-core/) + (The Mozilla Public License Version 2.0) csv-validator-java-api (uk.gov.nationalarchives:csv-validator-java-api:1.1.5 - http://digital-preservation.github.com/csv-validator/csv-validator-java-api/) + (The BSD 3-Clause License) UTF-8 Vaidator (uk.gov.nationalarchives:utf8-validator:1.2 - https://github.com/digital-preservation/utf8-validator) diff --git a/validator/licenses/xml-validator/LICENSE-3RD-PARTY.md b/validator/licenses/xml-validator/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..cc95099 --- /dev/null +++ b/validator/licenses/xml-validator/LICENSE-3RD-PARTY.md @@ -0,0 +1,29 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + +Flask 2.0.1 BSD License + +Jinja2 3.0.1 BSD License + +MarkupSafe 2.0.1 BSD License + +Werkzeug 2.0.1 BSD License + +asgiref 3.5.2 BSD License + +click 8.0.1 BSD License + +colorama 0.4.4 BSD License + +elementpath 2.2.3 MIT License + +itsdangerous 2.0.1 BSD License + +sqlparse 0.4.3 BSD License + +tzdata 2022.5 Apache Software License + +waitress 2.0.0 Zope Public License + +xmlschema 1.7.0 MIT License From 8e9ae089c37c975a967845460abc55e75ca2b933 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 09:37:23 +0200 Subject: [PATCH 02/31] feat: initial SR implementation - added SR files - fixed imports and go.mods - in processor.go, init.go, logging.go changed the flow callbacks logic --- .github/workflows/push.yaml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index de87f20..1296a28 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -91,14 +91,20 @@ jobs: strategy: matrix: component: - - dockerfile-path: ./persistor/docker/persistor/Dockerfile - image-name: persistor-core - - dockerfile-path: ./persistor/docker/indexer/Dockerfile - image-name: persistor-indexer - - dockerfile-path: ./indexer-api/Dockerfile - image-name: persistor-indexer-api - - dockerfile-path: ./resubmitter-api/Dockerfile - image-name: persistor-resubmitter + - dockerfile-path: ./validator/docker/csv-validator/Dockerfile + image-name: schema-registry-csv-val + - dockerfile-path: ./validator/docker/validator/Dockerfile + image-name: schema-registry-worker + - dockerfile-path: ./validator/docker/xml-validator/Dockerfile + image-name: schema-registry-xml-val + - dockerfile-path: ./registry/docker/compatibility-checker/Dockerfile + image-name: schema-registry-compatibility + - dockerfile-path: ./registry/docker/initdb/Dockerfile + image-name: schema-registry-initdb + - dockerfile-path: ./registry/docker/registry/Dockerfile + image-name: schema-registry-api + - dockerfile-path: ./registry/docker/validity-checker/Dockerfile + image-name: schema-registry-validity steps: - name: Check out code From b32a3d00b24b18c146302993c55dc699e27b0791 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 09:51:14 +0200 Subject: [PATCH 03/31] style: editor config fixes & hadolint --- README.md | 2 +- registry/docker/initdb/Dockerfile | 2 +- registry/docker/registry-firestore/Dockerfile | 2 +- registry/docker/registry/Dockerfile | 2 +- registry/docs/swagger.json | 2 +- validator/docker/validator/Dockerfile | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 77c9b4d..68de3de 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,4 @@ All of the other requirements for the product to fully-function (message broker For all the inquiries regarding contributing to the project, be sure to check out the information in the [CONTRIBUTING.md](CONTRIBUTING.md) file. ## License -This project is licensed under the [Apache 2.0 License](LICENSE). \ No newline at end of file +This project is licensed under the [Apache 2.0 License](LICENSE). diff --git a/registry/docker/initdb/Dockerfile b/registry/docker/initdb/Dockerfile index 843fe78..720d422 100644 --- a/registry/docker/initdb/Dockerfile +++ b/registry/docker/initdb/Dockerfile @@ -11,7 +11,7 @@ RUN apk add --no-cache git WORKDIR /src -COPY ./registry/go.mod ./registry/go.sum . +COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download COPY ./schema-registry . diff --git a/registry/docker/registry-firestore/Dockerfile b/registry/docker/registry-firestore/Dockerfile index 4818ac0..3eef5b6 100644 --- a/registry/docker/registry-firestore/Dockerfile +++ b/registry/docker/registry-firestore/Dockerfile @@ -11,7 +11,7 @@ RUN apk add --no-cache git WORKDIR /src -COPY ./registry/go.mod ./registry/go.sum . +COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download COPY ./schema-registry . diff --git a/registry/docker/registry/Dockerfile b/registry/docker/registry/Dockerfile index 1d43da6..064a641 100644 --- a/registry/docker/registry/Dockerfile +++ b/registry/docker/registry/Dockerfile @@ -11,7 +11,7 @@ RUN apk add --no-cache git WORKDIR /src -COPY ./registry/go.mod ./registry/go.sum . +COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download COPY ./schema-registry . diff --git a/registry/docs/swagger.json b/registry/docs/swagger.json index c4687fc..985bafe 100644 --- a/registry/docs/swagger.json +++ b/registry/docs/swagger.json @@ -460,4 +460,4 @@ } } } -} \ No newline at end of file +} diff --git a/validator/docker/validator/Dockerfile b/validator/docker/validator/Dockerfile index 0a91492..f0753a0 100644 --- a/validator/docker/validator/Dockerfile +++ b/validator/docker/validator/Dockerfile @@ -11,7 +11,7 @@ RUN apk add --no-cache git WORKDIR /src -COPY ./validator/go.mod ./validator/go.sum . +COPY ./validator/go.mod ./validator/go.sum ./ RUN go mod download COPY ./validator . From deea6775c399e26b65883399c81572e434c9a85e Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 09:52:46 +0200 Subject: [PATCH 04/31] style: editor config fixes --- registry/docs/docs.go | 910 +++++++++++++++++++++--------------------- 1 file changed, 455 insertions(+), 455 deletions(-) diff --git a/registry/docs/docs.go b/registry/docs/docs.go index d781fda..b07b432 100644 --- a/registry/docs/docs.go +++ b/registry/docs/docs.go @@ -8,467 +8,467 @@ const docTemplate = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/schemas": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all active schemas", - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Post new schema", - "parameters": [ - { - "description": "schema registration request", - "name": "data", - "in": "body", - "schema": { - "$ref": "#/definitions/registry.SchemaRegistrationRequest" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request" - }, - "409": { - "description": "Conflict" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/all": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all schemas", - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/search": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Search schemas", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "query" - }, - { - "type": "string", - "description": "schema version", - "name": "version", - "in": "query" - }, - { - "type": "string", - "description": "schema type", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "schema name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "order by name, type, id or version", - "name": "orderBy", - "in": "query" - }, - { - "type": "string", - "description": "sort schemas either asc or desc", - "name": "sort", - "in": "query" - }, - { - "type": "string", - "description": "maximum number of retrieved schemas matching the criteria", - "name": "limit", - "in": "query" - }, - { - "type": "string", - "description": "schema attributes", - "name": "attributes", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Put new schema version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "schema update request", - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/registry.SchemaUpdateRequest" - } - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - }, - "409": { - "description": "Conflict" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "summary": "Delete schema by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - } - } - } - }, - "/schemas/{id}/versions": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all active schema versions by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/all": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/latest": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get the latest schema version by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/{version}": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema version by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Delete schema version by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - } - } - } - }, - "/schemas/{id}/versions/{version}/spec": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema specification by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - } + "/schemas": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Post new schema", + "parameters": [ + { + "description": "schema registration request", + "name": "data", + "in": "body", + "schema": { + "$ref": "#/definitions/registry.SchemaRegistrationRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/search": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Search schemas", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "schema version", + "name": "version", + "in": "query" + }, + { + "type": "string", + "description": "schema type", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "schema name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "order by name, type, id or version", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "sort schemas either asc or desc", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "maximum number of retrieved schemas matching the criteria", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "schema attributes", + "name": "attributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}": { + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Put new schema version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "schema update request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/registry.SchemaUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "summary": "Delete schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schema versions by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/latest": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get the latest schema version by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/{version}": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Delete schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions/{version}/spec": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema specification by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } }, "definitions": { - "registry.SchemaRegistrationRequest": { - "type": "object", - "properties": { - "attributes": { - "type": "string" - }, - "compatibility_mode": { - "type": "string" - }, - "description": { - "type": "string" - }, - "last_created": { - "type": "string" - }, - "name": { - "type": "string" - }, - "publisher_id": { - "type": "string" - }, - "schema_type": { - "type": "string" - }, - "specification": { - "type": "string" - }, - "validity_mode": { - "type": "string" - } - } - }, - "registry.SchemaUpdateRequest": { - "type": "object", - "properties": { - "attributes": { - "type": "string" - }, - "description": { - "type": "string" - }, - "specification": { - "type": "string" - } - } - } + "registry.SchemaRegistrationRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "compatibility_mode": { + "type": "string" + }, + "description": { + "type": "string" + }, + "last_created": { + "type": "string" + }, + "name": { + "type": "string" + }, + "publisher_id": { + "type": "string" + }, + "schema_type": { + "type": "string" + }, + "specification": { + "type": "string" + }, + "validity_mode": { + "type": "string" + } + } + }, + "registry.SchemaUpdateRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "specification": { + "type": "string" + } + } + } } }` From b7a98931f16bfaaaa552daa9912ab5483058fd30 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:03:10 +0200 Subject: [PATCH 05/31] style: editor config fixes --- .editorconfig | 2 + .github/workflows/pr.yaml | 1 + registry/docs/docs.go | 910 +++++++++++++++++++------------------- 3 files changed, 458 insertions(+), 455 deletions(-) diff --git a/.editorconfig b/.editorconfig index e908007..fd277fc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -72,3 +72,5 @@ indent_size = unset [**/LICENSE-3RD-PARTY.md] insert_final_newline = unset +[**/docs.go] +indent_style = unset diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 12859f1..10d8291 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -271,6 +271,7 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: component: - dockerfile-path: ./validator/docker/csv-validator/Dockerfile diff --git a/registry/docs/docs.go b/registry/docs/docs.go index b07b432..d781fda 100644 --- a/registry/docs/docs.go +++ b/registry/docs/docs.go @@ -8,467 +8,467 @@ const docTemplate = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/schemas": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all active schemas", - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Post new schema", - "parameters": [ - { - "description": "schema registration request", - "name": "data", - "in": "body", - "schema": { - "$ref": "#/definitions/registry.SchemaRegistrationRequest" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request" - }, - "409": { - "description": "Conflict" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/all": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all schemas", - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/search": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Search schemas", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "query" - }, - { - "type": "string", - "description": "schema version", - "name": "version", - "in": "query" - }, - { - "type": "string", - "description": "schema type", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "schema name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "order by name, type, id or version", - "name": "orderBy", - "in": "query" - }, - { - "type": "string", - "description": "sort schemas either asc or desc", - "name": "sort", - "in": "query" - }, - { - "type": "string", - "description": "maximum number of retrieved schemas matching the criteria", - "name": "limit", - "in": "query" - }, - { - "type": "string", - "description": "schema attributes", - "name": "attributes", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}": { - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Put new schema version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "schema update request", - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/registry.SchemaUpdateRequest" - } - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - }, - "409": { - "description": "Conflict" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "delete": { - "produces": [ - "application/json" - ], - "summary": "Delete schema by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - } - } - } - }, - "/schemas/{id}/versions": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get all active schema versions by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/all": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/latest": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get the latest schema version by schema id", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/schemas/{id}/versions/{version}": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema version by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Delete schema version by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request" - }, - "404": { - "description": "Not Found" - } - } - } - }, - "/schemas/{id}/versions/{version}/spec": { - "get": { - "produces": [ - "application/json" - ], - "summary": "Get schema specification by schema id and version", - "parameters": [ - { - "type": "string", - "description": "schema id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "version", - "name": "version", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - } + "/schemas": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Post new schema", + "parameters": [ + { + "description": "schema registration request", + "name": "data", + "in": "body", + "schema": { + "$ref": "#/definitions/registry.SchemaRegistrationRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/search": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Search schemas", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "schema version", + "name": "version", + "in": "query" + }, + { + "type": "string", + "description": "schema type", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "schema name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "order by name, type, id or version", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "sort schemas either asc or desc", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "maximum number of retrieved schemas matching the criteria", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "schema attributes", + "name": "attributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}": { + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Put new schema version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "schema update request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/registry.SchemaUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "summary": "Delete schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schema versions by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/latest": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get the latest schema version by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/{version}": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Delete schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions/{version}/spec": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema specification by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } }, "definitions": { - "registry.SchemaRegistrationRequest": { - "type": "object", - "properties": { - "attributes": { - "type": "string" - }, - "compatibility_mode": { - "type": "string" - }, - "description": { - "type": "string" - }, - "last_created": { - "type": "string" - }, - "name": { - "type": "string" - }, - "publisher_id": { - "type": "string" - }, - "schema_type": { - "type": "string" - }, - "specification": { - "type": "string" - }, - "validity_mode": { - "type": "string" - } - } - }, - "registry.SchemaUpdateRequest": { - "type": "object", - "properties": { - "attributes": { - "type": "string" - }, - "description": { - "type": "string" - }, - "specification": { - "type": "string" - } - } - } + "registry.SchemaRegistrationRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "compatibility_mode": { + "type": "string" + }, + "description": { + "type": "string" + }, + "last_created": { + "type": "string" + }, + "name": { + "type": "string" + }, + "publisher_id": { + "type": "string" + }, + "schema_type": { + "type": "string" + }, + "specification": { + "type": "string" + }, + "validity_mode": { + "type": "string" + } + } + }, + "registry.SchemaUpdateRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "specification": { + "type": "string" + } + } + } } }` From 7e0e395fb09418861506bdd7613165a16c806a37 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:06:12 +0200 Subject: [PATCH 06/31] style: bumped the go version --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 10d8291..4c62e6a 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -6,7 +6,7 @@ on: env: GO111MODULE: on - GO_VERSION: 1.19 + GO_VERSION: 1.21 NODE_VERSION: 22 LINT_ARGS: -v --skip-files .*_test.go --timeout 5m0s --out-${NO_FUTURE}format colored-line-number GOLANGCI_LINT_VERSION: v1.50 From 7b28d81f1702bbedf5a4a282cbad3235f49f3013 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:14:29 +0200 Subject: [PATCH 07/31] style: dockerfile fixes --- registry/docker/initdb/Dockerfile | 2 +- registry/docker/registry-firestore/Dockerfile | 2 +- registry/docker/registry/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/docker/initdb/Dockerfile b/registry/docker/initdb/Dockerfile index 720d422..7f85076 100644 --- a/registry/docker/initdb/Dockerfile +++ b/registry/docker/initdb/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /src COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download -COPY ./schema-registry . +COPY ./registry . COPY LICENSE ./licenses/ RUN go mod tidy diff --git a/registry/docker/registry-firestore/Dockerfile b/registry/docker/registry-firestore/Dockerfile index 3eef5b6..86315f7 100644 --- a/registry/docker/registry-firestore/Dockerfile +++ b/registry/docker/registry-firestore/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /src COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download -COPY ./schema-registry . +COPY ./registry . COPY LICENSE ./licenses/ RUN go mod tidy diff --git a/registry/docker/registry/Dockerfile b/registry/docker/registry/Dockerfile index 064a641..da40817 100644 --- a/registry/docker/registry/Dockerfile +++ b/registry/docker/registry/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /src COPY ./registry/go.mod ./registry/go.sum ./ RUN go mod download -COPY ./schema-registry . +COPY ./registry . COPY LICENSE ./licenses/ RUN go mod tidy From 925e043dc1c7169ade6e86955e606e8dd5294b71 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:19:56 +0200 Subject: [PATCH 08/31] style: removed toolchain from go.mod --- validator/go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/validator/go.mod b/validator/go.mod index 2178f19..3e52662 100644 --- a/validator/go.mod +++ b/validator/go.mod @@ -2,8 +2,6 @@ module github.com/dataphos/aquarium-janitor-standalone-internal go 1.21 -toolchain go1.22.2 - require ( github.com/dataphos/lib-batchproc v1.0.0 github.com/dataphos/lib-brokers v1.0.0 From 9ca8b399192843943a2d80199fe7c2ddf2fd4b14 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Oct 2024 08:21:34 +0000 Subject: [PATCH 09/31] chore: update third party licenses --- registry/licenses/LICENSE-3RD-PARTY.md | 143 ++++++++++----------- validator/licenses/LICENSE-3RD-PARTY.md | 161 +++++++++++++++--------- 2 files changed, 166 insertions(+), 138 deletions(-) diff --git a/registry/licenses/LICENSE-3RD-PARTY.md b/registry/licenses/LICENSE-3RD-PARTY.md index 29a82b9..fb44fa6 100644 --- a/registry/licenses/LICENSE-3RD-PARTY.md +++ b/registry/licenses/LICENSE-3RD-PARTY.md @@ -1,76 +1,67 @@ -# Licenses list - -Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. - -| software | license link | license | -|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|--------------| -| cloud.google.com/go/compute/metadata | https://github.com/googleapis/google-cloud-go/blob/compute/v1.5.0/compute/LICENSE | Apache-2.0 | -| cloud.google.com/go/functions/metadata | https://github.com/googleapis/google-cloud-go/blob/functions/v1.3.0/functions/LICENSE | Apache-2.0 | -| cloud.google.com/go/iam | https://github.com/googleapis/google-cloud-go/blob/iam/v0.3.0/iam/LICENSE | Apache-2.0 | -| cloud.google.com/go/internal | https://github.com/googleapis/google-cloud-go/blob/v0.100.2/LICENSE | Apache-2.0 | -| cloud.google.com/go/pubsub | https://github.com/googleapis/google-cloud-go/blob/pubsub/v1.20.0/pubsub/LICENSE | Apache-2.0 | -| cloud.google.com/go/storage | https://github.com/googleapis/google-cloud-go/blob/storage/v1.22.0/storage/LICENSE | Apache-2.0 | -| github.com/Azure/azure-sdk-for-go/sdk/azcore | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azcore/v0.21.1/sdk/azcore/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/azidentity | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azidentity/v0.13.2/sdk/azidentity/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/internal | https://github.com/Azure/azure-sdk-for-go/blob/sdk/internal/v0.9.1/sdk/internal/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v0.3.6/sdk/messaging/azservicebus/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/messaging/internal | https://github.com/Azure/azure-sdk-for-go/blob/2b10e91d237e/sdk/messaging/internal/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/storage/azblob | https://github.com/Azure/azure-sdk-for-go/blob/sdk/storage/azblob/v0.3.0/sdk/storage/azblob/LICENSE.txt | MIT | -| github.com/Azure/go-amqp | https://github.com/Azure/go-amqp/blob/v0.17.4/LICENSE | MIT | -| github.com/AzureAD/microsoft-authentication-library-for-go/apps | https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/v0.4.0/LICENSE | MIT | -| github.com/devigned/tab | https://github.com/devigned/tab/blob/v0.1.1/LICENSE | MIT | -| github.com/go-stack/stack | https://github.com/go-stack/stack/blob/v1.8.0/LICENSE.md | MIT | -| github.com/gogo/protobuf | https://github.com/gogo/protobuf/blob/v1.3.2/LICENSE | BSD-3-Clause | -| github.com/golang-jwt/jwt | https://github.com/golang-jwt/jwt/blob/v3.2.1/LICENSE | MIT | -| github.com/golang/groupcache/lru | https://github.com/golang/groupcache/blob/8c9f03a8e57e/LICENSE | Apache-2.0 | -| github.com/golang/mock/gomock | https://github.com/golang/mock/blob/v1.6.0/LICENSE | Apache-2.0 | -| github.com/golang/protobuf | https://github.com/golang/protobuf/blob/v1.5.2/LICENSE | BSD-3-Clause | -| github.com/golang/snappy | https://github.com/golang/snappy/blob/v0.0.4/LICENSE | BSD-3-Clause | -| github.com/google/go-cmp/cmp | https://github.com/google/go-cmp/blob/v0.5.7/LICENSE | BSD-3-Clause | -| github.com/google/uuid | https://github.com/google/uuid/blob/v1.1.2/LICENSE | BSD-3-Clause | -| github.com/googleapis/gax-go/v2 | https://github.com/googleapis/gax-go/blob/v2.2.0/v2/LICENSE | BSD-3-Clause | -| github.com/googleapis/go-type-adapters/adapters | https://github.com/googleapis/go-type-adapters/blob/v1.0.0/LICENSE | Apache-2.0 | -| github.com/gorilla/mux | https://github.com/gorilla/mux/blob/v1.8.0/LICENSE | BSD-3-Clause | -| github.com/hamba/avro | https://github.com/hamba/avro/blob/v1.6.6/LICENCE | MIT | -| github.com/json-iterator/go | https://github.com/json-iterator/go/blob/v1.1.12/LICENSE | MIT | -| github.com/klauspost/compress | https://github.com/klauspost/compress/blob/v1.14.4/LICENSE | Apache-2.0 | -| github.com/klauspost/compress/internal/snapref | https://github.com/klauspost/compress/blob/v1.14.4/internal\snapref\LICENSE | BSD-3-Clause | -| github.com/klauspost/compress/s2 | https://github.com/klauspost/compress/blob/v1.14.4/s2\LICENSE | BSD-3-Clause | -| github.com/klauspost/compress/snappy | https://github.com/klauspost/compress/blob/v1.14.4/snappy\LICENSE | BSD-3-Clause | -| github.com/klauspost/compress/zstd/internal/xxhash | https://github.com/klauspost/compress/blob/v1.14.4/zstd\internal\xxhash\LICENSE.txt | MIT | -| github.com/kylelemons/godebug | https://github.com/kylelemons/godebug/blob/v1.1.0/LICENSE | Apache-2.0 | -| github.com/modern-go/concurrent | https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE | Apache-2.0 | -| github.com/modern-go/reflect2 | https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE | Apache-2.0 | -| github.com/nats-io/nats.go | https://github.com/nats-io/nats.go/blob/v1.15.0/LICENSE | Apache-2.0 | -| github.com/nats-io/nkeys | https://github.com/nats-io/nkeys/blob/v0.3.0/LICENSE | Apache-2.0 | -| github.com/nats-io/nuid | https://github.com/nats-io/nuid/blob/v1.0.1/LICENSE | Apache-2.0 | -| github.com/nats-io/stan.go | https://github.com/nats-io/stan.go/blob/v0.10.2/LICENSE | Apache-2.0 | -| github.com/pierrec/lz4/v4 | https://github.com/pierrec/lz4/blob/v4.1.14/LICENSE | BSD-3-Clause | -| github.com/pkg/browser | https://github.com/pkg/browser/blob/ce105d075bb4/LICENSE | BSD-2-Clause | -| github.com/pkg/errors | https://github.com/pkg/errors/blob/v0.9.1/LICENSE | BSD-2-Clause | -| github.com/robfig/cron/v3 | https://github.com/robfig/cron/blob/v3.0.1/LICENSE | MIT | -| github.com/segmentio/kafka-go | https://github.com/segmentio/kafka-go/blob/v0.4.31/LICENSE | MIT | -| github.com/xdg-go/pbkdf2 | https://github.com/xdg-go/pbkdf2/blob/v1.0.0/LICENSE | Apache-2.0 | -| github.com/xdg-go/scram | https://github.com/xdg-go/scram/blob/v1.0.2/LICENSE | Apache-2.0 | -| github.com/xdg-go/stringprep | https://github.com/xdg-go/stringprep/blob/v1.0.2/LICENSE | Apache-2.0 | -| github.com/youmark/pkcs8 | https://github.com/youmark/pkcs8/blob/1be2e3e5546d/LICENSE | MIT | -| github.com/hashicorp/golang-lru | https://github.com/hashicorp/golang-lru/blob/v0.5.1/LICENSE | MPL-2.0 | -| github.com/spf13/cast | https://github.com/spf13/cast/blob/master/LICENSE | MIT | -| github.com/swaggo/swag | https://github.com/swaggo/swag/blob/master/license | MIT | -| go.mongodb.org/mongo-driver | https://github.com/mongodb/mongo-go-driver/blob/v1.9.0/LICENSE | Apache-2.0 | -| go.opencensus.io | https://github.com/census-instrumentation/opencensus-go/blob/v0.23.0/LICENSE | Apache-2.0 | -| go.uber.org/atomic | https://github.com/uber-go/atomic/blob/v1.7.0/LICENSE.txt | MIT | -| go.uber.org/multierr | https://github.com/uber-go/multierr/blob/v1.6.0/LICENSE.txt | MIT | -| go.uber.org/zap | https://github.com/uber-go/zap/blob/v1.16.0/LICENSE.txt | MIT | -| golang.org/x/crypto | https://cs.opensource.google/go/x/crypto/+/3147a52a:LICENSE | BSD-3-Clause | -| golang.org/x/net | https://cs.opensource.google/go/x/net/+/de3da570:LICENSE | BSD-3-Clause | -| golang.org/x/oauth2 | https://cs.opensource.google/go/x/oauth2/+/6242fa91:LICENSE | BSD-3-Clause | -| golang.org/x/sync | https://cs.opensource.google/go/x/sync/+/036812b2:LICENSE | BSD-3-Clause | -| golang.org/x/sys | https://cs.opensource.google/go/x/sys/+/33da011f:LICENSE | BSD-3-Clause | -| golang.org/x/text | https://cs.opensource.google/go/x/text/+/v0.3.7:LICENSE | BSD-3-Clause | -| golang.org/x/xerrors | https://cs.opensource.google/go/x/xerrors/+/5ec99f83:LICENSE | BSD-3-Clause | -| google.golang.org/api | https://github.com/googleapis/google-api-go-client/blob/v0.74.0/LICENSE | BSD-3-Clause | -| google.golang.org/api/internal/third_party/uritemplates | https://github.com/googleapis/google-api-go-client/blob/v0.74.0/internal\third_party\uritemplates\LICENSE | BSD-3-Clause | -| google.golang.org/genproto | https://github.com/googleapis/go-genproto/blob/9d709892a2bf/LICENSE | Apache-2.0 | -| google.golang.org/grpc | https://github.com/grpc/grpc-go/blob/v1.45.0/LICENSE | Apache-2.0 | -| google.golang.org/protobuf | https://github.com/protocolbuffers/protobuf-go/blob/v1.28.0/LICENSE | BSD-3-Clause | +| Module | License | +|:----------------------------------------------------------------------------------------|:-------------| +| cloud.google.com/go/compute/metadata v0.2.3 (indirect) | Apache-2.0 | +| cloud.google.com/go/firestore v1.13.0 | Apache-2.0 | +| cloud.google.com/go/internal | Apache-2.0 | +| cloud.google.com/go/longrunning/autogen/longrunningpb | Apache-2.0 | +| github.com/KyleBanks/depth v1.2.1 (indirect) | MIT | +| github.com/beorn7/perks/quantile | MIT | +| github.com/cespare/xxhash/v2 v2.2.0 (indirect) | MIT | +| github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer | Apache-2.0 | +| github.com/go-chi/chi/v5 v5.0.10 | MIT | +| github.com/go-openapi/jsonpointer v0.20.0 (indirect) | Apache-2.0 | +| github.com/go-openapi/jsonreference v0.20.2 (indirect) | Apache-2.0 | +| github.com/go-openapi/spec v0.20.9 (indirect) | Apache-2.0 | +| github.com/go-openapi/swag v0.22.4 (indirect) | Apache-2.0 | +| github.com/golang/groupcache/lru | Apache-2.0 | +| github.com/golang/protobuf v1.5.3 (indirect) | BSD-3-Clause | +| github.com/google/go-cmp/cmp | BSD-3-Clause | +| github.com/google/s2a-go v0.1.7 (indirect) | Apache-2.0 | +| github.com/googleapis/enterprise-certificate-proxy/client | Apache-2.0 | +| github.com/googleapis/gax-go/v2 v2.12.0 (indirect) | BSD-3-Clause | +| github.com/hamba/avro/v2 v2.16.0 | MIT | +| github.com/hashicorp/golang-lru v1.0.2 | MPL-2.0 | +| github.com/jackc/pgpassfile v1.0.0 (indirect) | MIT | +| github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a (indirect) | MIT | +| github.com/jackc/pgx/v5 v5.4.3 (indirect) | MIT | +| github.com/jinzhu/inflection v1.0.0 (indirect) | MIT | +| github.com/jinzhu/now v1.1.5 (indirect) | MIT | +| github.com/josharian/intern v1.0.0 (indirect) | MIT | +| github.com/json-iterator/go v1.1.12 (indirect) | MIT | +| github.com/mailru/easyjson v0.7.7 (indirect) | MIT | +| github.com/matttproud/golang_protobuf_extensions/pbutil | Apache-2.0 | +| github.com/mitchellh/mapstructure v1.5.0 (indirect) | MIT | +| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd (indirect) | Apache-2.0 | +| github.com/modern-go/reflect2 v1.0.2 (indirect) | Apache-2.0 | +| github.com/pkg/errors v0.9.1 | BSD-2-Clause | +| github.com/prometheus/client_golang/prometheus | Apache-2.0 | +| github.com/prometheus/client_model/go | Apache-2.0 | +| github.com/prometheus/common v0.44.0 (indirect) | Apache-2.0 | +| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | BSD-3-Clause | +| github.com/prometheus/procfs v0.12.0 (indirect) | Apache-2.0 | +| github.com/spf13/cast v1.5.1 | MIT | +| github.com/swaggo/files v1.0.1 (indirect) | MIT | +| github.com/swaggo/http-swagger v1.3.4 | MIT | +| github.com/swaggo/swag v1.16.2 | MIT | +| go.opencensus.io v0.24.0 (indirect) | Apache-2.0 | +| go.uber.org/multierr v1.11.0 (indirect) | MIT | +| go.uber.org/zap v1.26.0 (indirect) | MIT | +| golang.org/x/crypto v0.13.0 (indirect) | BSD-3-Clause | +| golang.org/x/net v0.15.0 (indirect) | BSD-3-Clause | +| golang.org/x/oauth2 v0.12.0 (indirect) | BSD-3-Clause | +| golang.org/x/sync v0.3.0 | BSD-3-Clause | +| golang.org/x/sys v0.12.0 (indirect) | BSD-3-Clause | +| golang.org/x/text v0.13.0 (indirect) | BSD-3-Clause | +| golang.org/x/time/rate | BSD-3-Clause | +| golang.org/x/tools v0.13.0 (indirect) | BSD-3-Clause | +| golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 (indirect) | BSD-3-Clause | +| google.golang.org/api v0.143.0 | BSD-3-Clause | +| google.golang.org/api/internal/third_party/uritemplates | BSD-3-Clause | +| google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 (indirect) | Apache-2.0 | +| google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 (indirect) | Apache-2.0 | +| google.golang.org/genproto/googleapis/type/latlng | Apache-2.0 | +| google.golang.org/grpc v1.58.2 (indirect) | Apache-2.0 | +| google.golang.org/protobuf v1.31.0 (indirect) | BSD-3-Clause | +| gopkg.in/yaml.v3 v3.0.1 (indirect) | MIT | +| gorm.io/driver/postgres v1.5.2 | MIT | +| gorm.io/gorm v1.25.4 | MIT | \ No newline at end of file diff --git a/validator/licenses/LICENSE-3RD-PARTY.md b/validator/licenses/LICENSE-3RD-PARTY.md index 92f761d..788299e 100644 --- a/validator/licenses/LICENSE-3RD-PARTY.md +++ b/validator/licenses/LICENSE-3RD-PARTY.md @@ -1,62 +1,99 @@ -# Licenses list - -Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. - -| software | license link | license | -|---------------------------------|------------------------------------------------------------------|--------------| -| cloud.google.com/go/compute/metadata | https://github.com/googleapis/google-cloud-go/blob/compute/v1.7.0/compute/LICENSE | Apache-2.0 | -| cloud.google.com/go/iam | https://github.com/googleapis/google-cloud-go/blob/iam/v0.3.0/iam/LICENSE | Apache-2.0 | -| cloud.google.com/go/internal | https://github.com/googleapis/google-cloud-go/blob/v0.102.1/LICENSE | Apache-2.0 | -| cloud.google.com/go/pubsub | https://github.com/googleapis/google-cloud-go/blob/pubsub/v1.24.0/pubsub/LICENSE | Apache-2.0 | -| github.com/Azure/azure-sdk-for-go/sdk/azcore | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azcore/v1.0.0/sdk/azcore/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/internal | https://github.com/Azure/azure-sdk-for-go/blob/sdk/internal/v1.0.0/sdk/internal/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v1.1.0/sdk/messaging/azservicebus/LICENSE.txt | MIT | -| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus/internal/go-amqp | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v1.1.0/sdk/messaging/azservicebus/internal\go-amqp\LICENSE | MIT | -| github.com/go-playground/locales | https://github.com/go-playground/locales/blob/v0.14.0/LICENSE | MIT | -| github.com/go-playground/universal-translator | https://github.com/go-playground/universal-translator/blob/v0.18.0/LICENSE | MIT | -| github.com/go-playground/validator/v10 | https://github.com/go-playground/validator/blob/v10.11.0/LICENSE | MIT | -| github.com/golang/groupcache/lru | https://github.com/golang/groupcache/blob/8c9f03a8e57e/LICENSE | Apache-2.0 | -| github.com/golang/protobuf | https://github.com/golang/protobuf/blob/v1.5.2/LICENSE | BSD-3-Clause | -| github.com/google/go-cmp/cmp | https://github.com/google/go-cmp/blob/v0.5.8/LICENSE | BSD-3-Clause | -| github.com/googleapis/enterprise-certificate-proxy/client | https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.1.0/LICENSE | Apache-2.0 | -| github.com/googleapis/gax-go/v2 | https://github.com/googleapis/gax-go/blob/v2.4.0/v2/LICENSE | BSD-3-Clause | -| github.com/hamba/avro | https://github.com/hamba/avro/blob/v1.8.0/LICENCE | MIT | -| github.com/hashicorp/golang-lru | https://github.com/hashicorp/golang-lru/blob/v0.5.4/LICENSE | MPL-2.0 | -| github.com/jhump/protoreflect | https://github.com/jhump/protoreflect/blob/v1.12.0/LICENSE | Apache-2.0 | -| github.com/json-iterator/go | https://github.com/json-iterator/go/blob/v1.1.12/LICENSE | MIT | -| github.com/kkyr/fig | https://github.com/kkyr/fig/blob/v0.3.0/LICENSE | Apache-2.0 | -| github.com/klauspost/compress | https://github.com/klauspost/compress/blob/v1.15.9/LICENSE | Apache-2.0 | -| github.com/klauspost/compress/internal/snapref | https://github.com/klauspost/compress/blob/v1.15.9/internal\snapref\LICENSE | BSD-3-Clause | -| github.com/klauspost/compress/s2 | https://github.com/klauspost/compress/blob/v1.15.9/s2\LICENSE | BSD-3-Clause | -| github.com/klauspost/compress/zstd/internal/xxhash | https://github.com/klauspost/compress/blob/v1.15.9/zstd\internal\xxhash\LICENSE.txt | MIT | -| github.com/leodido/go-urn | https://github.com/leodido/go-urn/blob/v1.2.1/LICENSE | MIT | -| github.com/mitchellh/mapstructure | https://github.com/mitchellh/mapstructure/blob/v1.4.1/LICENSE | MIT | -| github.com/modern-go/concurrent | https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE | Apache-2.0 | -| github.com/modern-go/reflect2 | https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE | Apache-2.0 | -| github.com/nats-io/nats.go | https://github.com/nats-io/nats.go/blob/v1.16.0/LICENSE | Apache-2.0 | -| github.com/nats-io/nkeys | https://github.com/nats-io/nkeys/blob/v0.3.0/LICENSE | Apache-2.0 | -| github.com/nats-io/nuid | https://github.com/nats-io/nuid/blob/v1.0.1/LICENSE | Apache-2.0 | -| github.com/pelletier/go-toml | https://github.com/pelletier/go-toml/blob/v1.9.3/LICENSE | Apache-2.0 | -| github.com/pierrec/lz4/v4 | https://github.com/pierrec/lz4/blob/v4.1.15/LICENSE | BSD-3-Clause | -| github.com/pkg/errors | https://github.com/pkg/errors/blob/v0.9.1/LICENSE | BSD-2-Clause | -| github.com/santhosh-tekuri/jsonschema/v5 | https://github.com/santhosh-tekuri/jsonschema/blob/v5.0.0/LICENSE | Apache-2.0 | -| github.com/twmb/franz-go/pkg | https://github.com/twmb/franz-go/blob/v1.7.0/LICENSE | BSD-3-Clause | -| github.com/twmb/franz-go/pkg/kmsg | https://github.com/twmb/franz-go/blob/pkg/kmsg/v1.2.0/pkg/kmsg/LICENSE | BSD-3-Clause | -| github.com/xeipuuv/gojsonpointer | https://github.com/xeipuuv/gojsonpointer/blob/4e3ac2762d5f/LICENSE-APACHE-2.0.txt | Apache-2.0 | -| github.com/xeipuuv/gojsonreference | https://github.com/xeipuuv/gojsonreference/blob/bd5ef7bd5415/LICENSE-APACHE-2.0.txt | Apache-2.0 | -| github.com/xeipuuv/gojsonschema | https://github.com/xeipuuv/gojsonschema/blob/v1.2.0/LICENSE-APACHE-2.0.txt | Apache-2.0 | -| go.opencensus.io | https://github.com/census-instrumentation/opencensus-go/blob/v0.23.0/LICENSE | Apache-2.0 | -| go.uber.org/atomic | https://github.com/uber-go/atomic/blob/v1.7.0/LICENSE.txt | MIT | -| go.uber.org/multierr | https://github.com/uber-go/multierr/blob/v1.6.0/LICENSE.txt | MIT | -| go.uber.org/zap | https://github.com/uber-go/zap/blob/v1.16.0/LICENSE.txt | MIT | -| golang.org/x/crypto | https://cs.opensource.google/go/x/crypto/+/bc19a97f:LICENSE | BSD-3-Clause | -| golang.org/x/net | https://cs.opensource.google/go/x/net/+/c90051bb:LICENSE | BSD-3-Clause | -| golang.org/x/oauth2 | https://cs.opensource.google/go/x/oauth2/+/fd043fe5:LICENSE | BSD-3-Clause | -| golang.org/x/sync | https://cs.opensource.google/go/x/sync/+/886fb937:LICENSE | BSD-3-Clause | -| golang.org/x/text | https://cs.opensource.google/go/x/text/+/v0.3.7:LICENSE | BSD-3-Clause | -| google.golang.org/api | https://github.com/googleapis/google-api-go-client/blob/v0.91.0/LICENSE | BSD-3-Clause | -| google.golang.org/api/internal/third_party/uritemplates | https://github.com/googleapis/google-api-go-client/blob/v0.91.0/internal hird_party\uritemplates\LICENSE | BSD-3-Clause | -| google.golang.org/genproto | https://github.com/googleapis/go-genproto/blob/8cd45d7dbd1f/LICENSE | Apache-2.0 | -| google.golang.org/grpc | https://github.com/grpc/grpc-go/blob/v1.48.0/LICENSE | Apache-2.0 | -| google.golang.org/protobuf | https://github.com/protocolbuffers/protobuf-go/blob/v1.28.1/LICENSE | BSD-3-Clause | -| gopkg.in/yaml.v2 | https://github.com/go-yaml/yaml/blob/v2.4.0/LICENSE | Apache-2.0 | +| Module | License | +|:----------------------------------------------------------------------------------------|:-------------| +| cloud.google.com/go/compute/metadata v0.2.3 (indirect) | Apache-2.0 | +| cloud.google.com/go/iam v1.1.2 (indirect) | Apache-2.0 | +| cloud.google.com/go/internal | Apache-2.0 | +| cloud.google.com/go/pubsub v1.33.0 (indirect) | Apache-2.0 | +| github.com/99designs/keyring v1.2.2 (indirect) | MIT | +| github.com/AthenZ/athenz v1.11.29 (indirect) | Apache-2.0 | +| github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 (indirect) | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 (indirect) | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.3.0 (indirect) | MIT | +| github.com/Azure/go-amqp v1.0.0 (indirect) | MIT | +| github.com/DataDog/zstd v1.5.5 (indirect) | BSD-3-Clause | +| github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 (indirect) | MIT | +| github.com/apache/pulsar-client-go v0.14.0 (indirect) | Apache-2.0 | +| github.com/ardielle/ardielle-go/rdl | Apache-2.0 | +| github.com/beorn7/perks/quantile | MIT | +| github.com/bits-and-blooms/bitset v1.7.0 (indirect) | BSD-3-Clause | +| github.com/cespare/xxhash/v2 v2.2.0 (indirect) | MIT | +| github.com/dvsekhvalnov/jose2go v1.6.0 (indirect) | MIT | +| github.com/go-playground/locales v0.14.0 (indirect) | MIT | +| github.com/go-playground/universal-translator v0.18.0 (indirect) | MIT | +| github.com/go-playground/validator/v10 v10.11.1 | MIT | +| github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 (indirect) | BSD-2-Clause | +| github.com/golang-jwt/jwt/v5 v5.2.1 (indirect) | MIT | +| github.com/golang/groupcache/lru | Apache-2.0 | +| github.com/golang/protobuf v1.5.4 (indirect) | BSD-3-Clause | +| github.com/google/s2a-go v0.1.4 (indirect) | Apache-2.0 | +| github.com/googleapis/enterprise-certificate-proxy/client | Apache-2.0 | +| github.com/googleapis/gax-go/v2 v2.12.0 (indirect) | BSD-3-Clause | +| github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c (indirect) | MIT | +| github.com/hamba/avro v1.8.0 | MIT | +| github.com/hamba/avro/v2 v2.22.2-0.20240625062549-66aad10411d9 (indirect) | MIT | +| github.com/hashicorp/errwrap v1.1.0 (indirect) | MPL-2.0 | +| github.com/hashicorp/go-multierror v1.1.1 (indirect) | MPL-2.0 | +| github.com/hashicorp/go-uuid v1.0.3 (indirect) | MPL-2.0 | +| github.com/hashicorp/golang-lru v0.5.4 | MPL-2.0 | +| github.com/jcmturner/aescts/v2 v2.0.0 (indirect) | Apache-2.0 | +| github.com/jcmturner/dnsutils/v2 v2.0.0 (indirect) | Apache-2.0 | +| github.com/jcmturner/gofork v1.7.6 (indirect) | BSD-3-Clause | +| github.com/jcmturner/gokrb5/v8 v8.4.4 (indirect) | Apache-2.0 | +| github.com/jcmturner/rpc/v2 v2.0.3 (indirect) | Apache-2.0 | +| github.com/jhump/protoreflect v1.12.0 | Apache-2.0 | +| github.com/json-iterator/go v1.1.12 (indirect) | MIT | +| github.com/kkyr/fig v0.3.0 | Apache-2.0 | +| github.com/klauspost/compress v1.17.9 (indirect) | Apache-2.0 | +| github.com/klauspost/compress/internal/snapref | BSD-3-Clause | +| github.com/klauspost/compress/s2 | BSD-3-Clause | +| github.com/klauspost/compress/zstd/internal/xxhash | MIT | +| github.com/leodido/go-urn v1.2.1 (indirect) | MIT | +| github.com/matttproud/golang_protobuf_extensions/pbutil | Apache-2.0 | +| github.com/mitchellh/mapstructure v1.5.0 (indirect) | MIT | +| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd (indirect) | Apache-2.0 | +| github.com/modern-go/reflect2 v1.0.2 (indirect) | Apache-2.0 | +| github.com/mtibben/percent v0.2.1 (indirect) | MIT | +| github.com/nats-io/nats.go v1.25.0 (indirect) | Apache-2.0 | +| github.com/nats-io/nkeys v0.4.4 (indirect) | Apache-2.0 | +| github.com/nats-io/nuid v1.0.1 (indirect) | Apache-2.0 | +| github.com/pelletier/go-toml v1.9.3 (indirect) | Apache-2.0 | +| github.com/pierrec/lz4 v2.6.1+incompatible (indirect) | BSD-3-Clause | +| github.com/pierrec/lz4/v4 v4.1.17 (indirect) | BSD-3-Clause | +| github.com/pkg/errors v0.9.1 | BSD-2-Clause | +| github.com/prometheus/client_golang/prometheus | Apache-2.0 | +| github.com/prometheus/client_model/go | Apache-2.0 | +| github.com/prometheus/common v0.43.0 (indirect) | Apache-2.0 | +| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | BSD-3-Clause | +| github.com/prometheus/procfs v0.9.0 (indirect) | Apache-2.0 | +| github.com/santhosh-tekuri/jsonschema/v5 v5.0.2 | Apache-2.0 | +| github.com/sirupsen/logrus v1.9.3 (indirect) | MIT | +| github.com/spaolacci/murmur3 v1.1.0 (indirect) | BSD-3-Clause | +| github.com/twmb/franz-go/pkg | BSD-3-Clause | +| github.com/twmb/franz-go/pkg/kmsg v1.5.0 (indirect) | BSD-3-Clause | +| github.com/twmb/franz-go/pkg/sasl/kerberos v1.1.0 (indirect) | BSD-3-Clause | +| github.com/twmb/franz-go/plugin/kprom v1.0.0 (indirect) | BSD-3-Clause | +| github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb (indirect) | Apache-2.0 | +| github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 (indirect) | Apache-2.0 | +| github.com/xeipuuv/gojsonschema v1.2.0 | Apache-2.0 | +| go.opencensus.io v0.24.0 (indirect) | Apache-2.0 | +| go.uber.org/atomic v1.11.0 (indirect) | MIT | +| go.uber.org/multierr v1.9.0 | MIT | +| go.uber.org/ratelimit v0.2.0 | MIT | +| go.uber.org/zap v1.23.0 (indirect) | MIT | +| golang.org/x/crypto v0.22.0 (indirect) | BSD-3-Clause | +| golang.org/x/mod/semver | BSD-3-Clause | +| golang.org/x/net v0.23.0 | BSD-3-Clause | +| golang.org/x/oauth2 v0.11.0 (indirect) | BSD-3-Clause | +| golang.org/x/sync v0.3.0 | BSD-3-Clause | +| golang.org/x/sys v0.19.0 (indirect) | BSD-3-Clause | +| golang.org/x/term v0.19.0 (indirect) | BSD-3-Clause | +| golang.org/x/text v0.14.0 (indirect) | BSD-3-Clause | +| google.golang.org/api v0.128.0 (indirect) | BSD-3-Clause | +| google.golang.org/api/internal/third_party/uritemplates | BSD-3-Clause | +| google.golang.org/appengine v1.6.7 (indirect) | Apache-2.0 | +| google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a (indirect) | Apache-2.0 | +| google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 (indirect) | Apache-2.0 | +| google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b (indirect) | Apache-2.0 | +| google.golang.org/grpc v1.59.0 (indirect) | Apache-2.0 | +| google.golang.org/protobuf v1.33.0 | BSD-3-Clause | +| gopkg.in/yaml.v2 v2.4.0 (indirect) | Apache-2.0 | \ No newline at end of file From 317e2986d864c19f3d21377fcfdbed86a38554df Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:22:07 +0200 Subject: [PATCH 10/31] style: validator Dockerfile fix --- validator/docker/validator/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/docker/validator/Dockerfile b/validator/docker/validator/Dockerfile index f0753a0..4efc857 100644 --- a/validator/docker/validator/Dockerfile +++ b/validator/docker/validator/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine3.16 as build +FROM golang:1.21-alpine3.16 as build LABEL maintainer="Syntio Inc." From 3289edf7366996efe86cedc5095e8a11279c5f0a Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:26:26 +0200 Subject: [PATCH 11/31] style: validator Dockerfile fix & PR.yaml --- .github/workflows/pr.yaml | 2 +- validator/docker/validator/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 4c62e6a..cc0a2a2 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -8,7 +8,7 @@ env: GO111MODULE: on GO_VERSION: 1.21 NODE_VERSION: 22 - LINT_ARGS: -v --skip-files .*_test.go --timeout 5m0s --out-${NO_FUTURE}format colored-line-number + LINT_ARGS: -v --skip-files .*_test.go --timeout 5m0s --out-format colored-line-number GOLANGCI_LINT_VERSION: v1.50 TEST_ARGS: -v -short -coverprofile=coverage.out diff --git a/validator/docker/validator/Dockerfile b/validator/docker/validator/Dockerfile index 4efc857..8245b12 100644 --- a/validator/docker/validator/Dockerfile +++ b/validator/docker/validator/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21-alpine3.16 as build +FROM golang:1.21-alpine3.18 as build LABEL maintainer="Syntio Inc." From cca58eb1de94f8a61d590f0a9f5569321e292e7e Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:36:12 +0200 Subject: [PATCH 12/31] ci: pr lint job not showing results fix --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index cc0a2a2..2c3b8e4 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -105,7 +105,7 @@ jobs: if: steps.check_changed_files.outputs.any_changed == 'true' uses: actions/setup-go@v3 with: - go-version: ${{ env.GO_VERSION }} + go-version: 1.18 # Add all component folders for monorepos cache-dependency-path: | ${{ matrix.component }}/go.sum From 609af4ad74c674bbcc28745018edfc4eb2fff980 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:49:35 +0200 Subject: [PATCH 13/31] ci: pr lint job not showing results fix --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 2c3b8e4..cc0a2a2 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -105,7 +105,7 @@ jobs: if: steps.check_changed_files.outputs.any_changed == 'true' uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: ${{ env.GO_VERSION }} # Add all component folders for monorepos cache-dependency-path: | ${{ matrix.component }}/go.sum From df0c02953839a97d6a527af426ec227f6c321286 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:50:47 +0200 Subject: [PATCH 14/31] ci: pr lint job not showing results fix --- .github/workflows/pr.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index cc0a2a2..4359a21 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -122,8 +122,8 @@ jobs: with: version: v1.50.0 args: ${{env.LINT_ARGS}} - skip-pkg-cache: true - skip-build-cache: true + skip-cache: true + skip-save-cache: true working-directory: ${{ matrix.component }} licenses_check: From 087be98b1ef2f9476d81b663b56139bf0299859c Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 10:56:05 +0200 Subject: [PATCH 15/31] ci: pr lint job not showing results fix --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 4359a21..c643379 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -120,7 +120,7 @@ jobs: if: steps.check_changed_files.outputs.any_changed == 'true' uses: golangci/golangci-lint-action@v6 with: - version: v1.50.0 + version: v1.61.0 args: ${{env.LINT_ARGS}} skip-cache: true skip-save-cache: true From f692010f3ac18a9a51ae8a959633e60a75b3e3b5 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 13:10:37 +0200 Subject: [PATCH 16/31] ci: pr lint job not showing results fix --- validator/internal/publisher/mock.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validator/internal/publisher/mock.go b/validator/internal/publisher/mock.go index e97519b..eb98e1a 100644 --- a/validator/internal/publisher/mock.go +++ b/validator/internal/publisher/mock.go @@ -12,6 +12,10 @@ type MockPublisher struct { type MockTopic struct { } +func (t *MockTopic) BatchPublish(context.Context, ...broker.OutboundMessage) error { + return nil +} + func (*MockTopic) Publish(context.Context, broker.OutboundMessage) error { return nil } From e58bd87b47649f74bb211b7952fbd0c9ed153f45 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 13:17:22 +0200 Subject: [PATCH 17/31] ci: reverted the .golanci.yaml to the private repo version --- .golangci.yaml | 1048 ++++++------------------------------------------ 1 file changed, 118 insertions(+), 930 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 3893cb6..f2c2c73 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -2,59 +2,12 @@ # with their default values. # options for analysis running run: - # The default concurrency value is the number of available CPU. - concurrency: 4 - # Timeout for analysis, e.g. 30s, 5m. - # Default: 1m - timeout: 5m - # Exit code when at least one issue was found. - # Default: 1 + # default concurrency is a available CPU number issues-exit-code: 1 - # Include test files or not. - # Default: true + # include test files or not, default is true tests: true - # List of build tags, all linters use it. - # Default: []. - build-tags: - - mytag - # Which dirs to skip: issues from them won't be reported. - # Can use regexp here: `generated.*`, regexp is applied on full path. - # Default value is empty list, - # but default dirs are skipped independently of this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work on Windows. - skip-dirs: [ ] - # Enables skipping of directories: - # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - # Default: true - skip-dirs-use-default: true - # Which files to skip: they will be analyzed, but issues from them won't be reported. - # Default value is empty list, - # but there is no need to include all autogenerated files, - # we confidently recognize autogenerated files. - # If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work on Windows. - skip-files: [ ] - # If set we pass it to "go list -mod={option}". From "go help modules": - # If invoked with -mod=readonly, the go command is disallowed from the implicit - # automatic updating of go.mod described above. Instead, it fails when any changes - # to go.mod are needed. This setting is most useful to check that go.mod does - # not need updates, such as in a continuous integration and testing system. - # If invoked with -mod=vendor, the go command assumes that the vendor - # directory holds the correct copies of dependencies and ignores - # the dependency descriptions in go.mod. - # - # Allowed values: readonly|vendor|mod - # By default, it isn't set. - # modules-download-mode: - # Allow multiple parallel golangci-lint instances running. - # If false (default) - golangci-lint acquires file lock on start. - allow-parallel-runners: false - # Define the Go version limit. - # Mainly related to generics support since go1.18. - # Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.18 - # go: 'GOVERSION' -# output configuration options +# output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" format: colored-line-number @@ -66,361 +19,62 @@ output: uniq-by-line: true # add a prefix to the output file references; default is no prefix path-prefix: "" - # Sort results by: filepath, line and column. - sort-results: false # all available settings of specific linters - -linters: - disable-all: true - enable: - - asasalint - - asciicheck - - bidichk - - bodyclose - # - containedctx - - contextcheck - # - cyclop - - decorder - - depguard - - dogsled - # - dupl - - durationcheck - - errchkjson - - errcheck - - errname - - errorlint - - execinquery - - exhaustive - # - exhaustruct - - exportloopref - - forcetypeassert - # - funlen - - gosimple - - govet - - gci - # - gochecknoglobals - # - gochecknoinits - # - gocognit - - goconst - # - gocritic - # - gocyclo - - godot - - godox - # - goerr113 - - gofumpt - - goheader - # - gomnd - - gomoddirectives - - gomodguard - - goprintffuncname - - gosec - - grouper - - ineffassign - - importas - # - ireturn - # - lll - # - maintidx - - makezero - - misspell - - nakedret - # - nestif - - nilerr - - nilnil - - nlreturn - - noctx - # - nolintlint - # - nonamedreturns - - nosprintfhostport - # - paralleltest - - prealloc - - predeclared - - promlinter - # - revive - - rowserrcheck - - sqlclosecheck - - stylecheck - - staticcheck - # - tagliatelle - - tenv - - testpackage - - thelper - - tparallel - - typecheck - - unconvert - - unparam - - unused - - varnamelen - - wastedassign - - whitespace - # - wrapcheck - - wsl - presets: - - bugs - - unused - # Run only fast linters from enabled linters set (first run won't be fast) - # Default: false - fast: false - linters-settings: - asasalint: - # to specify a set of function names to exclude - # the values are merged with the builtin exclusions - # the builtin exclusions can be disabled by setting `use-builtin-exclusions` to `false` - # default: ["^(fmt|log|logger|t|)\.(Print|Fprint|Sprint|Fatal|Panic|Error|Warn|Warning|Info|Debug|Log)(|f|ln)$"] - exclude: - - Append - - \.Wrapf - # to enable/disable the asasalint builtin exclusions of function names - # see the default value of `exclude` to get the builtin exclusions, true by default - use-builtin-exclusions: true - # ignore *_test.go files, false by default - ignore-test: true - bidichk: - # the following configurations check for all mentioned invisible unicode runes. - # all runes are enabled by default. - left-to-right-embedding: true - right-to-left-embedding: true - pop-directional-formatting: true - left-to-right-override: true - right-to-left-override: true - left-to-right-isolate: true - right-to-left-isolate: true - first-strong-isolate: true - pop-directional-isolate: true - cyclop: - # the maximal code complexity to report, 10 by default - max-complexity: 10 - # the maximal average package complexity, 0.0 by default - # if it's higher than 0.0 (float) the check is enabled - package-average: 0.0 - # should ignore tests, false by default - skip-tests: true - decorder: - # required order of `type`, `const`, `var` and `func` declarations inside a file - # default: types before constants before variables before functions - dec-order: - - type - - const - - var - - func - # if true, order of declarations is not checked at all, true (disabled) by default - disable-dec-order-check: true - # if true, `init` func can be anywhere in file (does not have to be declared before all other functions), true (disabled) by default - disable-init-func-first-check: false - # if true, multiple global `type`, `const` and `var` declarations are allowed, true (disabled) by default - disable-dec-num-check: true depguard: - # kind of list is passed in - # allowed values: allowlist|denylist, default: denylist list-type: blacklist - # check the list against standard lib, false by default include-go-root: false - # a list of packages for the list type specified - # can accept both string prefixes and string glob patterns - # default: [] - packages: [ ] - # a list of packages for the list type specifyed - # specify an error message to output when a denied package is used - # default: [] - packages-with-error-message: [ ] - # specify rules by which the linter ignores certain files for consideration - # can accept both string prefixes and string glob patterns - # the ! character in front of the rule is a special character - # which signals that the linter should negate the rule - # this allows for more precise control, but it is only available for glob patterns - # default: [] - ignore-file-rules: [ ] - # create additional guards that follow the same configuration pattern - # results from all guards are aggregated together - additional-guards: [ ] - # for example - # - list-type: denylist - # include-go-root: false - # packages: - # - github.com/stretchr/testify - # specify rules by which the linter ignores certain files for consideration - # ignore-file-rules: - # - "**/*_test.go" - # - "**/mock/**/*.go" + packages: + - github.com/sirupsen/logrus + packages-with-error-message: + # specify an error message to output when a blacklisted package is used + - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" dogsled: - # checks assignments with too many blank identifiers; 2 by default + # checks assignments with too many blank identifiers; default is 2 max-blank-identifiers: 2 dupl: # tokens count to trigger issue, 150 by default threshold: 100 errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)` - # false by default: such cases aren't reported by default - check-type-assertions: true - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)` - # false by default: such cases aren't reported by default + # report about not checking of errors in type assertions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. check-blank: false - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details - disable-default-exclusions: true - # list of functions to exclude from checking, where each entry is a single function to exclude + + # list of functions to exclude from checking, where each entry is a single function to exclude. # see https://github.com/kisielk/errcheck#excluding-functions for details - exclude-functions: [ ] - errchkjson: - # with check-error-free-encoding set to true, errchkjson does warn about errors - # from json encoding functions that are safe to be ignored, - # because they are not possible to happen - # - # if check-error-free-encoding is set to true and errcheck linter is enabled, - # it is recommended to add the following exceptions to prevent from false positives: - # - # linters-settings: - # errcheck: - # exclude-functions: - # - encoding/json.Marshal - # - encoding/json.MarshalIndent - # - # false by default - check-error-free-encoding: false - # issue on struct encoding that doesn't have exported fields, false by default - report-no-exported: false - errorlint: - # check whether fmt.Errorf uses the %w verb for formatting errors - # see the https://github.com/polyfloyd/go-errorlint for caveats, true by default - errorf: true - # check for plain type assertions and type switches, true by default - asserts: true - # check for plain error comparisons, true by default - comparison: true + exclude-functions: + - io/os.ReadFile + - io.Copy(*bytes.Buffer) + - io.Copy(os.Stdout) + - (io.ReadCloser).Close exhaustive: - # check switch statements in generated files also, false by default + # check switch statements in generated files also check-generated: false # indicates that switch statements are to be considered exhaustive if a # 'default' case is present, even if all enum members aren't listed in the # switch default-signifies-exhaustive: false - # enum members matching the supplied regex do not have to be listed in - # switch statements to satisfy exhaustiveness - # default: "" - ignore-enum-members: "" - # consider enums only in package scopes, not in inner scopes, false by default - package-scope-only: false funlen: - # checks the number of lines in a function. - # if lower than 0, disable the check, 60 by default - lines: 100 - # checks the number of statements in a function. - # if lower than 0, disable the check, 40 by default - statements: 50 - gci: - # section configuration to compare against - # section names are case-insensitive and may contain parameters in () - # the default order of sections is `standard > default > custom > blank > dot`, - # if `custom-order` is `true`, it follows the order of `sections` option - # custom section: groups all imports with the specified Prefix - # blank section: contains all blank imports. This section is not present unless explicitly enabled - # dot section: contains all dot imports. This section is not present unless explicitly enabled - # default: ["standard", "default"] - sections: - - standard # Standard section: captures all standard packages - - default # Default section: contains all imports that could not be matched to another section type - - prefix(github.com/dataphos) - # skip generated files, true by default - skip-generated: true - # enable custom order of sections - # if `true`, make the section order the same as the order of `sections`, false by default - custom-order: false + lines: 60 + statements: 40 gocognit: # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 15 + min-complexity: 10 goconst: # minimal length of string constant, 3 by default min-len: 3 # minimal occurrences count to trigger, 3 by default min-occurrences: 3 - # ignore test files, false by default - ignore-tests: true - # look for existing constants matching the values, true by default - match-constant: true - # search also for duplicated numbers, false by default - numbers: false - # minimum value, only works with goconst.numbers, 3 by default - min: 3 - # maximum value, only works with goconst.numbers, 3 by default - max: 3 - # ignore when constant is not used as function argument, true by default - ignore-calls: true - gocritic: - # which checks should be enabled; can't be combined with 'disabled-checks' - # see https://go-critic.github.io/overview#checks-overview - # to check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # by default, list of stable checks is used - enabled-checks: - - nestingReduce - - unnamedResult - - ruleguard - - truncateCmp - # which checks should be disabled; can't be combined with 'enabled-checks' - # default: [] - disabled-checks: [ ] - # enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks - # see https://github.com/go-critic/go-critic#usage -> section "Tags" - # default: [] - enabled-tags: [ ] - disabled-tags: [ ] - # settings passed to gocritic. - # the settings key is the name of a supported gocritic checker. - # the list of supported checkers can be find in https://go-critic.github.io/overview. - settings: - # must be valid enabled check name. - nestingReduce: - # min number of statements inside a branch to trigger a warning, 5 by default - bodyWidth: 5 - # whether to check test functions, true by default - # skipTestFuncs: true - ruleguard: - # enable debug to identify which 'Where' condition was rejected - # the value of the parameter is the name of a function in a ruleguard file - # - # when a rule is evaluated: - # If: - # the Match() clause is accepted; and - # one of the conditions in the Where() clause is rejected, - # Then: - # ruleguard prints the specific Where() condition that was rejected - # - # The flag is passed to the ruleguard 'debug-group' argument - # Default: "" - debug: "" - # determines the behavior when an error occurs while parsing ruleguard files - # if flag is not set, log error and skip rule files that contain an error - # if flag is set, the value must be a comma-separated list of error conditions - # - 'all': fail on all errors - # - 'import': ruleguard rule imports a package that cannot be found - # - 'dsl': gorule file does not comply with the ruleguard DSL - # default: "" - failOn: "" - # comma-separated list of file paths containing ruleguard rules - # if a path is relative, it is relative to the directory where the golangci-lint command is executed - # the special '${configDir}' variable is substituted with the absolute directory containing the golangci config file - # glob patterns such as 'rules-*.go' may be specified - # default: "" - rules: "" - # comma-separated list of enabled groups or skip empty to enable everything - # tags can be defined with # character prefix - # default: "" - enable: "" - # comma-separated list of disabled groups or skip empty to enable everything - # tags can be defined with # character prefix - # default: "" - disable: "" - truncateCmp: - # whether to skip int/uint/uintptr types, true by deafult - skipArchDependent: true - unnamedResult: - # whether to check exported functions, false by default - checkExported: false gocyclo: # minimal code complexity to report, 30 by default (but we recommend 10-20) min-complexity: 10 godot: # check all top-level comments, not only declarations - check-all: true + check-all: false godox: # report any comments starting with keywords, this is useful for TODO or FIXME comments that # might be left in the code accidentally and should be resolved before merging @@ -429,599 +83,133 @@ linters-settings: - OPTIMIZE # marks code that should be optimized before merging - HACK # marks hack-arounds that should be removed before merging gofmt: - # Simplify code: gofmt with `-s` option. - # Default: true + # simplify code: gofmt with `-s` option, true by default simplify: true - # Apply the rewrite rules to the source before reformatting. - # https://pkg.go.dev/cmd/gofmt - # Default: [] - rewrite-rules: [ ] - gofumpt: - # module path which contains the source code being formatted - # default: "" - module-path: "" - # choose whether to use the extra rules - # false by default - extra-rules: false - goheader: - # supports two types 'const` and `regexp` - # values can be used recursively - # default: {} - values: { } - # the template use for checking - # default: "" - template: "" - # ss alternative of directive 'template', you may put the path to file with the template source - # useful if you need to load the template from a specific file - # default: "" - template-path: "" - goimports: - # put imports beginning with prefix after 3rd-party packages - # it's a comma-separated list of prefixes - # default: "" - local-prefixes: "" + golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.8 gomnd: - # list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description - # default: ["argument", "case", "condition", "operation", "return", "assign"] - checks: [ argument,case,condition,operation,return,assign ] - # list of numbers to exclude from analysis - # the numbers should be written as string - # values always ignored: "1", "1.0", "0" and "0.0" - # default: [] - ignored-numbers: [ ] - # list of file patterns to exclude from analysis - # values always ignored: `.+_test.go` - # default: [] - ignored-files: [ ] - # list of function patterns to exclude from analysis - # values always ignored: `time.Date` - # default: [] - ignored-functions: [ ] - gomoddirectives: - # allow local `replace` directives. - # false by default - replace-local: false - # list of allowed `replace` directives. - # default: [] - replace-allow-list: [ ] - # allow to not explain why the version has been retracted in the `retract` directives. - # false by default - retract-allow-no-explanation: false - # forbid the use of the `exclude` directives. - # false by default - exclude-forbidden: false - gomodguard: - allowed: - # list of allowed modules - # default: [] - modules: [ ] - # list of allowed module domains - # default: [] - domains: [ ] - blocked: - # list of blocked modules - # default: [] - modules: - # blocked module - - github.com/uudashr/go-module: - # recommended modules that should be used instead. (Optional) - recommendations: - - golang.org/x/mod - # reason why the recommended module should be used. (Optional) - reason: "`mod` is the official go.mod parser library." - # list of blocked module version constraints - # default: [] - versions: [ ] - # set to true to raise lint issues for packages that are loaded from a local path via replace directive - # false by default - local_replace_directives: false - gosimple: - # https://staticcheck.io/docs/configuration/options/#checks - # default: ["*"] - checks: [ "*" ] - gosec: - # to select a subset of rules to run. - # available rules: https://github.com/securego/gosec#available-rules - # default: [] - means include all rules - includes: [ ] - # to specify a set of rules to explicitly exclude. - # available rules: https://github.com/securego/gosec#available-rules - # default: [] - excludes: [ ] - # exclude generated files - # false by default - exclude-generated: false - # filter out the issues with a lower severity than the given value - # valid options are: low, medium, high. - # low by default - severity: low - # filter out the issues with a lower confidence than the given value - # valid options are: low, medium, high. - # low by default - confidence: low - # concurrency value. - # default: the number of logical CPUs usable by the current process - concurrency: 12 - # to specify the configuration of rules - config: - # globals are applicable to all rules - global: - # if true, ignore #nosec in comments (and an alternative as well) - # false by default - nosec: false - # add an alternative comment prefix to #nosec (both will work at the same time) - # default: "" - "#nosec": "" - # define whether nosec issues are counted as finding or not - # default: false - show-ignored: false - # audit mode enables addition checks that for normal code analysis might be too nosy - # default: false - audit: false - G101: - # regexp pattern for variables and constants to find - # default: "(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred" - pattern: "(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred" - # if true, complain about all cases (even with low entropy) - # false by default - ignore_entropy: false - # maximum allowed entropy of the string - # "80.0" by default - entropy_threshold: "80.0" - # maximum allowed value of entropy/string length - # is taken into account if entropy >= entropy_threshold/2 - # "3.0" by default - per_char_threshold: "3.0" - # calculate entropy for first N chars of the string - # "16" by default - truncate: "16" - # additional functions to ignore while checking unhandled errors - # following functions always ignored: - # bytes.Buffer: - # - Write - # - WriteByte - # - WriteRune - # - WriteString - # fmt: - # - Print - # - Printf - # - Println - # - Fprint - # - Fprintf - # - Fprintln - # strings.Builder: - # - Write - # - WriteByte - # - WriteRune - # - WriteString - # io.PipeWriter: - # - CloseWithError - # hash.Hash: - # - Write - # os: - # - Unsetenv - # default: {} - G104: { } - G111: - # Regexp pattern to find potential directory traversal. - # Default: "http\\.Dir\\(\"\\/\"\\)|http\\.Dir\\('\\/'\\)" - pattern: "http\\.Dir\\(\"\\/\"\\)|http\\.Dir\\('\\/'\\)" - # maximum allowed permissions mode for os.Mkdir and os.MkdirAll - # "0750" by default - G301: "0750" - # maximum allowed permissions mode for os.OpenFile and os.Chmod - # "0600" by default - G302: "0600" - # maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile - # "0600" by default - G306: "0600" - govet: - # report about shadowed variables. - # false by default - check-shadowing: false - # settings per analyzer. - # settings: - # analyzer name, run `go tool vet help` to see all analyzers - # printf: - # comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`) - # default: [] - # funcs: [] - # shadow: - # Whether to be strict about shadowing; can be noisy - # false by default - # strict: false - # unusedresult: - # comma-separated list of functions whose results must be used - # (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue, - # errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse) - # default: [] - # funcs: [] - # comma-separated list of names of methods of type func() string whose results must be used - # (in addition to default Error,String) - # default: [] - # stringmethods: [] - # disable all analyzers - # false by default - disable-all: true - # enable analyzers by name (in addition to default) - # run `go tool vet help` to see all analyzers - # default: [] - enable: [ ] - # enable all analyzers - # false by default - enable-all: false - # disable analyzers by name - # run `go tool vet help` to see all analyzers - # default: [] - disable: [ ] - importas: - # so not allow unaliased imports of aliased packages, false by default - no-unaliased: false - # so not allow non-required aliases, false by default - no-extra-aliases: false - # list of aliases, default: [] - alias: [ ] - interfacebloat: - # the maximum number of methods allowed for an interface - # 10 by default - max: 10 + settings: + mnd: + # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + checks: + - argument + - case + - condition + - operation + - return + - assign lll: - # max line length, lines longer will be reported, 120 by default + # max line length, lines longer will be reported. Default is 120. # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 130 - # tab width in spaces, 1 by default + line-length: 120 + # tab width in spaces. Default to 1. tab-width: 2 - maintidx: - # show functions with maintainability index lower than N - # a high index indicates better maintainability (it's kind of the opposite of complexity) - # 20 by default - under: 20 - makezero: - # allow only slices initialized with a length of zero - # false by default - always: false - misspell: - # correct spellings using locale preferences for US or UK - # setting locale to US will correct the British spelling of 'colour' to 'color' - # default is to use a neutral variety of English. - locale: US - # default: [] - ignore-words: [ ] - nakedret: - # make an issue if func has more lines of code than this setting, and it has naked returns - # 30 by default - max-func-lines: 30 + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true nestif: # minimal complexity of if statements to report, 5 by default min-complexity: 4 - nilnil: - # checks that there is no simultaneous return of `nil` error and an invalid value - # default: ["ptr", "func", "iface", "map", "chan"] - checked-types: - - ptr - - func - - iface - - map - - chan nolintlint: - # enable to ensure that nolint directives are all used. Default is true. + # Enable to ensure that nolint directives are all used. Default is true. allow-unused: false - # disable to ensure that nolint directives don't have a leading space, true by default + # Disable to ensure that nolint directives don't have a leading space. Default is true. allow-leading-space: true - # exclude following linters from requiring an explanation. Default is []. + # Exclude following linters from requiring an explanation. Default is []. allow-no-explanation: [ ] - # enable to require an explanation of nonzero length after each nolint directive, false by default + # Enable to require an explanation of nonzero length after each nolint directive. Default is false. require-explanation: true - # enable to require nolint directives to mention the specific linter being suppressed, false by default + # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. require-specific: true - nonamedreturns: - # report named error if it is assigned inside defer - # false by default - report-error-in-defer: false - prealloc: - # IMPORTANT: we don't recommend using this linter before doing performance profiling - # for most programs usage of prealloc will be a premature optimization - # report pre-allocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them, true by default - simple: true - # report pre-allocation suggestions on range loops, true by default - range-loops: true - # Report pre-allocation suggestions on for loops, false by default - for-loops: false - promlinter: - # promlinter cannot infer all metrics name in static analysis - # enable strict mode will also include the errors caused by failing to parse the args - # false by default - strict: false - # please refer to https://github.com/yeya24/promlinter#usage for detailed usage - # default: [] - disabled-linters: [ ] - reassign: - # patterns for global variable names that are checked for reassignment - # see https://github.com/curioswitch/go-reassign#usage - # default: ["EOF", "Err.*"] - patterns: [ "EOF", "Err.*" ] - revive: - # maximum number of open files at the same time - # see https://github.com/mgechev/revive#command-line-flags - # defaults to unlimited. - max-open-files: 2048 - # when set to false, ignores files with "GENERATED" header, similar to golint - # see https://github.com/mgechev/revive#available-rules for details - # false by default - ignore-generated-header: false - # sets the default severity. - # see https://github.com/mgechev/revive#configuration - # warning by default - severity: warning - # enable all available rules - # default: false - enable-all-rules: false - # sets the default failure confidence - # this means that linting errors with less than 0.8 confidence will be ignored - # 0.8 by default - confidence: 0.8 - rules: - - name: atomic - - name: blank-imports - - name: bool-literal-in-expr - - name: call-to-gc - - name: constant-logical-expr - - name: context-as-argument - - name: context-keys-type - - name: defer - - name: dot-imports - - name: duplicated-imports - - name: early-return - - name: empty-block - - name: empty-lines - - name: error-naming - - name: error-return - - name: error-strings - - name: errorf - - name: get-return - - name: identical-branches - - name: if-return - - name: increment-decrement - - name: indent-error-flow - - name: optimize-operands-order - - name: package-comments - - name: range - - name: range-val-in-closure - - name: receiver-naming - - name: string-of-int - - name: struct-tag - - name: superfluous-else - - name: time-equal - - name: time-naming - - name: var-declaration - - name: unconditional-recursion - - name: unexported-naming - - name: unexported-return - - name: unnecessary-stmt - - name: unreachable-code - - name: unused-parameter - - name: unused-receiver - - name: useless-break - - name: waitgroup-by-value - rowserrcheck: - # database/sql is always checked - # default: [] - packages: [ ] staticcheck: - # https://staticcheck.io/docs/configuration/options/#checks - # default: ["*"] - checks: [ "*" ] - stylecheck: - # https://staticcheck.io/docs/configuration/options/#checks - # default: ["*"] - checks: [ "*" ] - # https://staticcheck.io/docs/configuration/options/#dot_import_whitelist - # default: ["github.com/mmcloughlin/avo/build", "github.com/mmcloughlin/avo/operand", "github.com/mmcloughlin/avo/reg"] - dot-import-whitelist: [ ] - # https://staticcheck.io/docs/configuration/options/#initialisms - # default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] - initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS" ] - # https://staticcheck.io/docs/configuration/options/#http_status_code_whitelist - # default: ["200", "400", "404", "500"] - http-status-code-whitelist: [ "200", "400", "404", "500" ] - tagliatelle: - # check the struck tag name case. - case: - # use the struct field name to check the name of the struct tag - # false by default - use-field-name: false - # `camel` is used for `json` and `yaml` (can be overridden) - # default: {} - rules: { } - tenv: - # the option `all` will run against whole test files (`_test.go`) regardless of method/function signatures - # otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked - # false by default - all: false - thelper: - test: - # check *testing.T is first param (or after context.Context) of helper function - # true by default - first: true - # check *testing.T param has name t - # true by default - name: true - # check t.Helper() begins helper function - # true by default - begin: true - benchmark: - # check *testing.B is first param (or after context.Context) of helper function - # true by default - first: true - # check *testing.B param has name b - # true by default - name: true - # check b.Helper() begins helper function - # true by default - begin: true - tb: - # check *testing.TB is first param (or after context.Context) of helper function - # true by default - first: true - # check *testing.TB param has name tb - # true by default - name: true - # check tb.Helper() begins helper function - # true by default - begin: true - fuzz: - # check *testing.F is first param (or after context.Context) of helper function - # true by default - first: true - # check *testing.F param has name f - # true by default - name: true - # check f.Helper() begins helper function - # true by default - begin: true - usestdlibvars: - # suggest the use of http.MethodXX - # true by default - http-method: true - # suggest the use of http.StatusXX - # true by default - http-status-code: true - # suggest the use of time.Weekday - # true by default - time-weekday: true - # suggest the use of time.Month - # false by default - time-month: false - # suggest the use of time.Layout - # false by default - time-layout: false - # suggest the use of crypto.Hash - # false by default - crypto-hash: false - # suggest the use of rpc.DefaultXXPath - # false by default - default-rpc-path: false - unparam: - # inspect exported functions. - # - # set to true if no external program/library imports your code. - # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find external interfaces. All text editor integrations - # with golangci-lint call it on a directory with the changed file - # - # false by default - check-exported: false - varnamelen: - # the longest distance, in source lines, that is being considered a "small scope". - # variables used in at most this many lines will be ignored - # 5 by default - max-distance: 5 - # the minimum length of a variable's name that is considered "long" - # variable names that are at least this long will be ignored - # 3 by default - min-name-length: 3 - # check method receivers - # false by default - check-receiver: false - # check named return values - # false by default - check-return: false - # check type parameters - # false by default - check-type-param: false - # ignore "ok" variables that hold the bool return value of a type assertion - # false by default - ignore-type-assert-ok: false - # Ignore "ok" variables that hold the bool return value of a map index - # false by default - ignore-map-index-ok: false - # ignore "ok" variables that hold the bool return value of a channel receive - # false by default - ignore-chan-recv-ok: false - # optional list of variable names that should be ignored completely - # default: [] - ignore-names: [ ] - # optional list of variable declarations that should be ignored completely - # entries must be in one of the following forms (see below for examples): - # - for variables, parameters, named return values, method receivers, or type parameters: - # ( can also be a pointer/slice/map/chan/...) - # - for constants: const - # - # default: [] - ignore-decls: [ ] + # ignore some false positives for this project + checks: + - all + - '-SA9003' # disable the rule SA9003 + - '-SA4009' # disable the rule SA4009 + whitespace: + multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-func: false # Enforces newlines (or comments) after every multi-line function signature wsl: - # if true append is only allowed to be cuddled if appending value is - # matching variables, fields or types online above, true by default + # If true append is only allowed to be cuddled if appending value is + # matching variables, fields or types on line above. Default is true. strict-append: true - # allow calls and assignments to be cuddled as long as the lines have any - # matching variables, fields or types, true by default + # Allow calls and assignments to be cuddled as long as the lines have any + # matching variables, fields or types. Default is true. allow-assign-and-call: true - # allow multiline assignments to be cuddled, true by default + # Allow multiline assignments to be cuddled. Default is true. allow-multiline-assign: true - # allow declarations (var) to be cuddled + # Allow declarations (var) to be cuddled. allow-cuddle-declarations: false - # allow trailing comments in ending of blocks + # Allow trailing comments in ending of blocks allow-trailing-comment: false - # force newlines in end of case at this limit (0 = never) + # Force newlines in end of case at this limit (0 = never). force-case-trailing-whitespace: 0 - # force cuddling of err checks with err var assignment + # Force cuddling of err checks with err var assignment force-err-cuddling: false - # allow leading comments to be separated with empty liens + # Allow leading comments to be separated with empty liens allow-separated-leading-comment: false - wrapcheck: - # an array of strings that specify substrings of signatures to ignore - # if this set, it will override the default set of ignored signatures - # see https://github.com/tomarrell/wrapcheck#configuration for more information - # default: [".Errorf(", "errors.New(", "errors.Unwrap(", ".Wrap(", ".Wrapf(", ".WithMessage(", ".WithMessagef(", ".WithStack("] - ignoreSigs: - - .Errorf( - - errors.New( - - errors.Unwrap( - - .Wrap( - - .Wrapf( - - .WithMessage( - - .WithMessagef( - - .WithStack( - # an array of strings that specify regular expressions of signatures to ignore - # default: [] - ignoreSigRegexps: [ ] - # an array of strings that specify globs of packages to ignore - # default: [] - ignorePackageGlobs: [ ] - # an array of strings that specify regular expressions of interfaces to ignore - # default: [] - ignoreInterfaceRegexps: [ ] - - # the custom section can be used to define linter plugins to be loaded at runtime - # see README documentation for more info + errorlint: + # Report non-wrapping error creation using fmt.Errorf + errorf: true + # The custom section can be used to define linter plugins to be loaded at runtime. See README doc + # for more info. +(io: + ReadCloser): + Close:linters: + enable: + - megacheck + - govet + - gosec + - gocritic + - goconst + disable: + - asciicheck + - maligned + - prealloc + disable-all: false + presets: + - bugs + - unused + fast: false issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: + # Exclude some linters from running on tests files. - path: _test\.go linters: - # - gocyclo + - gocyclo - errcheck - - gosec - dupl - # - gocognit - - funlen - # independently of option `exclude` we use default exclude patterns, + - gosec + # Exclude known linters from partially hard-vendored code, + # which is impossible to exclude via "nolint" comments. + - path: internal/hmac/ + text: "weak cryptographic primitive" + linters: + - gosec + # Exclude lll issues for long lines with go:generate + - linters: + - lll + source: "^//go:generate " + # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all - # excluded by default patterns execute `golangci-lint run --help` - # default value for this option is true + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. exclude-use-default: false - # the default value is false. If set to true exclude and exclude-rules - # regular expressions become case sensitive + # The default value is false. If set to true exclude and exclude-rules + # regular expressions become case sensitive. exclude-case-sensitive: false - # the list of ids of default excludes to include or disable. Default is empty. + # The list of ids of default excludes to include or disable. By default it's empty. include: - EXC0002 # disable excluding of issues about comments from golint - # maximum issues count per one linter. Set to 0 to disable. Default is 50 - max-issues-per-linter: 0 - # maximum count of issues with the same text. Set to 0 to disable. Default is 3 - max-same-issues: 0 + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-issues-per-linter: 50 + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 3 # Show only new issues: if there are unstaged changes or untracked files, - # only those changes are analyzed, else only changes in HEAD~ are analyzed + # only those changes are analyzed, else only changes in HEAD~ are analyzed. # It's a super-useful option for integration of golangci-lint into existing # large codebase. It's not practical to fix all existing issues at the moment # of integration: much better don't allow issues in new code. @@ -1038,7 +226,7 @@ severity: # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message default-severity: error # The default value is false. - # If set to true severity-rules regular expressions become case-sensitive. + # If set to true severity-rules regular expressions become case sensitive. case-sensitive: false # Default value is empty list. # When a list of severity rules are provided, severity information will be added to lint From 8efe87c003471b818f384e84ae3cc95869d42962 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 13:22:46 +0200 Subject: [PATCH 18/31] style: golangci.yaml fix --- .golangci.yaml | 2 +- registry/registry/schema.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index f2c2c73..305e138 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -171,7 +171,7 @@ linters-settings: disable-all: false presets: - bugs - - unused + # - unused fast: false issues: # Excluding configuration per-path, per-linter, per-text and per-source diff --git a/registry/registry/schema.go b/registry/registry/schema.go index b1f92cb..c1c15c3 100644 --- a/registry/registry/schema.go +++ b/registry/registry/schema.go @@ -331,7 +331,7 @@ func flattenJSON(prefix string, nested interface{}, flat map[string]interface{}, switch nested.(type) { case map[string]interface{}: - for k, v := range nested.(map[string]interface{}) { + for k, v := range nested.(map[string]interface{}) { //nolint:gosimple // fine here newKey := k if currentDepth == 0 && strings.ToLower(newKey) != "properties" { continue @@ -345,7 +345,7 @@ func flattenJSON(prefix string, nested interface{}, flat map[string]interface{}, } } case []interface{}: - for i, v := range nested.([]interface{}) { + for i, v := range nested.([]interface{}) { //nolint:gosimple // fine here newKey := strconv.Itoa(i) if currentDepth != 0 { newKey = prefix + delimiter + newKey From 8ba3742d3d60079e013a030c0a9d705f34f183d7 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:06:08 +0200 Subject: [PATCH 19/31] refactor: removed deprecated usage of rand.seed in centralconsumer/main.go and pullecleaner/main.go --- validator/cmd/centralconsumer/main.go | 7 ------- validator/cmd/pullercleaner/main.go | 7 ------- validator/internal/centralconsumer/centralconsumer.go | 2 +- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/validator/cmd/centralconsumer/main.go b/validator/cmd/centralconsumer/main.go index 8b7e3b8..6d00957 100644 --- a/validator/cmd/centralconsumer/main.go +++ b/validator/cmd/centralconsumer/main.go @@ -2,16 +2,9 @@ package main import ( "flag" - "math/rand" - "time" - "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitorctl" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - func main() { configFile := flag.String("f", "", "toml file containing configuration of working environment") flag.Parse() diff --git a/validator/cmd/pullercleaner/main.go b/validator/cmd/pullercleaner/main.go index fa86a3a..92e3d35 100644 --- a/validator/cmd/pullercleaner/main.go +++ b/validator/cmd/pullercleaner/main.go @@ -2,16 +2,9 @@ package main import ( "flag" - "math/rand" - "time" - "github.com/dataphos/aquarium-janitor-standalone-internal/internal/janitorctl" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - func main() { configFile := flag.String("f", "", "toml file containing configuration of working environment") flag.Parse() diff --git a/validator/internal/centralconsumer/centralconsumer.go b/validator/internal/centralconsumer/centralconsumer.go index 8665c43..48e6e60 100644 --- a/validator/internal/centralconsumer/centralconsumer.go +++ b/validator/internal/centralconsumer/centralconsumer.go @@ -362,7 +362,7 @@ func (cc *CentralConsumer) getMessageTopicPair(messageSchemaPair janitor.Message acquireIfSet(cc.validatorsSem) var err error if cc.encryptionKey != "" { - encryptedMessageData = messageSchemaPair.Message.Payload + encryptedMessageData = messageSchemaPair.Message.Payload //nolint:ineffassign // fine for now messageSchemaPair.Message.Payload, err = janitor.Decrypt(messageSchemaPair.Message.Payload, cc.encryptionKey) if err != nil { messageSchemaPair.Message.RawAttributes["deadLetterErrorCategory"] = "Failure to decrypt" From 734cad8befb79c6570eb6c54580f67f287dd5904 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:15:15 +0200 Subject: [PATCH 20/31] style: lint fixes --- .golangci.yaml | 3 ++- registry/registry/schema.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 305e138..3846e02 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -113,7 +113,7 @@ linters-settings: min-complexity: 4 nolintlint: # Enable to ensure that nolint directives are all used. Default is true. - allow-unused: false + allow-unused: true # Disable to ensure that nolint directives don't have a leading space. Default is true. allow-leading-space: true # Exclude following linters from requiring an explanation. Default is []. @@ -128,6 +128,7 @@ linters-settings: - all - '-SA9003' # disable the rule SA9003 - '-SA4009' # disable the rule SA4009 + - '-SA4004' whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature diff --git a/registry/registry/schema.go b/registry/registry/schema.go index c1c15c3..01da7a2 100644 --- a/registry/registry/schema.go +++ b/registry/registry/schema.go @@ -329,7 +329,7 @@ func flattenJSON(prefix string, nested interface{}, flat map[string]interface{}, return nil } - switch nested.(type) { + switch nested.(type) { //nolint:gosimple // fine here case map[string]interface{}: for k, v := range nested.(map[string]interface{}) { //nolint:gosimple // fine here newKey := k From d2fb89a760b0a3eb26e66530a49964ee137b8fa4 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:20:01 +0200 Subject: [PATCH 21/31] style: lint fixes --- validator/internal/centralconsumer/centralconsumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/internal/centralconsumer/centralconsumer.go b/validator/internal/centralconsumer/centralconsumer.go index 48e6e60..c0dc041 100644 --- a/validator/internal/centralconsumer/centralconsumer.go +++ b/validator/internal/centralconsumer/centralconsumer.go @@ -362,7 +362,7 @@ func (cc *CentralConsumer) getMessageTopicPair(messageSchemaPair janitor.Message acquireIfSet(cc.validatorsSem) var err error if cc.encryptionKey != "" { - encryptedMessageData = messageSchemaPair.Message.Payload //nolint:ineffassign // fine for now + encryptedMessageData = messageSchemaPair.Message.Payload //nolint:ineffassign,staticcheck // fine for now messageSchemaPair.Message.Payload, err = janitor.Decrypt(messageSchemaPair.Message.Payload, cc.encryptionKey) if err != nil { messageSchemaPair.Message.RawAttributes["deadLetterErrorCategory"] = "Failure to decrypt" From b8c57f82db709fb42103b9701fa58683fde2e974 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:23:56 +0200 Subject: [PATCH 22/31] style: lint fixes --- .golangci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yaml b/.golangci.yaml index 3846e02..47595f6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -169,6 +169,7 @@ linters-settings: - asciicheck - maligned - prealloc + - unused disable-all: false presets: - bugs From 5d0e377a48d0b36529c647a87f09158b9c1042ed Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:28:20 +0200 Subject: [PATCH 23/31] style: lint fixes --- .golangci.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 47595f6..a33b22b 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -128,7 +128,8 @@ linters-settings: - all - '-SA9003' # disable the rule SA9003 - '-SA4009' # disable the rule SA4009 - - '-SA4004' + disable: + - SA4004 whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature From 1e16b75dac9cafc7641ce7215ec11b58fbeb3529 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:29:38 +0200 Subject: [PATCH 24/31] style: lint fixes --- .golangci.yaml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index a33b22b..042b4c7 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -122,14 +122,12 @@ linters-settings: require-explanation: true # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. require-specific: true - staticcheck: - # ignore some false positives for this project - checks: - - all - - '-SA9003' # disable the rule SA9003 - - '-SA4009' # disable the rule SA4009 - disable: - - SA4004 +# staticcheck: +# # ignore some false positives for this project +# checks: +# - all +# - '-SA9003' # disable the rule SA9003 +# - '-SA4009' # disable the rule SA4009 whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature From 5918ac0c4322bb7cf1005d89b520b9df2bebf0ce Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:34:08 +0200 Subject: [PATCH 25/31] style: lint fixes --- registry/registry/mock.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registry/registry/mock.go b/registry/registry/mock.go index 3ac81df..8a4aef0 100644 --- a/registry/registry/mock.go +++ b/registry/registry/mock.go @@ -1,3 +1,5 @@ +//nolint:unused + package registry import ( From 5c98cbc0bc4b72dc84ee05b05933e25bf6590153 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:40:03 +0200 Subject: [PATCH 26/31] style: lint fixes --- .golangci.yaml | 12 ++++++------ registry/registry/mock.go | 2 +- registry/registry/repository/firestore/firestore.go | 3 --- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 042b4c7..8d22db3 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -122,12 +122,12 @@ linters-settings: require-explanation: true # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. require-specific: true -# staticcheck: -# # ignore some false positives for this project -# checks: -# - all -# - '-SA9003' # disable the rule SA9003 -# - '-SA4009' # disable the rule SA4009 + staticcheck: + # ignore some false positives for this project + checks: + - all + - '-SA9003' # disable the rule SA9003 + - '-SA4009' # disable the rule SA4009 whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature diff --git a/registry/registry/mock.go b/registry/registry/mock.go index 8a4aef0..53e40e3 100644 --- a/registry/registry/mock.go +++ b/registry/registry/mock.go @@ -1,4 +1,4 @@ -//nolint:unused +//nolint:staticcheck,unused package registry diff --git a/registry/registry/repository/firestore/firestore.go b/registry/registry/repository/firestore/firestore.go index 62b0ee1..c49ad57 100644 --- a/registry/registry/repository/firestore/firestore.go +++ b/registry/registry/repository/firestore/firestore.go @@ -57,9 +57,6 @@ func (db *DB) DeleteSchemaVersion(id, version string) (bool, error) { deleted := false // flag to track if the version exists document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) - if err != nil { - - } // remove the one that has the version==version var result *Schema if err = document.DataTo(&result); err != nil { From 2e36fd399bad43584ab2387ea65eafa823ba18c5 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:47:27 +0200 Subject: [PATCH 27/31] style: lint fixes --- registry/registry/mock.go | 48 +++++++++---------- .../repository/firestore/firestore.go | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/registry/registry/mock.go b/registry/registry/mock.go index 53e40e3..bbbc7ad 100644 --- a/registry/registry/mock.go +++ b/registry/registry/mock.go @@ -20,38 +20,38 @@ type mockRepository struct { } type mockCompChecker struct { - checkCompResponse map[string]mockCheckComp + // checkCompResponse map[string]mockCheckComp } type mockValChecker struct { - checkValResponse map[string]mockValComp + // checkValResponse map[string]mockValComp } -type mockCheckComp struct { - ok bool - err error -} +//type mockCheckComp struct { +// ok bool +// err error +//} -type mockValComp struct { - ok bool - err error -} +//type mockValComp struct { +// ok bool +// err error +//} type mockCreateSchema struct { VersionDetails VersionDetails - ok bool - err error + //ok bool + //err error } type mockGetSchemaVersionByIdAndVersion struct { VersionDetails VersionDetails - err error + //err error } type mockUpdateSchemaById struct { VersionDetails VersionDetails - ok bool - err error + //ok bool + //err error } type mockGetSchemaVersionsById struct { @@ -60,17 +60,17 @@ type mockGetSchemaVersionsById struct { } type mockGetAllSchemaVersions struct { - schema Schema - err error + //schema Schema + err error } type mockGetLatestSchemaVersion struct { - schema Schema - err error + //schema Schema + err error } type mockDeleteSchema struct { - ok bool + //ok bool err error } @@ -80,13 +80,13 @@ type mockDeleteSchemaVersion struct { } type mockGetSchemas struct { - schemas []Schema - err error + //schemas []Schema + err error } type mockGetAllSchemas struct { - schemas []Schema - err error + //schemas []Schema + err error } func MockSchema(id string) Schema { diff --git a/registry/registry/repository/firestore/firestore.go b/registry/registry/repository/firestore/firestore.go index c49ad57..5a841e4 100644 --- a/registry/registry/repository/firestore/firestore.go +++ b/registry/registry/repository/firestore/firestore.go @@ -56,7 +56,7 @@ func (db *DB) DeleteSchemaVersion(id, version string) (bool, error) { ctx := context.Background() deleted := false // flag to track if the version exists - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) //nolint:ineffassign // remove the one that has the version==version var result *Schema if err = document.DataTo(&result); err != nil { From eb38e16eb517acf1022f1b0364f779ac391a3807 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 14:50:15 +0200 Subject: [PATCH 28/31] style: lint fixes --- registry/registry/mock.go | 8 ++++---- registry/registry/repository/firestore/firestore.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/registry/registry/mock.go b/registry/registry/mock.go index bbbc7ad..216bdc5 100644 --- a/registry/registry/mock.go +++ b/registry/registry/mock.go @@ -61,21 +61,21 @@ type mockGetSchemaVersionsById struct { type mockGetAllSchemaVersions struct { //schema Schema - err error + //err error } type mockGetLatestSchemaVersion struct { //schema Schema - err error + //err error } type mockDeleteSchema struct { //ok bool - err error + //err error } type mockDeleteSchemaVersion struct { - ok bool + //ok bool err error } diff --git a/registry/registry/repository/firestore/firestore.go b/registry/registry/repository/firestore/firestore.go index 5a841e4..998fe50 100644 --- a/registry/registry/repository/firestore/firestore.go +++ b/registry/registry/repository/firestore/firestore.go @@ -56,7 +56,7 @@ func (db *DB) DeleteSchemaVersion(id, version string) (bool, error) { ctx := context.Background() deleted := false // flag to track if the version exists - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) //nolint:ineffassign + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) //nolint:ineffassign,staticcheck // remove the one that has the version==version var result *Schema if err = document.DataTo(&result); err != nil { From decd17109d51783100bff1a634b5543c421b6a7c Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 15:11:48 +0200 Subject: [PATCH 29/31] style: lint fixes --- registry/registry/mock.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/registry/registry/mock.go b/registry/registry/mock.go index 216bdc5..8fea124 100644 --- a/registry/registry/mock.go +++ b/registry/registry/mock.go @@ -39,19 +39,14 @@ type mockValChecker struct { type mockCreateSchema struct { VersionDetails VersionDetails - //ok bool - //err error } type mockGetSchemaVersionByIdAndVersion struct { VersionDetails VersionDetails - //err error } type mockUpdateSchemaById struct { VersionDetails VersionDetails - //ok bool - //err error } type mockGetSchemaVersionsById struct { @@ -60,33 +55,21 @@ type mockGetSchemaVersionsById struct { } type mockGetAllSchemaVersions struct { - //schema Schema - //err error } type mockGetLatestSchemaVersion struct { - //schema Schema - //err error } type mockDeleteSchema struct { - //ok bool - //err error } type mockDeleteSchemaVersion struct { - //ok bool - err error } type mockGetSchemas struct { - //schemas []Schema - err error } type mockGetAllSchemas struct { - //schemas []Schema - err error } func MockSchema(id string) Schema { From 56094231908e9f557de04e1b594fe25d4eba99d8 Mon Sep 17 00:00:00 2001 From: Skenktio Date: Wed, 9 Oct 2024 15:42:49 +0200 Subject: [PATCH 30/31] refactor: firestore removed --- .github/workflows/pr.yaml | 3 +- .github/workflows/push.yaml | 2 +- README.md | 2 +- registry/README.md | 4 +- registry/cmd/janitorsr-firestore/main.go | 129 -- registry/docker/registry-firestore/Dockerfile | 38 - registry/go.mod | 19 - registry/go.sum | 1409 ----------------- .../repository/firestore/firestore.go | 325 ---- .../registry/repository/firestore/model.go | 87 - 10 files changed, 5 insertions(+), 2013 deletions(-) delete mode 100644 registry/cmd/janitorsr-firestore/main.go delete mode 100644 registry/docker/registry-firestore/Dockerfile delete mode 100644 registry/registry/repository/firestore/firestore.go delete mode 100644 registry/registry/repository/firestore/model.go diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index c643379..8771fd1 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -48,7 +48,6 @@ jobs: - ./registry/docker/compatibility-checker/Dockerfile - ./registry/docker/initdb/Dockerfile - ./registry/docker/registry/Dockerfile - - ./registry/docker/registry-firestore/Dockerfile - ./registry/docker/validity-checker/Dockerfile steps: @@ -277,7 +276,7 @@ jobs: - dockerfile-path: ./validator/docker/csv-validator/Dockerfile image-name: schema-registry-csv-val - dockerfile-path: ./validator/docker/validator/Dockerfile - image-name: schema-registry-worker + image-name: schema-registry-validator - dockerfile-path: ./validator/docker/xml-validator/Dockerfile image-name: schema-registry-xml-val - dockerfile-path: ./registry/docker/compatibility-checker/Dockerfile diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index 1296a28..e721192 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -94,7 +94,7 @@ jobs: - dockerfile-path: ./validator/docker/csv-validator/Dockerfile image-name: schema-registry-csv-val - dockerfile-path: ./validator/docker/validator/Dockerfile - image-name: schema-registry-worker + image-name: schema-registry-validator - dockerfile-path: ./validator/docker/xml-validator/Dockerfile image-name: schema-registry-xml-val - dockerfile-path: ./registry/docker/compatibility-checker/Dockerfile diff --git a/README.md b/README.md index 68de3de..85a7783 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ All of the other requirements for the product to fully-function (message broker ### Registry - Takes care of everything related to the schemas themselves - registration, updates, retrieval, deletion of an entire schema or its particular version, as well as performing schema checks for validity and compatibility (backwards, forwards and transitively). - Its REST API provides handles for clients and communicates via HTTP requests. -- With regards to the message schemas themselves, the Schema History database where they get stored in can be anything from a standard SQL database like Oracle or PostgreSQL, to a NoSQL database like Firestore or MongoDB. +- With regards to the message schemas themselves, the Schema History database where they get stored in can be anything from a standard SQL database like Oracle or PostgreSQL, to a NoSQL database like MongoDB. ### Validator - In order for the Validator to work, the message schema needs to be registered in the Schema History database. diff --git a/registry/README.md b/registry/README.md index 07310c0..fabf3ef 100644 --- a/registry/README.md +++ b/registry/README.md @@ -22,8 +22,8 @@ requests. The worker component communicates with the REST API by sending the HTTP GET request that retrieves a message schema from the Registry by using the necessary parameters. The message schemas themselves can be stored in any type of database ( -Schema History), whether in tables like in standard SQL databases, such as Oracle or PostgreSQL, or NoSQL databases like -Firestore, MongoDB etc. The component itself has an interface with the database connector that can be easily modified to +Schema History), whether in tables like in standard SQL databases, such as Oracle or PostgreSQL, or NoSQL databases like +MongoDB. The component itself has an interface with the database connector that can be easily modified to work with databases that fit the client’s needs. diff --git a/registry/cmd/janitorsr-firestore/main.go b/registry/cmd/janitorsr-firestore/main.go deleted file mode 100644 index 4b19109..0000000 --- a/registry/cmd/janitorsr-firestore/main.go +++ /dev/null @@ -1,129 +0,0 @@ -package main - -import ( - "context" - "fmt" - "net/http" - "os" - "os/signal" - "runtime/debug" - "strconv" - "syscall" - "time" - - "github.com/pkg/errors" - - "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility" - "github.com/dataphos/aquarium-janitor-standalone-sr/internal/config" - "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" - "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" - "github.com/dataphos/aquarium-janitor-standalone-sr/registry" - "github.com/dataphos/aquarium-janitor-standalone-sr/registry/repository/firestore" - "github.com/dataphos/aquarium-janitor-standalone-sr/server" - "github.com/dataphos/aquarium-janitor-standalone-sr/validity" - "github.com/dataphos/lib-logger/logger" - "github.com/dataphos/lib-logger/standardlogger" -) - -const ( - serverPortEnvKey = "SERVER_PORT" -) - -const ( - defaultServerPort = 8080 -) - -func main() { - labels := logger.Labels{ - "product": "Janitor", - "component": "Schema Registry", - } - var Commit = func() string { - if info, ok := debug.ReadBuildInfo(); ok { - for _, setting := range info.Settings { - if setting.Key == "vcs.revision" { - return setting.Value - } - } - } - - return "" - }() - if Commit != "" { - labels["commit"] = Commit - } - - logLevel, logConfigWarnings := config.GetLogLevel() - log := standardlogger.New(labels, standardlogger.WithLogLevel(logLevel)) - - for _, w := range logConfigWarnings { - log.Warn(w) - } - - db, err := firestore.New() - if err != nil { - log.Error(err.Error(), errcodes.DatabaseConnectionInitialization) - return - } - - var port int - portStr := os.Getenv(serverPortEnvKey) - if portStr == "" { - port = defaultServerPort - } else { - port, err = strconv.Atoi(portStr) - if err != nil { - log.Error(errtemplates.ExpectedInt(serverPortEnvKey, portStr).Error(), errcodes.ServerInitialization) - return - } - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - compChecker, globalCompMode, err := compatibility.InitCompatibilityChecker(ctx) - if err != nil { - log.Error(err.Error(), errcodes.ExternalCheckerInitialization) - return - } - log.Info("Successfully connected compatibility checker.") - - valChecker, globalValMode, err := validity.InitExternalValidityChecker(ctx) - if err != nil { - log.Error(err.Error(), errcodes.ExternalCheckerInitialization) - return - } - log.Info("Successfully connected validity checker.") - - srv := http.Server{ - Addr: fmt.Sprintf(":%d", port), - Handler: server.New(server.NewHandler(registry.New(db, compChecker, valChecker, globalCompMode, globalValMode), log)), - } - - idleConnsClosed := make(chan struct{}) - go func() { - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) - - <-c - - log.Info("initiating graceful shutdown") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - if err = srv.Shutdown(ctx); err != nil { - log.Error(errors.Wrap(err, "graceful shutdown failed").Error(), errcodes.ServerShutdown) - } - close(idleConnsClosed) - }() - - log.Infow("starting server", logger.F{"port": srv.Addr}) - if err = srv.ListenAndServe(); err != nil { - if err != http.ErrServerClosed { - log.Error(errors.Wrap(err, "an error occurred starting or closing server").Error(), errcodes.ServerShutdown) - } - } - - <-idleConnsClosed - - log.Info("shutting down") -} diff --git a/registry/docker/registry-firestore/Dockerfile b/registry/docker/registry-firestore/Dockerfile deleted file mode 100644 index 86315f7..0000000 --- a/registry/docker/registry-firestore/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM golang:alpine3.15 AS build - -LABEL maintainer="Syntio Inc." - -ENV GO111MODULE=on \ - GOOS=linux \ - GOARCH=amd64 \ - CGO_ENABLED=0 - -RUN apk add --no-cache git - -WORKDIR /src - -COPY ./registry/go.mod ./registry/go.sum ./ -RUN go mod download - -COPY ./registry . -COPY LICENSE ./licenses/ - -RUN go mod tidy - -RUN go build -buildvcs=false -o /app/sr ./cmd/janitorsr-firestore - -FROM alpine:3.16 - -COPY --from=build /app/sr /app/sr -COPY --from=build /src/licenses/LICENSE-3RD-PARTY.md /app/licenses/ -COPY --from=build /src/licenses/LICENSE /app/licenses/ - -# change to a non-root user for security -RUN adduser -D -h /app user -RUN chown -R user /app -RUN chmod -R 700 /app -USER user - -EXPOSE 8080 - -CMD ["/app/sr"] diff --git a/registry/go.mod b/registry/go.mod index 1cc9407..826d661 100644 --- a/registry/go.mod +++ b/registry/go.mod @@ -9,13 +9,11 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 golang.org/x/text v0.13.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gorm.io/driver/postgres v1.5.2 gorm.io/gorm v1.25.4 ) require ( - cloud.google.com/go/firestore v1.13.0 github.com/cyberphone/json-canonicalization v0.0.0-20230710064741-aa7fe85c7dbd github.com/dataphos/lib-httputil v1.0.0 github.com/dataphos/lib-retry v1.0.0 @@ -27,14 +25,9 @@ require ( github.com/swaggo/http-swagger v1.3.4 github.com/swaggo/swag v1.16.2 golang.org/x/sync v0.3.0 - google.golang.org/api v0.143.0 ) require ( - cloud.google.com/go v0.110.8 // indirect - cloud.google.com/go/compute v1.23.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/longrunning v0.5.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -43,11 +36,7 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/swag v0.22.4 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.4.3 // indirect @@ -65,20 +54,12 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/swaggo/files v1.0.1 // indirect - go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.13.0 // indirect golang.org/x/net v0.15.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sys v0.12.0 // indirect - golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.13.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/grpc v1.58.2 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/registry/go.sum b/registry/go.sum index cb1a2e5..27a7b5b 100644 --- a/registry/go.sum +++ b/registry/go.sum @@ -3,7 +3,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -14,804 +13,34 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -820,24 +49,12 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -847,20 +64,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberphone/json-canonicalization v0.0.0-20230710064741-aa7fe85c7dbd h1:0av0vtcjA8Hqv5gyWj79CLCFVwOOyBNWPjrfUWceMNg= @@ -874,42 +77,16 @@ github.com/dataphos/lib-retry v1.0.0/go.mod h1:0T0VfgdamSHvieGMVMBRThXqZGezx/E1b github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -918,8 +95,6 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -942,20 +117,12 @@ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -963,8 +130,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -980,15 +145,12 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -996,22 +158,14 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -1019,62 +173,17 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/hamba/avro/v2 v2.16.0 h1:0XhyP65Hs8iMLtdSR0v7ZrwRjsbIZdvr7KzYgmx1Mbo= github.com/hamba/avro/v2 v2.16.0/go.mod h1:Q9YK+qxAhtVrNqOhwlZTATLgLA8qxG2vtvkhK8fJ7Jo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -1101,16 +210,9 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -1121,25 +223,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1157,17 +248,11 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1206,27 +291,18 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1243,7 +319,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= @@ -1260,25 +335,14 @@ github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtX github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= @@ -1294,51 +358,26 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1349,8 +388,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1359,17 +396,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1400,46 +430,19 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1447,34 +450,10 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1483,15 +462,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1511,7 +486,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1526,115 +500,52 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1648,7 +559,6 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1675,47 +585,17 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1732,55 +612,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= -google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA= -google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1788,8 +619,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1813,159 +642,12 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:qDbnxtViX5J6CvFbxeNUSzKgVlDLJ/6L+caxye9+Flo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1978,42 +660,6 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2026,10 +672,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -2066,60 +710,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/registry/registry/repository/firestore/firestore.go b/registry/registry/repository/firestore/firestore.go deleted file mode 100644 index 998fe50..0000000 --- a/registry/registry/repository/firestore/firestore.go +++ /dev/null @@ -1,325 +0,0 @@ -package firestore - -import ( - "cloud.google.com/go/firestore" - "context" - "encoding/base64" - "google.golang.org/api/iterator" - "log" - "os" - "strconv" - "time" - - "github.com/dataphos/aquarium-janitor-standalone-sr/registry" - "github.com/dataphos/aquarium-janitor-standalone-sr/registry/internal/hashutils" -) - -// Rewrite all functions to work differently based on whether the schema is active or not. - -// Firestore implementation for database.DBExecutor interface. -type DB struct { - Collection string - Client *firestore.Client -} - -// CREDENTIAL FILE NEED TO BE SET UNDER ENV VAR "GOOGLE_APPLICATION_CREDENTIALS" -func New() (*DB, error) { - ctx := context.Background() - - collection := os.Getenv("COLLECTION") - projectId := os.Getenv("PROJECT_ID") - - client, initErr := firestore.NewClient(ctx, projectId) - if initErr != nil { - log.Fatalf("Firestore client initialization failed. Server can't start properly.\nError: %s", initErr) - } - return &DB{ - Collection: collection, - Client: client, - }, nil -} - -// DeleteSchema takes the id of the schema which needs to be deleted -// will return bool that indicates if the schema was deleted and error -func (db *DB) DeleteSchema(id string) (bool, error) { - ctx := context.Background() - _, err := db.Client.Collection(db.Collection).Doc(id).Delete(ctx) - if err != nil { - return false, err - } - return true, err -} - -// DeleteSchemaVersion takes the id of the schema and version which needs to be deleted -// will return bool that indicates if the schema was deleted and error -func (db *DB) DeleteSchemaVersion(id, version string) (bool, error) { - ctx := context.Background() - deleted := false // flag to track if the version exists - - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) //nolint:ineffassign,staticcheck - // remove the one that has the version==version - var result *Schema - if err = document.DataTo(&result); err != nil { - return false, err - } - var newDetails []VersionDetails - for i, v := range result.VersionDetails { - versionInt, _ := strconv.Atoi(version) - if v.Version != int32(versionInt) { - newDetails = append(newDetails, result.VersionDetails[i:i+1]...) - continue - } - // set deleted to true, so we know that the version existed - deleted = true - } - if deleted { - // update the new version details only if the version exists - _, err = db.Client.Collection(db.Collection).Doc(id).Set(ctx, map[string]interface{}{ - "schemas": newDetails, - }, firestore.MergeAll) - if err != nil { - return false, err - } - } - - return deleted, nil -} - -// GetSchemaVersionByIdAndVersion retrieves a schema by its id and version. Method returns a boolean flag which defines -// if the wanted schema exists. If the schema is found, representing Payload is retrieved. -func (db *DB) GetSchemaVersionByIdAndVersion(id, version string) (registry.VersionDetails, error) { - ctx := context.Background() - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) - if err != nil { - log.Printf("could not get schema by that ID: %v", err) - return registry.VersionDetails{}, err - } - var result *Schema - if err = document.DataTo(&result); err != nil { - return registry.VersionDetails{}, err - } - - for i, v := range result.VersionDetails { - versionInt, _ := strconv.Atoi(version) - if v.Version == int32(versionInt) { - newDetails := result.VersionDetails[i : i+1] - return intoRegistryVersionDetails(newDetails[0]), nil - } - } - return registry.VersionDetails{}, err -} - -// GetSchemaVersionsById returns a list of VersionDetails from the database. -// The input arguments are the request context and the document/row ID. -// The return value is a list of model.VersionDetails and an error in case of a fault or failure. -// Has to be rewritten to return only active schemas -func (db *DB) GetSchemaVersionsById(id string) (registry.Schema, error) { - ctx := context.Background() - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) - if err != nil { - log.Printf("could not get schema by that ID: %v", err) - return registry.Schema{}, err - } - var result Schema - if err = document.DataTo(&result); err != nil { - return registry.Schema{}, err - } - return intoRegistrySchema(result), nil -} - -// GetAllSchemaVersions returns a list of VersionDetails from the database. -// The input arguments are the request context and the document/row ID. -// The return value is a list of model.VersionDetails and an error in case of a fault or failure. -func (db *DB) GetAllSchemaVersions(id string) (registry.Schema, error) { - ctx := context.Background() - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) - if err != nil { - log.Printf("could not get schema by that ID: %v", err) - return registry.Schema{}, err - } - var result Schema - if err = document.DataTo(&result); err != nil { - return registry.Schema{}, err - } - return intoRegistrySchema(result), nil -} - -// GetLatestSchemaVersion retrieves the latest VersionDetails of a schema by its id. -func (db *DB) GetLatestSchemaVersion(id string) (registry.VersionDetails, error) { - document, err := db.Client.Collection(db.Collection).Doc(id).Get(context.Background()) - if err != nil { - log.Printf("could not get schema by that ID: %v", err) - return registry.VersionDetails{}, err - } - var result Schema - if err = document.DataTo(&result); err != nil { - return registry.VersionDetails{}, err - } - - for i, v := range result.VersionDetails { - // because versions start from 1 - if int(v.Version) == len(result.VersionDetails) { - newDetails := result.VersionDetails[i : i+1] - result.VersionDetails = newDetails - return intoRegistryVersionDetails(result.VersionDetails[0]), nil - } - } - return registry.VersionDetails{}, nil -} - -// GetSchemas retrieves all schemas in the Collection -// Has to be rewritten to return only active schemas -func (db *DB) GetSchemas() ([]registry.Schema, error) { - var allSchemas []registry.Schema - iter := db.Client.Collection(db.Collection).Documents(context.Background()) - defer iter.Stop() - for { - doc, err := iter.Next() - if err == iterator.Done { - break - } - if err != nil { - return nil, err - } - - var result Schema - if err = doc.DataTo(&result); err != nil { - return nil, err - } - allSchemas = append(allSchemas, intoRegistrySchema(result)) - } - - return allSchemas, nil -} - -// GetAllSchemas retrieves all schemas in the Collection -func (db *DB) GetAllSchemas() ([]registry.Schema, error) { - var allSchemas []registry.Schema - iter := db.Client.Collection(db.Collection).Documents(context.Background()) - defer iter.Stop() - for { - doc, err := iter.Next() - if err == iterator.Done { - break - } - if err != nil { - return nil, err - } - - var result Schema - if err = doc.DataTo(&result); err != nil { - return nil, err - } - allSchemas = append(allSchemas, intoRegistrySchema(result)) - } - return allSchemas, nil -} - -// UpdateSchemaById updates the schema Specification e.g. creates a new entry of VersionDetails. -// The input arguments are the request context, followed by the ID string of the document/row ID, -// specification in []byte form and a flag indicating if Schema was manually updated or dynamically evolved. -// The output is a model.InsertInfo structure, a flag indicating if new version of schema was added and an error. -func (db *DB) UpdateSchemaById(id string, schemaUpdateRequest registry.SchemaUpdateRequest) (registry.VersionDetails, bool, error) { - ctx := context.Background() - document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) - if err != nil { - log.Printf("could not get schema by that ID: %v", err) - return registry.VersionDetails{}, false, err - } - - var result *Schema - if err = document.DataTo(&result); err != nil { - return registry.VersionDetails{}, false, err - } - - hash := hashutils.SHA256([]byte(schemaUpdateRequest.Specification)) - - if exists, info := db.existsByHash(hash, result); exists { - log.Printf("Schema %v with version %d already exists ", result.SchemaID, info.Version) - return intoRegistryVersionDetails(*info), false, nil - } - - newVersion := int32(len(result.VersionDetails) + 1) - d := &VersionDetails{ - VersionID: id, - SchemaID: id, - Version: newVersion, - SchemaHash: hash, - Specification: base64.StdEncoding.EncodeToString([]byte(schemaUpdateRequest.Specification)), - } - details := result.VersionDetails - details = append(details, *d) - result.VersionDetails = details - - if _, err := db.Client.Collection(db.Collection).Doc(id).Set(ctx, result); err != nil { - log.Println("Could not update new schema") - return registry.VersionDetails{}, false, err - } - - return registry.VersionDetails{ - VersionID: id, - SchemaID: id, - Version: strconv.Itoa(int(newVersion)), - Specification: schemaUpdateRequest.Specification, - Description: schemaUpdateRequest.Description, - SchemaHash: hash, - CreatedAt: time.Now(), - }, true, nil -} - -// CreateSchema persists a new Schema structure into the document or relational database. -// Input arguments are request context, and a DTO describing the basic new schema parameters. -// The output is a model.InsertInfo structure, a flag indicating if new version of schema was added and an error. -func (db *DB) CreateSchema(schemaRegisterRequest registry.SchemaRegistrationRequest) (registry.VersionDetails, bool, error) { - ctx := context.Background() - byteSchema := []byte(schemaRegisterRequest.Specification) - hash := hashutils.SHA256(byteSchema) - - it := db.Client.Collection(db.Collection).Documents(ctx) - for sh, err := it.Next(); err != iterator.Done; sh, err = it.Next() { - if err != nil { - log.Println("Could not read existing data") - return registry.VersionDetails{}, false, err - } - var schema *Schema - err = sh.DataTo(&schema) - if err != nil { - log.Printf("err while transfering schema to struct: %v", err) - return registry.VersionDetails{}, false, err - } - if exists, _ := db.existsByHash(hash, schema); exists { - return intoRegistryVersionDetails(schema.VersionDetails[0]), false, err - } - } - version := int32(1) - doc := db.Client.Collection(db.Collection).NewDoc() - - sc := fillOutSchema(schemaRegisterRequest, doc.ID, hash, version) - if _, err := doc.Set(ctx, sc); err != nil { - log.Println("Could not create new schema") - return registry.VersionDetails{}, false, err - } - return intoRegistryVersionDetails(sc.VersionDetails[0]), true, nil -} - -// existsByHash is a helper function that checks if there is a corresponding hash in a schema. -// the input arguments are a sha-256 hash of the schema specification and a model.Schema struct. -// the output is a flag indicating if the schema exists, and were the flag true the corresponding model.InsertInfo -// struct. -func (db *DB) existsByHash(hash string, schema *Schema) (bool, *VersionDetails) { - var info *VersionDetails - for _, sd := range schema.VersionDetails { - if sd.SchemaHash == hash { - info = &VersionDetails{ - VersionID: sd.VersionID, - Version: sd.Version, - SchemaID: sd.SchemaID, - Specification: sd.Specification, - SchemaHash: hash, - Description: sd.Description, - } - return true, info - } - } - return false, nil -} diff --git a/registry/registry/repository/firestore/model.go b/registry/registry/repository/firestore/model.go deleted file mode 100644 index 4b17365..0000000 --- a/registry/registry/repository/firestore/model.go +++ /dev/null @@ -1,87 +0,0 @@ -package firestore - -import ( - "encoding/base64" - "github.com/dataphos/aquarium-janitor-standalone-sr/registry" - "strconv" - "time" -) - -// Schema is a structure that defines the parent entity in the schema registry. -type Schema struct { - SchemaID string `json:"schema_id,omitempty" bson:"schema-id,omitempty" firestore:"schema-id"` - SchemaType string `json:"schema_type" bson:"schema-type" firestore:"schema-type"` - Name string `json:"name" bson:"name" firestore:"name"` - Description string `json:"description" bson:"description" firestore:"description"` - LastCreated string `json:"last_created" bson:"last-created" firestore:"last-created"` - PublisherID string `json:"publisher_id" bson:"publisher-id" firestore:"publisher-id"` - VersionDetails []VersionDetails `json:"schemas" bson:"schemas" firestore:"schemas"` -} - -// VersionDetails represents the child entity in the schema registry model. -type VersionDetails struct { - VersionID string `json:"id,omitempty" bson:"_id,omitempty" firestore:"ID"` - Version int32 `json:"version" bson:"version" firestore:"version"` - SchemaID string `json:"schemaID" bson:"schemaID" firestore:"schemaID"` - Description string `json:"description" bson:"description" firestore:"description"` - Specification string `json:"specification" bson:"specification" firestore:"specification"` - SchemaHash string `json:"schema_hash" bson:"schema-hash" firestore:"schema-hash"` - CreatedAt time.Time `json:"creation_date" bson:"creation-date" firestore:"creation-date"` - VersionDeactivated bool `json:"version_deactivated" bson:"version-deactivated" firestore:"version-deactivated"` -} - -// intoRegistrySchema maps Schema from repository to service layer. -func intoRegistrySchema(schema Schema) registry.Schema { - var registryVersionDetails []registry.VersionDetails - for _, versionDetails := range schema.VersionDetails { - registryVersionDetails = append(registryVersionDetails, intoRegistryVersionDetails(versionDetails)) - } - - return registry.Schema{ - SchemaID: schema.SchemaID, - SchemaType: schema.SchemaType, - Name: schema.Name, - VersionDetails: registryVersionDetails, - Description: schema.Description, - LastCreated: schema.LastCreated, - PublisherID: schema.PublisherID, - } -} - -// intoRegistryVersionDetails maps VersionDetails from repository to service layer. -func intoRegistryVersionDetails(VersionDetails VersionDetails) registry.VersionDetails { - return registry.VersionDetails{ - VersionID: VersionDetails.VersionID, - Version: strconv.Itoa(int(VersionDetails.Version)), - SchemaID: VersionDetails.SchemaID, - Specification: VersionDetails.Specification, - Description: VersionDetails.Description, - SchemaHash: VersionDetails.SchemaHash, - CreatedAt: VersionDetails.CreatedAt, - VersionDeactivated: VersionDetails.VersionDeactivated, - } -} - -func fillOutSchema(schema registry.SchemaRegistrationRequest, documentID, hash string, version int32) *Schema { - b64coder := base64.StdEncoding - - return &Schema{ - SchemaID: documentID, - SchemaType: schema.SchemaType, - Name: schema.Name, - VersionDetails: []VersionDetails{ - { - VersionID: documentID, - Version: version, - SchemaID: documentID, - Specification: b64coder.EncodeToString([]byte(schema.Specification)), - Description: "", - SchemaHash: hash, - CreatedAt: time.Now(), - }, - }, - LastCreated: time.Now().String(), - Description: schema.Description, - PublisherID: "", - } -} From c3a66794b0b451e54686c780a67ce538641a8cf1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Oct 2024 13:44:43 +0000 Subject: [PATCH 31/31] chore: update third party licenses --- registry/licenses/LICENSE-3RD-PARTY.md | 115 +++++++++++-------------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/registry/licenses/LICENSE-3RD-PARTY.md b/registry/licenses/LICENSE-3RD-PARTY.md index fb44fa6..5193a73 100644 --- a/registry/licenses/LICENSE-3RD-PARTY.md +++ b/registry/licenses/LICENSE-3RD-PARTY.md @@ -1,67 +1,48 @@ -| Module | License | -|:----------------------------------------------------------------------------------------|:-------------| -| cloud.google.com/go/compute/metadata v0.2.3 (indirect) | Apache-2.0 | -| cloud.google.com/go/firestore v1.13.0 | Apache-2.0 | -| cloud.google.com/go/internal | Apache-2.0 | -| cloud.google.com/go/longrunning/autogen/longrunningpb | Apache-2.0 | -| github.com/KyleBanks/depth v1.2.1 (indirect) | MIT | -| github.com/beorn7/perks/quantile | MIT | -| github.com/cespare/xxhash/v2 v2.2.0 (indirect) | MIT | -| github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer | Apache-2.0 | -| github.com/go-chi/chi/v5 v5.0.10 | MIT | -| github.com/go-openapi/jsonpointer v0.20.0 (indirect) | Apache-2.0 | -| github.com/go-openapi/jsonreference v0.20.2 (indirect) | Apache-2.0 | -| github.com/go-openapi/spec v0.20.9 (indirect) | Apache-2.0 | -| github.com/go-openapi/swag v0.22.4 (indirect) | Apache-2.0 | -| github.com/golang/groupcache/lru | Apache-2.0 | -| github.com/golang/protobuf v1.5.3 (indirect) | BSD-3-Clause | -| github.com/google/go-cmp/cmp | BSD-3-Clause | -| github.com/google/s2a-go v0.1.7 (indirect) | Apache-2.0 | -| github.com/googleapis/enterprise-certificate-proxy/client | Apache-2.0 | -| github.com/googleapis/gax-go/v2 v2.12.0 (indirect) | BSD-3-Clause | -| github.com/hamba/avro/v2 v2.16.0 | MIT | -| github.com/hashicorp/golang-lru v1.0.2 | MPL-2.0 | -| github.com/jackc/pgpassfile v1.0.0 (indirect) | MIT | -| github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a (indirect) | MIT | -| github.com/jackc/pgx/v5 v5.4.3 (indirect) | MIT | -| github.com/jinzhu/inflection v1.0.0 (indirect) | MIT | -| github.com/jinzhu/now v1.1.5 (indirect) | MIT | -| github.com/josharian/intern v1.0.0 (indirect) | MIT | -| github.com/json-iterator/go v1.1.12 (indirect) | MIT | -| github.com/mailru/easyjson v0.7.7 (indirect) | MIT | -| github.com/matttproud/golang_protobuf_extensions/pbutil | Apache-2.0 | -| github.com/mitchellh/mapstructure v1.5.0 (indirect) | MIT | -| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd (indirect) | Apache-2.0 | -| github.com/modern-go/reflect2 v1.0.2 (indirect) | Apache-2.0 | -| github.com/pkg/errors v0.9.1 | BSD-2-Clause | -| github.com/prometheus/client_golang/prometheus | Apache-2.0 | -| github.com/prometheus/client_model/go | Apache-2.0 | -| github.com/prometheus/common v0.44.0 (indirect) | Apache-2.0 | -| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | BSD-3-Clause | -| github.com/prometheus/procfs v0.12.0 (indirect) | Apache-2.0 | -| github.com/spf13/cast v1.5.1 | MIT | -| github.com/swaggo/files v1.0.1 (indirect) | MIT | -| github.com/swaggo/http-swagger v1.3.4 | MIT | -| github.com/swaggo/swag v1.16.2 | MIT | -| go.opencensus.io v0.24.0 (indirect) | Apache-2.0 | -| go.uber.org/multierr v1.11.0 (indirect) | MIT | -| go.uber.org/zap v1.26.0 (indirect) | MIT | -| golang.org/x/crypto v0.13.0 (indirect) | BSD-3-Clause | -| golang.org/x/net v0.15.0 (indirect) | BSD-3-Clause | -| golang.org/x/oauth2 v0.12.0 (indirect) | BSD-3-Clause | -| golang.org/x/sync v0.3.0 | BSD-3-Clause | -| golang.org/x/sys v0.12.0 (indirect) | BSD-3-Clause | -| golang.org/x/text v0.13.0 (indirect) | BSD-3-Clause | -| golang.org/x/time/rate | BSD-3-Clause | -| golang.org/x/tools v0.13.0 (indirect) | BSD-3-Clause | -| golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 (indirect) | BSD-3-Clause | -| google.golang.org/api v0.143.0 | BSD-3-Clause | -| google.golang.org/api/internal/third_party/uritemplates | BSD-3-Clause | -| google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 (indirect) | Apache-2.0 | -| google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 (indirect) | Apache-2.0 | -| google.golang.org/genproto/googleapis/type/latlng | Apache-2.0 | -| google.golang.org/grpc v1.58.2 (indirect) | Apache-2.0 | -| google.golang.org/protobuf v1.31.0 (indirect) | BSD-3-Clause | -| gopkg.in/yaml.v3 v3.0.1 (indirect) | MIT | -| gorm.io/driver/postgres v1.5.2 | MIT | -| gorm.io/gorm v1.25.4 | MIT | \ No newline at end of file +| Module | License | +|:--------------------------------------------------------------------------------|:-------------| +| github.com/KyleBanks/depth v1.2.1 (indirect) | MIT | +| github.com/beorn7/perks/quantile | MIT | +| github.com/cespare/xxhash/v2 v2.2.0 (indirect) | MIT | +| github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer | Apache-2.0 | +| github.com/go-chi/chi/v5 v5.0.10 | MIT | +| github.com/go-openapi/jsonpointer v0.20.0 (indirect) | Apache-2.0 | +| github.com/go-openapi/jsonreference v0.20.2 (indirect) | Apache-2.0 | +| github.com/go-openapi/spec v0.20.9 (indirect) | Apache-2.0 | +| github.com/go-openapi/swag v0.22.4 (indirect) | Apache-2.0 | +| github.com/golang/protobuf/proto | BSD-3-Clause | +| github.com/hamba/avro/v2 v2.16.0 | MIT | +| github.com/hashicorp/golang-lru v1.0.2 | MPL-2.0 | +| github.com/jackc/pgpassfile v1.0.0 (indirect) | MIT | +| github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a (indirect) | MIT | +| github.com/jackc/pgx/v5 v5.4.3 (indirect) | MIT | +| github.com/jinzhu/inflection v1.0.0 (indirect) | MIT | +| github.com/jinzhu/now v1.1.5 (indirect) | MIT | +| github.com/josharian/intern v1.0.0 (indirect) | MIT | +| github.com/json-iterator/go v1.1.12 (indirect) | MIT | +| github.com/mailru/easyjson v0.7.7 (indirect) | MIT | +| github.com/matttproud/golang_protobuf_extensions/pbutil | Apache-2.0 | +| github.com/mitchellh/mapstructure v1.5.0 (indirect) | MIT | +| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd (indirect) | Apache-2.0 | +| github.com/modern-go/reflect2 v1.0.2 (indirect) | Apache-2.0 | +| github.com/pkg/errors v0.9.1 | BSD-2-Clause | +| github.com/prometheus/client_golang/prometheus | Apache-2.0 | +| github.com/prometheus/client_model/go | Apache-2.0 | +| github.com/prometheus/common v0.44.0 (indirect) | Apache-2.0 | +| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | BSD-3-Clause | +| github.com/prometheus/procfs v0.12.0 (indirect) | Apache-2.0 | +| github.com/spf13/cast v1.5.1 | MIT | +| github.com/swaggo/files v1.0.1 (indirect) | MIT | +| github.com/swaggo/http-swagger v1.3.4 | MIT | +| github.com/swaggo/swag v1.16.2 | MIT | +| go.uber.org/multierr v1.11.0 (indirect) | MIT | +| go.uber.org/zap v1.26.0 (indirect) | MIT | +| golang.org/x/crypto/pbkdf2 | BSD-3-Clause | +| golang.org/x/net/webdav | BSD-3-Clause | +| golang.org/x/sync/singleflight | BSD-3-Clause | +| golang.org/x/sys v0.12.0 (indirect) | BSD-3-Clause | +| golang.org/x/text v0.13.0 (indirect) | BSD-3-Clause | +| golang.org/x/tools v0.13.0 (indirect) | BSD-3-Clause | +| google.golang.org/protobuf v1.31.0 (indirect) | BSD-3-Clause | +| gopkg.in/yaml.v3 v3.0.1 (indirect) | MIT | +| gorm.io/driver/postgres v1.5.2 | MIT | +| gorm.io/gorm v1.25.4 | MIT | \ No newline at end of file

)HZ((*}`6*%(4 zL{*8N(ht^i9MKIlV26}VQmUv#^>wqd(SbdvDT+m8B*!}PX+RAr(x*kH=j*r3$8cbt z6NJoStHwm>z&mSg0s@JOMo7S3ql&7W*jpfR zLW;0ei7l;rFkti7GU8yMm+~sU)z3qs#JrDxw(=Mb;Z!(Jde|%>7(EDAVnUfDgNqEOxaHx$5_=3rL(oc0C((@V_< zW_Xa1F<#tTuJ}e)R>N_ri=gDF&0NGw!b?p%Elx%}xS{%cLRHUwf>ODZr?S`_It%3!>r9cnWbq5TsAuIf{Jp`~i1L?GkjL(4tZnc*a;bAc2; z_J%t(L|d2$oOkB$uC21+PCpWDBzsIXb{y{_7)CEO(5@M37PN$dDJch0SO?NQSZ$&M zkgo7nkgjOAGBC;Zb(AfCLAKR>s-9KRO_oj&ka`93jqlv@U;56Bv)Q^jUs z{;9Ag?h}%dlEn%`&QxUoxOEunk)kMqN~q%!l#9Entbz}@^f2;rlG+M!-QSy5IZV15 zFQ&vaG}s|1FEbSxFMg;Zs~#9SO4}D5p&`-vcSR+-O>j9h!(3Um zfzkd1LJPt|BtVvtHB@jcL-_;~5k8Wdl;viVI(1jn$p)lW*2)U|)}SBv1dRM{;GrMM zQ)-HKqnNj>R=bm&$O$Dbgk{F+@KT6}ET6tm;O=4p67{K5V@l@t2r+@i2+ z_sq3NEFp#$4Pt(TX~|((xuMp#&7cC8;H)%Bipwrt^0QxYfB*});!MJw-E0r+Y_0t2 z6S1ZI){b~n&7gIki@D*3g}p>oz8R_%H}TW6br0)#_oB_J{Eqc6)T+(>G4U--U95h? zifw^8X>6ZE2CTxbk4I%3;!`px1eZe&C^SHhk4xQGI2xYVn|qgiu0BKBwsBU!HmMSv zWgyINdxEJFm$Xk*Wi56tjG6ct&umotYcfuOUbsdVl)bE?b*3Pv?_p0dkX$wg)=X(I zC-!wU1fHM|b6zmk1u4Bh7@E+Abq%gjhVF>o922#35QSc91jn{o1ifz3Rd~$tn#e7g z)x+hZMFbL!jNRKOYZqO9vpS$&to_e^ka(kz2yNVz1d_qyl&fOirq{o*EXk(@)BKhk zF|O5z(PCOevAvfZgmpi}OGg`{La@L62=t;S%{4`s{Cl4E;J+wa7@jDvS-ovb8{U6< zuGAS>!g7sY(#~F+aL@Nd@k|07L3cW@N)n1S3;rnAm+baLbW?jiwLYwK3fBWco$5h6 z6AGc|<-wdL1yWyCgTl-c{fZD-Xp5>8er|0uWjrDQds)~`{b?9B@0;jq1m8^SC3msn zWOGp< znp(SjtNqYf8JK?S?>hZQLyE@nzkrCw$lBr`U)tN*&;o3%msJ(4Ht7+3W@{k~Y7@4Y z=^=6ql6X-TY~(RKsUo}_lGYO9jkydid*xCt*Jv$HqMf(z54QevcFOH$lLWUXaOs6naBVY5^ro zB_ama3!E$mGAKaqrB`SeyEzDxnkrf=3iifLSlQe!WAqYAub<)BzNEO16of*miRL8C zC;LqCMXXKu{iLk_R?AMjzT$NBnDO!ONU|4mENwoPxWX> z%3WS;iMz5G5J9>ss~EPLmMEQ=r0C|w!xMrd1nYn0ze{|774~;!ta7f7s98%-=jfG{ z6XateKhoacH58H}5sSO4Q#Aq3u#ZTs>?OlYs-k2ZE6AnbfWqsY@C zXw&#hS7b3WzX@^WjK!3Q_rg}b9;l$kEWzIn51zV81YkuBgCdCLdeYmUlr550?2{0f zWZ1L|d`DN$>ky*Q>zx~aj<~(g4I2=FTpXJVA$}Z8!&WKOTEYV2H z%u>@*R4mENj7v{b?Mu>4(9!&$oS0gbnwgcFqyU9XDMmvz`+c&Wae;Y;>G<=Tg!U5% z1^8QC3j*T*)OIe=QB-FfA2@*JEurB}EwTuKHjsc4Krs&!NJ3)B=0ynTl1v`3?vmXE zL}+n&G#n_9@=^o=>7uqk%OhA$4gvyNtiiTY2m#7NK}0GXK;#q<`oB9nJ9}sD%-zzi+;KXD$~3ffrux*JmySt-)XXukUiZ$WNd683~!GDaq!X=!_Jh z1q?vExJFv=-GU$ZX0Z2qock_eCw}`{@V~9S?6wH;E{@!G%KtVe@4%Pjc;{gM`#Z?) z#}N|Vi`@ScRFf*~nl~V)^}8WTxIvmav{;?RJ3X@I$Zz$`I-2Y!sRkCZ8xW=~an{mo zuRqn^$3eAcnc>hjP&CzO8%(*dsAM2POPP=so6TP3*(aghTTxWoc|o=9owl_)h8Fp4 zJXcJV0SgE;ugYG|ZQBfC0; zi>S0-H;p{$X%j|>0FOS`brbkki}~qf+l@9Rmck@s(@M~0bMnR24lKQDb_-d`6)s|^ z)giS%#p0|ewp3S@Ym&&j1`_E;Xe8d^;2i-`14NRiZ_=>eHn7nG_xK>H)!Lw1^;Hf0 z$F@AKpyutpNFOwzVP9MkGC!@Gdx`gYbZv#2hU{i4ZPaRs_UQNkEomm80!E0#Bpf!L z8JR;~+A74~X+D8D&h2``AL9#${xU~BSJJBMB^&V6Tw(%)|uTh+yL2h)yKG0*gh$|J`NpH}8unr4m`l zGn82Q_@BVeY-Vg0_g9@T&VPT!v>S{vC_0j2eBL$~2DQCo96y7%3hPyJPVK={Q^^F} z6_UR|ahl-xfpzgj^8|!+K`B$Jr%S75Wmzh`D`awF@v1xVn=!vEKpK}s5gU=;=pY8G zV(!u2$B)2+s-WhJ6!3I6T|hy_ToQatW;>E&TUn;Pgipc#f4f*`lxzEowL5Rwq3sT& zr_WRHwmn0Diz9{InYT(F|Ew2=>?_DIlPOr^6S`oOX{pUYa{c1(EbVd%#=Q;Wj-ilw zPZ>svFUZTG%k$@U?utaH6i{hiBoo$31Q#7HYi$uC7Wqd@X-~TcM7TZ6rWcFE7^CX(f6n2S83e_it0P!fq zCbf2@MZEyG=neCsY2W2`tt$G?9gJTxGi zQ}JDc(+ox##x(5{2N9tH`vhxbsk!;3<;^;`8OU*WTpX9`Ga>N_yEPb=H$hLbAl`U) zM~jOhNkV`wwpyG{x!WHdTl25}2s^Vo$*~vK=)j8ICal5;z$8@2D$3ZF-5;^7VH%>4 z8xBgljBSHKEE|~KqT{p)7~01%W9Cuj9r>OPpt^ZY-lK>TY$d5BY#G+XtzO>*clri0 zNGUk!;>Wh?kU_9@247{t%K{cQszc+VrRSlp4K^m3o_M)kqyD4=6_mPyJZw2yeZ^mF zgV<1uiGYq6D|YFSL%GnW<t^Hm)-05UOff^* zO72^8K6)0Wi2WExz^-xK%hE`1;X@<7H zfwl=E8vnXoe>|_3?yv3BY-RUsOL-ItWv9Zk=#g7=Q7_I{NYI)phV{u=d;|KC^IK`_ zesMWupy0DPv!?Sv&p_={&AQ!+9v=7>kAY)5aNIb`x`V$lNDmO?X4dwbPzghCL^4@K zk>_6zne40B2(f{8h!eMSI?5j^;kNrpd(mw8b`#2{6Ddh-x5F=qr=-O8y>Ay>*gFj- z`3p>vPYE*RzHvb^FvfDHV@~C>g}N472>bD!H=^JXckyWUG9^SJ*DQ#nz#FJlDrw4; z0b^35ZytWMWX|g_Nq0P8O`xQ?+ACekUJcEfudM(Amp{HX(~4_$J9mxo42byo1yze-^hWq0J>`BC88Vi* zA6v`RhG}m-1yo~K`IOtxBV?Rb)IN9f(X5Sd@wRxhOsAa6YziGH9Mzb|JDe!BvNbKV z)n$H&{wzd)7Es`c149RUDllR)OoBP@(3IlR@G?^z)SrtHPS5$vqC=O$!%ebQI}vNt zGQ{W>P3031>&g|G%aCDu$^NlCW(3>bt*-oMZ$5auB6qm@v=QDjY+Tk4m9t&~?oEYy z8;2Xg#i;OhtZ0hL1#gLhH+h5+UTiE|zk+9SYO=t4U1847qYUxbxWaE*M~(-MtZXGx zqvg=EMsP84Y~F(VaRVlS_lAP!9BqUbtCClb-T3pu8nDh{s+AT;NM<`EUN6r(;GJyE zZhSl_pRBM>1ucQHWTzy(B>!Plu=^D8%TfjI2k9rUgg;JYl<(MEUpEFe zY>8Qw*6!65y*OcQCf8vlr#!Q@dvNM}<%`g6p2AIjmaZ4)uU(AF6N#hu=Er#OHY#|> z#u?%bW9xS&^5#g=du0mVicCX1m1^NnFQ3?22;K^Xw~WDL6S}vksF!j4NI^adt=o^u zi`ZPY0UX^|i!z)+$C~>1HE572J)Ik4?mNl$mZ{w;`O$Nc{5N_Lbj* z7mGOfGS!_;TXgWmMef1UMhnD3jpbx^=k_{zwzxeU>swS+N+@a4-!~?WhA5g#mv!qe zlx)W{&*gR;XQ3oIz15gRW{Xq5fvUSDO}PazNP0Vo5~tNJW8!ESh}~C*5@uZMfWE3i zd4sOQId>ZqB^P@cQf;Mn<=zOkB#U;By_E<__CS)CDWlx~AS6kA8#M--$$q-x9Q!oh z7OXV)4tL4D2`R|)<4cq@ILkEnv_u+Fk~CV|M%bpw-P7X&8Bh-}ps>{7yWFm*eg8*c zG>24+>s#wGQ9)VNTV6$}KM;ycW~bH5GiC9wn6V8(rCyX*Uv`lUo|)(wx?)~=%pln8 z-N>dv=g#)t{Rz6F27%gt&#v3`&(96gQ!1=H#xGx@t^ekalHwXLmzfpyo7Tq-N&v9u z`%@}wF=zig>FaVlWzE5A>Uf_Mk|);Zn+%eDx@(xey#2&4&R{3c=>hVBK$kC#;n}0E zzV_JxA3#miT4ifN<8SHU38hHy6M70?g?gQeeJkJEbh81z6#?I(clVUv4hASZy{exj zZo?~tzAur>m&z}-Y&WC`+0hcrF?8p?b2l7t??L8j&n|zPw`=4b;A=7a)3s6Sy)fYO zu|Jj1DRW#uql0_%64r@y9Sofv;L)+lLDK?!ix!6VUUy z*l3yNBa_i}kZT@9#0k**E%4w`(PbXf&rB?~(bG@a6Jg+sj==Up?z78R zkKpMg4H>$b^8OKh!vH6y*Vg`rmN=>z)}IOMXHWvz282NXj|ZyMXHULcoYtZX$Mucl zxD*OKV~}w)+ukMbzI~Le@wP!Qr5C}@B^YO#h`Y1F*XtiXDu9<=L!6=0x6zql00$Uj z&s}q+cS0|Bg{zIFOx+?o40M%pz|Ft*w~`GWpJ1B>y^K9OCk)igYO7ToU0HT(g<6D} zf9>2+c8EV%5C$ + + + Syntio + + 2017 + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.4 + + + + org.example + Compatibility + 1.0-SNAPSHOT + + + 11 + 11 + 3.0.2 + 6.0.4 + 10.1.5 + + + + + io.confluent + io.confluent + https://packages.confluent.io/maven + + + io.apicurio + io.apicurio + https://repo1.maven.org/maven2 + + + central + Maven Central Repository + http://repo1.maven.org/maven2 + + + + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-websocket + ${tomcat.version} + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat.version} + + + + com.fasterxml.jackson.core + jackson-core + 2.13.4 + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.4 + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.1 + + + com.google.protobuf + protobuf-java + 3.21.9 + + + + org.springframework + spring-beans + ${springframework.version} + + + org.springframework + spring-core + ${springframework.version} + + + org.springframework + spring-webmvc + ${springframework.version} + + + org.springframework + spring-web + ${springframework.version} + + + org.springframework + spring-aop + ${springframework.version} + + + org.springframework + spring-context + ${springframework.version} + + + org.springframework + spring-expression + ${springframework.version} + + + org.springframework + spring-jcl + ${springframework.version} + + + org.springframework + spring-test + ${springframework.version} + + + + + org.springframework.boot + spring-boot-starter-test + test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-web + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-tomcat + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-validation + ${springframework.boot.version} + + + org.springframework.boot + spring-boot + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-json + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-starter-logging + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test + ${springframework.boot.version} + + + org.springframework.boot + spring-boot-test-autoconfigure + ${springframework.boot.version} + + + + org.yaml + snakeyaml + 2.0 + + + org.projectlombok + lombok + 1.18.22 + + + + io.apicurio + apicurio-registry-schema-util-common + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-json + 2.3.1.Final + + + io.apicurio + apicurio-registry-schema-util-protobuf + 2.3.1.Final + + + io.confluent + kafka-schema-registry-client + 7.2.1 + + + org.json + json + 20230227 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 14 + 14 + + + + compatibility-checker + + diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CheckerFactory.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CheckerFactory.java new file mode 100644 index 0000000..1303bfc --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CheckerFactory.java @@ -0,0 +1,17 @@ +package net.syntio.compatibility; + +import net.syntio.compatibility.checker.AvroChecker; +import net.syntio.compatibility.checker.CompatibilityChecker; +import net.syntio.compatibility.checker.JsonChecker; +import net.syntio.compatibility.checker.ProtobufChecker; + +public class CheckerFactory { + public static CompatibilityChecker createChecker(String format) throws Exception { + return switch (format) { + case FileTypes.JSON -> new JsonChecker(); + case FileTypes.PROTOBUF -> new ProtobufChecker(); + case FileTypes.AVRO -> new AvroChecker(); + default -> throw new Exception("Unknown format"); + }; + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CompatibilityCheckerApplication.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CompatibilityCheckerApplication.java new file mode 100644 index 0000000..2b8a20d --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/CompatibilityCheckerApplication.java @@ -0,0 +1,15 @@ +package net.syntio.compatibility; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.util.Collections; + +@SpringBootApplication +public class CompatibilityCheckerApplication { + public static void main(String[] args) { + SpringApplication app = new SpringApplication(CompatibilityCheckerApplication.class); + app.setDefaultProperties(Collections.singletonMap("server.port", "8088")); + app.run(args); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/FileTypes.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/FileTypes.java new file mode 100644 index 0000000..ade6de8 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/FileTypes.java @@ -0,0 +1,7 @@ +package net.syntio.compatibility; + +public class FileTypes { + public static final String JSON = "json"; + public static final String AVRO = "avro"; + public static final String PROTOBUF = "protobuf"; +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/Message.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/Message.java new file mode 100644 index 0000000..a3831f0 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/Message.java @@ -0,0 +1,26 @@ +package net.syntio.compatibility; + +public class Message { + private final String id; + private final String format; + private final String schema; + + public Message(String id, String format, String schema) { + this.id = id; + this.format = format; + this.schema = schema; + } + + + public String getSchema() { + return schema; + } + + public String getID() { + return id; + } + + public String getFormat() { + return format; + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/AvroChecker.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/AvroChecker.java new file mode 100644 index 0000000..4310dc9 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/AvroChecker.java @@ -0,0 +1,40 @@ +package net.syntio.compatibility.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; +import io.confluent.kafka.schemaregistry.avro.AvroSchema; +import io.confluent.kafka.schemaregistry.CompatibilityChecker; + +import java.util.ArrayList; +import java.util.List; + +public class AvroChecker implements net.syntio.compatibility.checker.CompatibilityChecker { + @Override + public boolean testCompatibility(CompatibilityLevel level, List history, ContentHandle currentSchema) { + io.confluent.kafka.schemaregistry.CompatibilityLevel avroCompatibilityLevel = switch (level) { + case NONE -> io.confluent.kafka.schemaregistry.CompatibilityLevel.NONE; + case BACKWARD -> io.confluent.kafka.schemaregistry.CompatibilityLevel.BACKWARD; + case BACKWARD_TRANSITIVE -> io.confluent.kafka.schemaregistry.CompatibilityLevel.BACKWARD_TRANSITIVE; + case FORWARD -> io.confluent.kafka.schemaregistry.CompatibilityLevel.FORWARD; + case FORWARD_TRANSITIVE -> io.confluent.kafka.schemaregistry.CompatibilityLevel.FORWARD_TRANSITIVE; + case FULL -> io.confluent.kafka.schemaregistry.CompatibilityLevel.FULL; + case FULL_TRANSITIVE -> io.confluent.kafka.schemaregistry.CompatibilityLevel.FULL_TRANSITIVE; + }; + List newHistory = new ArrayList<>(); + for (ContentHandle existingArtifact : history) { + newHistory.add(new AvroSchema(existingArtifact.content())); + } + AvroSchema newSchema = new AvroSchema(currentSchema.content()); + + List issues = switch (avroCompatibilityLevel) { + case BACKWARD -> CompatibilityChecker.BACKWARD_CHECKER.isCompatible(newSchema, newHistory); + case BACKWARD_TRANSITIVE -> CompatibilityChecker.BACKWARD_TRANSITIVE_CHECKER.isCompatible(newSchema, newHistory); + case FORWARD -> CompatibilityChecker.FORWARD_CHECKER.isCompatible(newSchema, newHistory); + case FORWARD_TRANSITIVE -> CompatibilityChecker.FORWARD_TRANSITIVE_CHECKER.isCompatible(newSchema, newHistory); + case FULL -> CompatibilityChecker.FULL_CHECKER.isCompatible(newSchema, newHistory); + case FULL_TRANSITIVE -> CompatibilityChecker.FULL_TRANSITIVE_CHECKER.isCompatible(newSchema, newHistory); + case NONE -> CompatibilityChecker.NO_OP_CHECKER.isCompatible(newSchema, newHistory); + }; + return issues.isEmpty(); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/Checker.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/Checker.java new file mode 100644 index 0000000..b549a4e --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/Checker.java @@ -0,0 +1,24 @@ +package net.syntio.compatibility.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; +import net.syntio.compatibility.Message; +import net.syntio.compatibility.CheckerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class Checker { + public static boolean checkCompatibility(Message msg, List history, CompatibilityLevel mode) throws Exception { + ContentHandle schema = ContentHandle.create(msg.getSchema()); + List schemaHistory = new ArrayList<>(); + + for (String s : history) { + ContentHandle ps = ContentHandle.create(s); + schemaHistory.add(ps); + } + CompatibilityChecker cc = CheckerFactory.createChecker(msg.getFormat()); + + return cc.testCompatibility(mode, schemaHistory, schema); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/CompatibilityChecker.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/CompatibilityChecker.java new file mode 100644 index 0000000..3b423d9 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/CompatibilityChecker.java @@ -0,0 +1,10 @@ +package net.syntio.compatibility.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; + +import java.util.List; + +public interface CompatibilityChecker { + boolean testCompatibility(CompatibilityLevel level, List history, ContentHandle currentSchema); +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/JsonChecker.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/JsonChecker.java new file mode 100644 index 0000000..d482e6d --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/JsonChecker.java @@ -0,0 +1,15 @@ +package net.syntio.compatibility.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; +import io.apicurio.registry.rules.compatibility.JsonSchemaCompatibilityChecker; + +import java.util.List; + +public class JsonChecker implements CompatibilityChecker { + @Override + public boolean testCompatibility(CompatibilityLevel level, List history, ContentHandle currentSchema) { + JsonSchemaCompatibilityChecker cc = new JsonSchemaCompatibilityChecker(); + return cc.testCompatibility(level, history, currentSchema).isCompatible(); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/ProtobufChecker.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/ProtobufChecker.java new file mode 100644 index 0000000..e162c32 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/checker/ProtobufChecker.java @@ -0,0 +1,15 @@ +package net.syntio.compatibility.checker; + +import io.apicurio.registry.content.ContentHandle; +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; +import io.apicurio.registry.rules.compatibility.ProtobufCompatibilityChecker; + +import java.util.List; + +public class ProtobufChecker implements CompatibilityChecker { + @Override + public boolean testCompatibility(CompatibilityLevel level, List history, ContentHandle currentSchema) { + ProtobufCompatibilityChecker cc = new ProtobufCompatibilityChecker(); + return cc.testCompatibility(level, history, currentSchema).isCompatible(); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/controller/CheckerController.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/controller/CheckerController.java new file mode 100644 index 0000000..2c9ca26 --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/controller/CheckerController.java @@ -0,0 +1,69 @@ +package net.syntio.compatibility.controller; + +import io.apicurio.registry.rules.compatibility.CompatibilityLevel; +import net.syntio.compatibility.Message; +import net.syntio.compatibility.checker.Checker; +import net.syntio.compatibility.dto.CheckRequestDto; +import net.syntio.compatibility.dto.CheckResponseDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class CheckerController { + @PostMapping(value = "/") + public ResponseEntity check(@RequestBody CheckRequestDto req) { + Message latestSchema = req.getMessage(); + List schemaHistory = req.getHistory(); + try { + for (int i = 0; i < schemaHistory.size(); i++) { + schemaHistory.set(i, schemaHistory.get(i).replaceAll("\r\n", "\n")); + } + String mode = req.getMode(); + + CompatibilityLevel cl = getCompatibilityLevel(mode); + boolean result; + if (cl.equals(CompatibilityLevel.NONE)) { + result = true; + } else { + result = Checker.checkCompatibility(latestSchema, schemaHistory, cl); + } + + CheckResponseDto res = new CheckResponseDto(result); + if (result) { + res.setInfo("Schema is compatible"); + return ResponseEntity.ok(res); + } + res.setInfo("Schema is incompatible"); + return ResponseEntity.ok(res); + } catch (NullPointerException e) { + System.err.println("Schema history is null."); + return ResponseEntity.badRequest().build(); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + } + + @GetMapping(value = "/health") + public ResponseEntity healthCheck() { + return ResponseEntity.ok().build(); + } + + private CompatibilityLevel getCompatibilityLevel(String mode) throws Exception { + return switch (mode.toUpperCase()) { + case "BACKWARD" -> CompatibilityLevel.BACKWARD; + case "BACKWARD_TRANSITIVE" -> CompatibilityLevel.BACKWARD_TRANSITIVE; + case "FORWARD" -> CompatibilityLevel.FORWARD; + case "FORWARD_TRANSITIVE" -> CompatibilityLevel.FORWARD_TRANSITIVE; + case "FULL" -> CompatibilityLevel.FULL; + case "FULL_TRANSITIVE" -> CompatibilityLevel.FULL_TRANSITIVE; + case "NONE", "" -> CompatibilityLevel.NONE; + default -> throw new Exception("Unknown compatibility mode"); + }; + } + +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckRequestDto.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckRequestDto.java new file mode 100644 index 0000000..353751d --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckRequestDto.java @@ -0,0 +1,48 @@ +package net.syntio.compatibility.dto; + +import net.syntio.compatibility.Message; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; + +public class CheckRequestDto { + private Message message; + private final List history; + private final String mode; + + public CheckRequestDto(String payload, List history, String mode) { + try { + this.message = transformStringToMessage(payload); + } catch (Exception e) { + this.message = new Message("", "", ""); + System.err.println("Cannot read message"); + } + this.history = history; + this.mode = mode; + } + + public Message getMessage() { + return message; + } + + public String getSchema() { + return message.getSchema(); + } + + public List getHistory() { + return history; + } + + public String getMode() { + return mode; + } + + private static Message transformStringToMessage(String payload) throws JSONException { + JSONObject jsonObject = new JSONObject(payload); + String id = jsonObject.getString("id"); + String format = jsonObject.getString("format"); + String newSchema = jsonObject.getString("schema"); + return new Message(id, format, newSchema); + } +} diff --git a/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckResponseDto.java b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckResponseDto.java new file mode 100644 index 0000000..02440fd --- /dev/null +++ b/registry/compatibility/external/compatibility-checker/src/main/java/net/syntio/compatibility/dto/CheckResponseDto.java @@ -0,0 +1,22 @@ +package net.syntio.compatibility.dto; + +public class CheckResponseDto { + private final boolean result; + private String info; + + public CheckResponseDto(boolean result) { + this.result = result; + } + + public boolean getResult() { + return result; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/registry/compatibility/externalChecker.go b/registry/compatibility/externalChecker.go new file mode 100644 index 0000000..aa72cf0 --- /dev/null +++ b/registry/compatibility/externalChecker.go @@ -0,0 +1,131 @@ +package compatibility + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility/http" + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" + "github.com/dataphos/lib-httputil/pkg/httputil" + "github.com/dataphos/lib-retry/pkg/retry" +) + +const ( + urlEnvKey = "COMPATIBILITY_CHECKER_URL" + timeoutEnvKey = "COMPATIBILITY_CHECKER_TIMEOUT_BASE" + globalCompatibilityMode = "GLOBAL_COMPATIBILITY_MODE" +) + +const ( + DefaultTimeoutBase = 2 * time.Second + defaultGlobalCompatibilityMode = "BACKWARD" +) + +type ExternalChecker struct { + url string + TimeoutBase time.Duration +} + +// NewFromEnv loads the needed environment variables and calls New. +func NewFromEnv(ctx context.Context) (*ExternalChecker, error) { + url := os.Getenv(urlEnvKey) + if url == "" { + return nil, errtemplates.EnvVariableNotDefined(urlEnvKey) + } + + timeout := DefaultTimeoutBase + if timeoutStr := os.Getenv(timeoutEnvKey); timeoutStr != "" { + var err error + timeout, err = time.ParseDuration(timeoutStr) + if err != nil { + return nil, errors.Wrap(err, errtemplates.ParsingEnvVariableFailed(timeoutEnvKey)) + } + } + + return New(ctx, url, timeout) +} + +// New returns a new instance of Repository. +func New(ctx context.Context, url string, timeoutBase time.Duration) (*ExternalChecker, error) { + if err := retry.Do(ctx, retry.WithJitter(retry.Constant(2*time.Second)), func(ctx context.Context) error { + return httputil.HealthCheck(ctx, url+"/health") + }); err != nil { + return nil, errors.Wrapf(err, "attempting to reach compatibility checker at %s failed", url) + } + + return &ExternalChecker{ + url: url, + TimeoutBase: timeoutBase, + }, nil +} + +func (c *ExternalChecker) Check(schemaInfo string, history []string, mode string) (bool, error) { + //check if compatibility mode is none, if it is, don't send HTTP request to java code + if strings.ToLower(mode) == "none" { + return true, nil + } + size := calculateSizeInBytes(schemaInfo, history, mode) + ctx, cancel := context.WithTimeout(context.Background(), http.EstimateHTTPTimeout(size, c.TimeoutBase)) + defer cancel() + + decodedHistory, err := c.DecodeHistory(history) + if err != nil { + return false, err + } + return http.CheckOverHTTP(ctx, schemaInfo, decodedHistory, mode, c.url+"/") +} + +func (c *ExternalChecker) DecodeHistory(history []string) ([]string, error) { + var decodedHistory []string + for i := 0; i < len(history); i++ { + decoded, err := base64.StdEncoding.DecodeString(history[i]) + if err != nil { + fmt.Println(fmt.Errorf("could not decode").Error()) + return nil, err + } + decodedHistory = append(decodedHistory, string(decoded)) + } + return decodedHistory, nil +} + +func calculateSizeInBytes(schema string, history []string, mode string) int { + bytes := []byte(schema + mode) + for i := 0; i < len(history); i++ { + bytes = append(bytes, []byte(history[i])...) + } + return len(bytes) +} + +func InitCompatibilityChecker(ctx context.Context) (*ExternalChecker, string, error) { + compChecker, err := NewFromEnv(ctx) + if err != nil { + return nil, "", err + } + globalCompMode := os.Getenv(globalCompatibilityMode) + if globalCompMode == "" { + globalCompMode = defaultGlobalCompatibilityMode + } + if globalCompMode == "BACKWARD" || globalCompMode == "BACKWARD_TRANSITIVE" || + globalCompMode == "FORWARD" || globalCompMode == "FORWARD_TRANSITIVE" || + globalCompMode == "FULL" || globalCompMode == "FULL_TRANSITIVE" || globalCompMode == "NONE" { + return compChecker, globalCompMode, nil + } + return nil, "", errors.Errorf("unsupported compatibility mode") +} + +func CheckIfValidMode(mode *string) bool { + if *mode == "" { + *mode = defaultGlobalCompatibilityMode + } + lowerMode := strings.ToLower(*mode) + if lowerMode != "none" && lowerMode != "backward" && lowerMode != "backward_transitive" && lowerMode != "forward" && lowerMode != "forward_transitive" && lowerMode != "full" && lowerMode != "full_transitive" { + return false + } + return true +} diff --git a/registry/compatibility/http/http.go b/registry/compatibility/http/http.go new file mode 100644 index 0000000..a2fc3e1 --- /dev/null +++ b/registry/compatibility/http/http.go @@ -0,0 +1,92 @@ +package http + +import ( + "bytes" + "context" + "encoding/json" + "github.com/dataphos/lib-httputil/pkg/httputil" + "io" + "math" + "net/http" + "time" + + "github.com/pkg/errors" +) + +// checkRequest contains a new schema, list of old schemas and a compatibility mode which should be enforced. The structure represents an HTTP +// request body. +type checkRequest struct { + Payload string `json:"payload"` + History []string `json:"history"` + Mode string `json:"mode"` +} + +// checkResponse contains the compatibility result and an info message. The structure represents an HTTP response body. +type checkResponse struct { + Result bool `json:"result"` + Info string `json:"info"` +} + +// HTTPTimeoutBytesUnit the base amount of bytes used by EstimateHTTPTimeout. +const HTTPTimeoutBytesUnit = 1024 * 100 + +// EstimateHTTPTimeout calculates the expected timeout, by dividing the size given in bytes with HTTPTimeoutBytesUnit, and then +// multiplying the coefficient with the given time duration. +// +// If the given size is less than HTTPTimeoutBytesUnit, base is returned, to avoid problems due to the http overhead which isn't fully linear. +func EstimateHTTPTimeout(size int, base time.Duration) time.Duration { + coef := int(math.Round(float64(size) / float64(HTTPTimeoutBytesUnit))) + if coef <= 1 { + return base + } + + return time.Duration(coef) * base +} + +// CheckOverHTTP requests a schema check over HTTP. +// Function returns false if schema isn't compatible. +func CheckOverHTTP(ctx context.Context, schema string, history []string, mode, url string) (bool, error) { + response, err := sendCheckRequest(ctx, schema, history, mode, url) + if err != nil { + return false, err + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + panic(errors.New("couldn't close response body")) + } + }(response.Body) + + body, err := io.ReadAll(response.Body) + if err != nil { + return false, err + } + + var parsedBody checkResponse + if err = json.Unmarshal(body, &parsedBody); err != nil { + return false, err + } + + compatible := parsedBody.Result + + switch response.StatusCode { + case http.StatusOK: + return compatible, nil + case http.StatusBadRequest: + return compatible, nil + default: + return compatible, errors.Errorf("error: status code [%v]", response.StatusCode) + } +} + +func sendCheckRequest(ctx context.Context, payload string, history []string, mode, url string) (*http.Response, error) { + // this can't generate an error, so it's safe to ignore + data, _ := json.Marshal(checkRequest{Payload: payload, History: history, Mode: mode}) + + request, err := httputil.Post(ctx, url, "application/json", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + return http.DefaultClient.Do(request) +} diff --git a/registry/compatibility/testdata/backward_avro_false/schema1.json b/registry/compatibility/testdata/backward_avro_false/schema1.json new file mode 100644 index 0000000..ba32aa8 --- /dev/null +++ b/registry/compatibility/testdata/backward_avro_false/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "avro", + "schema": "{\r\n \"namespace\": \"example.avro\",\r\n \"type\": \"record\",\r\n \"name\": \"user\",\r\n \"fields\": [\r\n {\"name\": \"name\", \"type\": \"string\"},\r\n {\"name\": \"favorite_animal\", \"type\": \"string\"},\r\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\r\n ]\r\n}" +} diff --git a/registry/compatibility/testdata/backward_avro_false/schema2.json b/registry/compatibility/testdata/backward_avro_false/schema2.json new file mode 100644 index 0000000..f35e735 --- /dev/null +++ b/registry/compatibility/testdata/backward_avro_false/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "avro", + "schema": "{\r\n \"namespace\": \"example.avro\",\r\n \"type\": \"record\",\r\n \"name\": \"user\",\r\n \"fields\": [\r\n {\"name\": \"name\", \"type\": \"string\"},\r\n {\"name\": \"favorite_number\", \"type\": \"int\"},\r\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\r\n ]\r\n}" +} diff --git a/registry/compatibility/testdata/backward_avro_true/schema1.json b/registry/compatibility/testdata/backward_avro_true/schema1.json new file mode 100644 index 0000000..f0502c3 --- /dev/null +++ b/registry/compatibility/testdata/backward_avro_true/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "avro", + "schema": "{\r\n \"namespace\": \"example.avro\",\r\n \"type\": \"record\",\r\n \"name\": \"user\",\r\n \"fields\": [\r\n {\"name\": \"name\", \"type\": \"string\"},\r\n {\"name\": \"favorite_number\", \"type\": \"int\"},\r\n {\"name\": \"favorite_animal\", \"type\": \"string\"},\r\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\r\n ]\r\n}" +} diff --git a/registry/compatibility/testdata/backward_avro_true/schema2.json b/registry/compatibility/testdata/backward_avro_true/schema2.json new file mode 100644 index 0000000..f35e735 --- /dev/null +++ b/registry/compatibility/testdata/backward_avro_true/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "avro", + "schema": "{\r\n \"namespace\": \"example.avro\",\r\n \"type\": \"record\",\r\n \"name\": \"user\",\r\n \"fields\": [\r\n {\"name\": \"name\", \"type\": \"string\"},\r\n {\"name\": \"favorite_number\", \"type\": \"int\"},\r\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\r\n ]\r\n}" +} diff --git a/registry/compatibility/testdata/backward_json_false/schema1.json b/registry/compatibility/testdata/backward_json_false/schema1.json new file mode 100644 index 0000000..d8298d9 --- /dev/null +++ b/registry/compatibility/testdata/backward_json_false/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "json", + "schema": "{\r\n \"$id\": \"https:\/\/example.com\/person.schema.json\",\r\n \"$schema\": \"https:\/\/json-schema.org\/draft-07\/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n },\r\n \"additionalProperties\": true\r\n}" +} diff --git a/registry/compatibility/testdata/backward_json_false/schema2.json b/registry/compatibility/testdata/backward_json_false/schema2.json new file mode 100644 index 0000000..94d24a8 --- /dev/null +++ b/registry/compatibility/testdata/backward_json_false/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "json", + "schema": "{\r\n \"$id\": \"https:\/\/example.com\/person.schema.json\",\r\n \"$schema\": \"https:\/\/json-schema.org\/draft-07\/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n },\r\n \"phoneNumber\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's phone number.\"\r\n }\r\n },\r\n \"additionalProperties\": true\r\n}" +} diff --git a/registry/compatibility/testdata/backward_json_true/schema1.json b/registry/compatibility/testdata/backward_json_true/schema1.json new file mode 100644 index 0000000..0d4f3bb --- /dev/null +++ b/registry/compatibility/testdata/backward_json_true/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "json", + "schema": "{\n \"$id\": \"https://example.com/person.schema.json\",\n \"$schema\": \"https://json-schema.org/draft-07/schema\",\n \"title\": \"Person\",\n \"type\": \"object\",\n \"properties\": {\n \"firstName\": {\n \"type\": \"string\",\n \"description\": \"The person's first name.\"\n },\n \"lastName\": {\n \"type\": \"string\",\n \"description\": \"The person's last name.\"\n },\n \"age\": {\n \"description\": \"Age in years which must be equal to or greater than zero.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"phoneNumber\": {\n \"type\": \"string\",\n \"description\": \"The person's phone number.\"\n }\n },\n \"additionalProperties\": true\n}" +} diff --git a/registry/compatibility/testdata/backward_json_true/schema2.json b/registry/compatibility/testdata/backward_json_true/schema2.json new file mode 100644 index 0000000..19c6606 --- /dev/null +++ b/registry/compatibility/testdata/backward_json_true/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "json", + "schema": "{\r\n \"$id\": \"https:\/\/example.com\/person.schema.json\",\r\n \"$schema\": \"https:\/\/json-schema.org\/draft-07\/schema\",\r\n \"title\": \"Person\",\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"firstName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's first name.\"\r\n },\r\n \"lastName\": {\r\n \"type\": \"string\",\r\n \"description\": \"The person's last name.\"\r\n },\r\n \"age\": {\r\n \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n \"type\": \"integer\",\r\n \"minimum\": 0\r\n }\r\n },\r\n \"additionalProperties\": true\r\n}" +} diff --git a/registry/compatibility/testdata/compatible_avro_back1.json b/registry/compatibility/testdata/compatible_avro_back1.json new file mode 100644 index 0000000..9a214ec --- /dev/null +++ b/registry/compatibility/testdata/compatible_avro_back1.json @@ -0,0 +1,4 @@ +{ + "schema": "{\n \"type\" : \"record\",\n \"namespace\" : \"Tutorialspoint\",\n \"name\" : \"Employee\",\n \"fields\" : [\n { \"name\" : \"Name\" , \"type\" : \"string\" },\n { \"name\" : \"Age\" , \"type\" : \"int\" }\n ]\n}", + "history": ["{\n \"type\" : \"record\",\n \"namespace\" : \"Tutorialspoint\",\n \"name\" : \"Employee\",\n \"fields\" : [\n { \"name\" : \"Name\" , \"type\" : \"string\" },\n { \"name\" : \"Age\" , \"type\" : \"int\" }\n ]\n}"] +} diff --git a/registry/compatibility/testdata/compatible_json_back1.json b/registry/compatibility/testdata/compatible_json_back1.json new file mode 100644 index 0000000..b0cc46f --- /dev/null +++ b/registry/compatibility/testdata/compatible_json_back1.json @@ -0,0 +1,4 @@ +{ + "schema": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n }\n }\n}", + "history": ["{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n },\n \"room\": {\n \"type\": \"integer\",\n \"title\": \"The Room Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 18\n ]\n }\n }\n}"] +} diff --git a/registry/compatibility/testdata/forward_avro_false/schema1.json b/registry/compatibility/testdata/forward_avro_false/schema1.json new file mode 100644 index 0000000..97381a5 --- /dev/null +++ b/registry/compatibility/testdata/forward_avro_false/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "avro", + "schema": "{\n \"namespace\": \"example.avro\",\n \"type\": \"record\",\n \"name\": \"user\",\n \"fields\": [\n {\"name\": \"name\", \"type\": \"string\"},\n {\"name\": \"favorite_number\", \"type\": \"int\"},\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\n ]\n}" +} diff --git a/registry/compatibility/testdata/forward_avro_false/schema2.json b/registry/compatibility/testdata/forward_avro_false/schema2.json new file mode 100644 index 0000000..b878c70 --- /dev/null +++ b/registry/compatibility/testdata/forward_avro_false/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "avro", + "schema": "{\n \"namespace\": \"example.avro\",\n \"type\": \"record\",\n \"name\": \"user\",\n \"fields\": [\n {\"name\": \"name\", \"type\": \"string\"},\n {\"name\": \"favorite_animal\", \"type\": \"string\"},\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\n ]\n}" +} diff --git a/registry/compatibility/testdata/forward_avro_true/schema1.json b/registry/compatibility/testdata/forward_avro_true/schema1.json new file mode 100644 index 0000000..97381a5 --- /dev/null +++ b/registry/compatibility/testdata/forward_avro_true/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "avro", + "schema": "{\n \"namespace\": \"example.avro\",\n \"type\": \"record\",\n \"name\": \"user\",\n \"fields\": [\n {\"name\": \"name\", \"type\": \"string\"},\n {\"name\": \"favorite_number\", \"type\": \"int\"},\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\n ]\n}" +} diff --git a/registry/compatibility/testdata/forward_avro_true/schema2.json b/registry/compatibility/testdata/forward_avro_true/schema2.json new file mode 100644 index 0000000..bc1850d --- /dev/null +++ b/registry/compatibility/testdata/forward_avro_true/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "avro", + "schema": "{\n \"namespace\": \"example.avro\",\n \"type\": \"record\",\n \"name\": \"user\",\n \"fields\": [\n {\"name\": \"name\", \"type\": \"string\"},\n {\"name\": \"favorite_number\", \"type\": \"int\"},\n {\"name\": \"favorite_animal\", \"type\": \"string\"},\n {\"name\": \"favorite_color\", \"type\": \"string\", \"default\": \"green\"}\n ]\n}" +} diff --git a/registry/compatibility/testdata/forward_json_false/schema1.json b/registry/compatibility/testdata/forward_json_false/schema1.json new file mode 100644 index 0000000..0d4f3bb --- /dev/null +++ b/registry/compatibility/testdata/forward_json_false/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "json", + "schema": "{\n \"$id\": \"https://example.com/person.schema.json\",\n \"$schema\": \"https://json-schema.org/draft-07/schema\",\n \"title\": \"Person\",\n \"type\": \"object\",\n \"properties\": {\n \"firstName\": {\n \"type\": \"string\",\n \"description\": \"The person's first name.\"\n },\n \"lastName\": {\n \"type\": \"string\",\n \"description\": \"The person's last name.\"\n },\n \"age\": {\n \"description\": \"Age in years which must be equal to or greater than zero.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"phoneNumber\": {\n \"type\": \"string\",\n \"description\": \"The person's phone number.\"\n }\n },\n \"additionalProperties\": true\n}" +} diff --git a/registry/compatibility/testdata/forward_json_false/schema2.json b/registry/compatibility/testdata/forward_json_false/schema2.json new file mode 100644 index 0000000..69e7a56 --- /dev/null +++ b/registry/compatibility/testdata/forward_json_false/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "json", + "schema": "{\n \"$id\": \"https://example.com/person.schema.json\",\n \"$schema\": \"https://json-schema.org/draft-07/schema\",\n \"title\": \"Person\",\n \"type\": \"object\",\n \"properties\": {\n \"firstName\": {\n \"type\": \"string\",\n \"description\": \"The person's first name.\"\n },\n \"lastName\": {\n \"type\": \"string\",\n \"description\": \"The person's last name.\"\n },\n \"age\": {\n \"description\": \"Age in years which must be equal to or greater than zero.\",\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": true\n}" +} diff --git a/registry/compatibility/testdata/forward_json_true/schema1.json b/registry/compatibility/testdata/forward_json_true/schema1.json new file mode 100644 index 0000000..2cfe071 --- /dev/null +++ b/registry/compatibility/testdata/forward_json_true/schema1.json @@ -0,0 +1,5 @@ +{ + "id": "1", + "format": "json", + "schema": "{\n \"$id\": \"https://example.com/person.schema.json\",\n \"$schema\": \"https://json-schema.org/draft-07/schema\",\n \"title\": \"Person\",\n \"type\": \"object\",\n \"properties\": {\n \"firstName\": {\n \"type\": \"string\",\n \"description\": \"The person's first name.\"\n },\n \"lastName\": {\n \"type\": \"string\",\n \"description\": \"The person's last name.\"\n },\n \"age\": {\n \"description\": \"Age in years which must be equal to or greater than zero.\",\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": true\n}" +} diff --git a/registry/compatibility/testdata/forward_json_true/schema2.json b/registry/compatibility/testdata/forward_json_true/schema2.json new file mode 100644 index 0000000..b6169d3 --- /dev/null +++ b/registry/compatibility/testdata/forward_json_true/schema2.json @@ -0,0 +1,5 @@ +{ + "id": "2", + "format": "json", + "schema": "{\n \"$id\": \"https://example.com/person.schema.json\",\n \"$schema\": \"https://json-schema.org/draft-07/schema\",\n \"title\": \"Person\",\n \"type\": \"object\",\n \"properties\": {\n \"firstName\": {\n \"type\": \"string\",\n \"description\": \"The person's first name.\"\n },\n \"lastName\": {\n \"type\": \"string\",\n \"description\": \"The person's last name.\"\n },\n \"age\": {\n \"description\": \"Age in years which must be equal to or greater than zero.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"phoneNumber\": {\n \"type\": \"string\",\n \"description\": \"The person's phone number.\"\n }\n },\n \"additionalProperties\": true\n}" +} diff --git a/registry/compatibility/testdata/incompatible_avro_back1.json b/registry/compatibility/testdata/incompatible_avro_back1.json new file mode 100644 index 0000000..1e0001e --- /dev/null +++ b/registry/compatibility/testdata/incompatible_avro_back1.json @@ -0,0 +1,4 @@ +{ + "schema": "{\n \"type\" : \"record\",\n \"namespace\" : \"Tutorialspoint\",\n \"name\" : \"Employee\",\n \"fields\" : [\n { \"name\" : \"Name\" , \"type\" : \"string\" },\n { \"name\" : \"Age\" , \"type\" : \"int\" }\n ]\n}", + "history": ["{\n \"type\" : \"record\",\n \"namespace\" : \"Tutorialspoint\",\n \"name\" : \"Employee\",\n \"fields\" : [\n { \"name\" : \"Name\" , \"type\" : \"string\" }]\n}"] +} diff --git a/registry/compatibility/testdata/incompatible_json_back1.json b/registry/compatibility/testdata/incompatible_json_back1.json new file mode 100644 index 0000000..435896e --- /dev/null +++ b/registry/compatibility/testdata/incompatible_json_back1.json @@ -0,0 +1,4 @@ +{ + "schema": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n },\n \"room\": {\n \"type\": \"integer\",\n \"title\": \"The Room Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 18\n ]\n }\n }\n}", + "history": ["{\n \"$schema\": \"http://json-schema.org/draft-07/schema\",\n \"type\": \"object\",\n \"title222\": \"The Root Schema\",\n \"description\": \"The root schema comprises the entire JSON document.\",\n \"default\": {},\n \"additionalProperties\": true,\n \"required\": [\n \"phone\",\n \"room\"\n ],\n \"properties\": {\n \"phone\": {\n \"type\": \"integer\",\n \"title\": \"The Phone Schema\",\n \"description\": \"An explanation about the purpose of this instance.\",\n \"default\": \"\",\n \"examples\": [\n 23541\n ]\n }\n }\n}"] +} diff --git a/registry/docker/compatibility-checker/Dockerfile b/registry/docker/compatibility-checker/Dockerfile new file mode 100644 index 0000000..07fc765 --- /dev/null +++ b/registry/docker/compatibility-checker/Dockerfile @@ -0,0 +1,37 @@ +# References the base image for Java 18 and maven +FROM maven:3.8.7-openjdk-18-slim AS build + +# Maintainer Info +LABEL maintainer="Syntio Inc." + +# Copy the source code to a new working directory +COPY registry/compatibility/external/compatibility-checker/src /home/app/src + +# Copy the pom.xml to the root of the project +COPY registry/compatibility/external/compatibility-checker/pom.xml /home/app + +COPY registry/licenses/compatibility-checker/LICENSE-3RD-PARTY.md /home/app/licenses/LICENSE-3RD-PARTY.md +COPY LICENSE /home/app/licenses/LICENSE + +# Download dependecies and build +RUN mvn -f /home/app/pom.xml clean package + +# References base image for Java 18 runtime +FROM openjdk:18-jdk-slim + +# Copy the binaries in a new working directory +COPY --from=build /home/app/target/compatibility-checker.jar /home/checker/compatibility-checker.jar +COPY --from=build /home/app/licenses/LICENSE-3RD-PARTY.md /home/checker/licenses/LICENSE-3RD-PARTY.md +COPY --from=build /home/app/licenses/LICENSE /home/checker/licenses/LICENSE + +# Expose port 8088 to the outside world +EXPOSE 8088 + +# change to a non-root user for security +RUN adduser --disabled-password --home /home/checker user +RUN chown -R user /home/checker +RUN chmod -R 500 /home/checker +USER user + +# Set entrypoint of command that will run when container is started +ENTRYPOINT ["java","-jar","/home/checker/compatibility-checker.jar"] diff --git a/registry/docker/initdb/Dockerfile b/registry/docker/initdb/Dockerfile new file mode 100644 index 0000000..843fe78 --- /dev/null +++ b/registry/docker/initdb/Dockerfile @@ -0,0 +1,36 @@ +FROM golang:alpine3.15 AS build + +LABEL maintainer="Syntio Inc." + +ENV GO111MODULE=on \ + GOOS=linux \ + GOARCH=amd64 \ + CGO_ENABLED=0 + +RUN apk add --no-cache git + +WORKDIR /src + +COPY ./registry/go.mod ./registry/go.sum . +RUN go mod download + +COPY ./schema-registry . +COPY LICENSE ./licenses/ + +RUN go mod tidy + +RUN go build -buildvcs=false -o /app/initdb ./cmd/initdb + +FROM alpine:3.16 + +COPY --from=build /app/initdb /app/initdb +COPY --from=build /src/licenses/LICENSE-3RD-PARTY.md /app/licenses/ +COPY --from=build /src/licenses/LICENSE /app/licenses/ + +# change to a non-root user for security +RUN adduser -D -h /app user +RUN chown -R user /app +RUN chmod -R 700 /app +USER user + +CMD ["/app/initdb"] diff --git a/registry/docker/registry-firestore/Dockerfile b/registry/docker/registry-firestore/Dockerfile new file mode 100644 index 0000000..4818ac0 --- /dev/null +++ b/registry/docker/registry-firestore/Dockerfile @@ -0,0 +1,38 @@ +FROM golang:alpine3.15 AS build + +LABEL maintainer="Syntio Inc." + +ENV GO111MODULE=on \ + GOOS=linux \ + GOARCH=amd64 \ + CGO_ENABLED=0 + +RUN apk add --no-cache git + +WORKDIR /src + +COPY ./registry/go.mod ./registry/go.sum . +RUN go mod download + +COPY ./schema-registry . +COPY LICENSE ./licenses/ + +RUN go mod tidy + +RUN go build -buildvcs=false -o /app/sr ./cmd/janitorsr-firestore + +FROM alpine:3.16 + +COPY --from=build /app/sr /app/sr +COPY --from=build /src/licenses/LICENSE-3RD-PARTY.md /app/licenses/ +COPY --from=build /src/licenses/LICENSE /app/licenses/ + +# change to a non-root user for security +RUN adduser -D -h /app user +RUN chown -R user /app +RUN chmod -R 700 /app +USER user + +EXPOSE 8080 + +CMD ["/app/sr"] diff --git a/registry/docker/registry/Dockerfile b/registry/docker/registry/Dockerfile new file mode 100644 index 0000000..1d43da6 --- /dev/null +++ b/registry/docker/registry/Dockerfile @@ -0,0 +1,39 @@ +FROM golang:alpine3.15 AS build + +LABEL maintainer="Syntio Inc." + +ENV GO111MODULE=on \ + GOOS=linux \ + GOARCH=amd64 \ + CGO_ENABLED=0 + +RUN apk add --no-cache git + +WORKDIR /src + +COPY ./registry/go.mod ./registry/go.sum . +RUN go mod download + +COPY ./schema-registry . +COPY LICENSE ./licenses/ + +RUN go mod tidy + +RUN go build -buildvcs=false -o /app/sr ./cmd/janitorsr + +FROM alpine:3.16 + +COPY --from=build /app/sr /app/sr +COPY --from=build /src/docs /app/docs +COPY --from=build /src/licenses/LICENSE-3RD-PARTY.md /app/licenses/ +COPY --from=build /src/licenses/LICENSE /app/licenses/ + +# change to a non-root user for security +RUN adduser -D -h /app user +RUN chown -R user /app +RUN chmod -R 700 /app +USER user + +EXPOSE 8080 + +CMD ["/app/sr"] diff --git a/registry/docker/validity-checker/Dockerfile b/registry/docker/validity-checker/Dockerfile new file mode 100644 index 0000000..61e31df --- /dev/null +++ b/registry/docker/validity-checker/Dockerfile @@ -0,0 +1,37 @@ +# References the base image for Java 18 and maven +FROM maven:3.8.7-openjdk-18-slim AS build + +# Maintainer Info +LABEL maintainer="Syntio Inc." + +# Copy the source code to a new working directory +COPY registry/validity/external/validity-checker/src /home/app/src + +# Copy the pom.xml to the root of the project +COPY registry/validity/external/validity-checker/pom.xml /home/app + +COPY registry/licenses/validity-checker/LICENSE-3RD-PARTY.md /home/app/licenses/LICENSE-3RD-PARTY.md +COPY LICENSE /home/app/licenses/LICENSE + +# Download dependecies and build +RUN mvn -f /home/app/pom.xml clean package + +# References base image for Java 18 runtime +FROM openjdk:18-jdk-slim + +# Copy the binaries in a new working directory +COPY --from=build /home/app/target/validity-checker.jar /home/checker/validity-checker.jar +COPY --from=build /home/app/licenses/LICENSE-3RD-PARTY.md /home/checker/licenses/LICENSE-3RD-PARTY.md +COPY --from=build /home/app/licenses/LICENSE /home/checker/licenses/LICENSE + +# Expose port 8089 to the outside world +EXPOSE 8089 + +# change to a non-root user for security +RUN adduser --disabled-password --home /home/checker user +RUN chown -R user /home/checker +RUN chmod -R 500 /home/checker +USER user + +# Set entrypoint of command that will run when container is started +ENTRYPOINT ["java","-jar","/home/checker/validity-checker.jar"] diff --git a/registry/docs/docs.go b/registry/docs/docs.go new file mode 100644 index 0000000..d781fda --- /dev/null +++ b/registry/docs/docs.go @@ -0,0 +1,491 @@ +// Code generated by swaggo/swag. DO NOT EDIT. + +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/schemas": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Post new schema", + "parameters": [ + { + "description": "schema registration request", + "name": "data", + "in": "body", + "schema": { + "$ref": "#/definitions/registry.SchemaRegistrationRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/search": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Search schemas", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "schema version", + "name": "version", + "in": "query" + }, + { + "type": "string", + "description": "schema type", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "schema name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "order by name, type, id or version", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "sort schemas either asc or desc", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "maximum number of retrieved schemas matching the criteria", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "schema attributes", + "name": "attributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}": { + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Put new schema version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "schema update request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/registry.SchemaUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "summary": "Delete schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schema versions by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/latest": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get the latest schema version by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/{version}": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Delete schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions/{version}/spec": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema specification by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } + }, + "definitions": { + "registry.SchemaRegistrationRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "compatibility_mode": { + "type": "string" + }, + "description": { + "type": "string" + }, + "last_created": { + "type": "string" + }, + "name": { + "type": "string" + }, + "publisher_id": { + "type": "string" + }, + "schema_type": { + "type": "string" + }, + "specification": { + "type": "string" + }, + "validity_mode": { + "type": "string" + } + } + }, + "registry.SchemaUpdateRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "specification": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "Schema Registry API", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/registry/docs/swagger.json b/registry/docs/swagger.json new file mode 100644 index 0000000..c4687fc --- /dev/null +++ b/registry/docs/swagger.json @@ -0,0 +1,463 @@ +{ + "swagger": "2.0", + "info": { + "title": "Schema Registry API", + "contact": {}, + "version": "1.0" + }, + "paths": { + "/schemas": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Post new schema", + "parameters": [ + { + "description": "schema registration request", + "name": "data", + "in": "body", + "schema": { + "$ref": "#/definitions/registry.SchemaRegistrationRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all schemas", + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/search": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Search schemas", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "schema version", + "name": "version", + "in": "query" + }, + { + "type": "string", + "description": "schema type", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "schema name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "order by name, type, id or version", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "sort schemas either asc or desc", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "description": "maximum number of retrieved schemas matching the criteria", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "schema attributes", + "name": "attributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}": { + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Put new schema version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "schema update request", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/registry.SchemaUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "summary": "Delete schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get all active schema versions by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/all": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/latest": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get the latest schema version by schema id", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/schemas/{id}/versions/{version}": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Delete schema version by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/schemas/{id}/versions/{version}/spec": { + "get": { + "produces": [ + "application/json" + ], + "summary": "Get schema specification by schema id and version", + "parameters": [ + { + "type": "string", + "description": "schema id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "version", + "name": "version", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + } + }, + "definitions": { + "registry.SchemaRegistrationRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "compatibility_mode": { + "type": "string" + }, + "description": { + "type": "string" + }, + "last_created": { + "type": "string" + }, + "name": { + "type": "string" + }, + "publisher_id": { + "type": "string" + }, + "schema_type": { + "type": "string" + }, + "specification": { + "type": "string" + }, + "validity_mode": { + "type": "string" + } + } + }, + "registry.SchemaUpdateRequest": { + "type": "object", + "properties": { + "attributes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "specification": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/registry/docs/swagger.yaml b/registry/docs/swagger.yaml new file mode 100644 index 0000000..142f974 --- /dev/null +++ b/registry/docs/swagger.yaml @@ -0,0 +1,300 @@ +definitions: + registry.SchemaRegistrationRequest: + properties: + attributes: + type: string + compatibility_mode: + type: string + description: + type: string + last_created: + type: string + name: + type: string + publisher_id: + type: string + schema_type: + type: string + specification: + type: string + validity_mode: + type: string + type: object + registry.SchemaUpdateRequest: + properties: + attributes: + type: string + description: + type: string + specification: + type: string + type: object +info: + contact: {} + title: Schema Registry API + version: "1.0" +paths: + /schemas: + get: + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get all active schemas + post: + consumes: + - application/json + parameters: + - description: schema registration request + in: body + name: data + schema: + $ref: '#/definitions/registry.SchemaRegistrationRequest' + produces: + - application/json + responses: + "201": + description: Created + "400": + description: Bad Request + "409": + description: Conflict + "500": + description: Internal Server Error + summary: Post new schema + /schemas/{id}: + delete: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "400": + description: Bad Request + "404": + description: Not Found + summary: Delete schema by schema id + put: + consumes: + - application/json + parameters: + - description: schema id + in: path + name: id + required: true + type: string + - description: schema update request + in: body + name: data + required: true + schema: + $ref: '#/definitions/registry.SchemaUpdateRequest' + produces: + - application/json + responses: + "200": + description: OK + "400": + description: Bad Request + "404": + description: Not Found + "409": + description: Conflict + "500": + description: Internal Server Error + summary: Put new schema version + /schemas/{id}/versions: + get: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get all active schema versions by schema id + /schemas/{id}/versions/{version}: + delete: + consumes: + - application/json + parameters: + - description: schema id + in: path + name: id + required: true + type: string + - description: version + in: path + name: version + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "400": + description: Bad Request + "404": + description: Not Found + summary: Delete schema version by schema id and version + get: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + - description: version + in: path + name: version + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get schema version by schema id and version + /schemas/{id}/versions/{version}/spec: + get: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + - description: version + in: path + name: version + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get schema specification by schema id and version + /schemas/{id}/versions/all: + get: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get schema by schema id + /schemas/{id}/versions/latest: + get: + parameters: + - description: schema id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get the latest schema version by schema id + /schemas/all: + get: + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get all schemas + /schemas/search: + get: + parameters: + - description: schema id + in: query + name: id + type: string + - description: schema version + in: query + name: version + type: string + - description: schema type + in: query + name: type + type: string + - description: schema name + in: query + name: name + type: string + - description: order by name, type, id or version + in: query + name: orderBy + type: string + - description: sort schemas either asc or desc + in: query + name: sort + type: string + - description: maximum number of retrieved schemas matching the criteria + in: query + name: limit + type: string + - description: schema attributes + in: query + name: attributes + type: string + produces: + - application/json + responses: + "200": + description: OK + "400": + description: Bad Request + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Search schemas +swagger: "2.0" diff --git a/registry/go.mod b/registry/go.mod new file mode 100644 index 0000000..1cc9407 --- /dev/null +++ b/registry/go.mod @@ -0,0 +1,84 @@ +module github.com/dataphos/aquarium-janitor-standalone-sr + +go 1.17 + +require ( + github.com/DATA-DOG/go-sqlmock v1.5.0 + github.com/dataphos/lib-logger v1.0.0 + github.com/go-chi/chi/v5 v5.0.10 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.8.4 + golang.org/x/text v0.13.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + gorm.io/driver/postgres v1.5.2 + gorm.io/gorm v1.25.4 +) + +require ( + cloud.google.com/go/firestore v1.13.0 + github.com/cyberphone/json-canonicalization v0.0.0-20230710064741-aa7fe85c7dbd + github.com/dataphos/lib-httputil v1.0.0 + github.com/dataphos/lib-retry v1.0.0 + github.com/google/go-cmp v0.5.9 + github.com/hamba/avro/v2 v2.16.0 + github.com/hashicorp/golang-lru v1.0.2 + github.com/prometheus/client_golang v1.17.0 + github.com/spf13/cast v1.5.1 + github.com/swaggo/http-swagger v1.3.4 + github.com/swaggo/swag v1.16.2 + golang.org/x/sync v0.3.0 + google.golang.org/api v0.143.0 +) + +require ( + cloud.google.com/go v0.110.8 // indirect + cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/longrunning v0.5.1 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.20.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/swaggo/files v1.0.1 // indirect + go.opencensus.io v0.24.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.13.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/grpc v1.58.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/registry/go.sum b/registry/go.sum new file mode 100644 index 0000000..cb1a2e5 --- /dev/null +++ b/registry/go.sum @@ -0,0 +1,2125 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= +cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= +cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= +cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= +cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= +cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= +cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= +cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= +cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= +cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= +cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= +cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= +cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= +cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= +cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= +cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= +cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= +cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= +cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= +cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= +cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= +cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= +cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= +cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= +cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= +cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk= +cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= +cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= +cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= +cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= +cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= +cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= +cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= +cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= +cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= +cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= +cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= +cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= +cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= +cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= +cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= +cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= +cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= +cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= +cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= +cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= +cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= +cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= +cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= +cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyberphone/json-canonicalization v0.0.0-20230710064741-aa7fe85c7dbd h1:0av0vtcjA8Hqv5gyWj79CLCFVwOOyBNWPjrfUWceMNg= +github.com/cyberphone/json-canonicalization v0.0.0-20230710064741-aa7fe85c7dbd/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= +github.com/dataphos/lib-httputil v1.0.0 h1:xfaZqHz+PXxifPJU0kS/FhbQG7dEVQEibBCz9MPBPgY= +github.com/dataphos/lib-httputil v1.0.0/go.mod h1:XlXMsNAj94vwBt0pc3G9reLln51G5puRX8Qv24zmmiI= +github.com/dataphos/lib-logger v1.0.0 h1:c6d1//cyVpXB0QvixUb79rMz9OuFzvGYtk2PE8WXqtE= +github.com/dataphos/lib-logger v1.0.0/go.mod h1:AJi106+YVssJ0ak0GrrMoqvtgA+0ido2ZlvxuKyxqUQ= +github.com/dataphos/lib-retry v1.0.0 h1:pvh00Esu34z9bWKliphkeT8DHO9paLOGAi9oQ3yVN4c= +github.com/dataphos/lib-retry v1.0.0/go.mod h1:0T0VfgdamSHvieGMVMBRThXqZGezx/E1bItanDHsmDM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hamba/avro/v2 v2.16.0 h1:0XhyP65Hs8iMLtdSR0v7ZrwRjsbIZdvr7KzYgmx1Mbo= +github.com/hamba/avro/v2 v2.16.0/go.mod h1:Q9YK+qxAhtVrNqOhwlZTATLgLA8qxG2vtvkhK8fJ7Jo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= +github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= +github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= +github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= +google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= +google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA= +google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:qDbnxtViX5J6CvFbxeNUSzKgVlDLJ/6L+caxye9+Flo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= +gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= +modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= +modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= +modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= +modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/registry/internal/config/logger.go b/registry/internal/config/logger.go new file mode 100644 index 0000000..50b273e --- /dev/null +++ b/registry/internal/config/logger.go @@ -0,0 +1,41 @@ +package config + +import ( + "fmt" + "os" + + "github.com/dataphos/lib-logger/logger" +) + +const ( + LogLevelEnvKey = "LOG_LEVEL_MINIMUM" +) + +const ( + InfoLevel = "info" + WarnLevel = "warn" + ErrorLevel = "error" + DefaultLevel = InfoLevel +) + +var levels = map[string]logger.Level{InfoLevel: logger.LevelInfo, WarnLevel: logger.LevelWarn, ErrorLevel: logger.LevelError} + +// GetLogLevel returns minimum log level based on environment variable. +// Possible levels are info, warn, and error. Defaults to info. +func GetLogLevel() (logger.Level, []string) { + warnings := make([]string, 0, 2) // warnings about log config to be logged after the logger is configured + + levelString := os.Getenv(LogLevelEnvKey) + if levelString == "" { + warnings = append(warnings, fmt.Sprintf("Value for '%s' not set! Using level %s.", LogLevelEnvKey, DefaultLevel)) + return levels[DefaultLevel], warnings + } + + level, supported := levels[levelString] + if supported { + return level, warnings + } else { + warnings = append(warnings, fmt.Sprintf("Value %v for %v is not supported, using level %v.", levelString, LogLevelEnvKey, DefaultLevel)) + return levels[DefaultLevel], warnings + } +} diff --git a/registry/internal/errcodes/errcodes.go b/registry/internal/errcodes/errcodes.go new file mode 100644 index 0000000..e71f615 --- /dev/null +++ b/registry/internal/errcodes/errcodes.go @@ -0,0 +1,24 @@ +package errcodes + +const ( + DatabaseConnectionInitialization = 100 + InvalidDatabaseState = 101 + DatabaseInitialization = 102 + ServerInitialization = 103 + ExternalCheckerInitialization = 104 + ServerShutdown = 200 + BadRequest = 400 + InternalServerError = 500 + Miscellaneous = 999 +) + +func FromHttpStatusCode(code int) uint64 { + switch { + case code >= 400 && code < 500: + return BadRequest + case code >= 500: + return InternalServerError + default: + return Miscellaneous + } +} diff --git a/registry/internal/errtemplates/errtemplates.go b/registry/internal/errtemplates/errtemplates.go new file mode 100644 index 0000000..1f31d72 --- /dev/null +++ b/registry/internal/errtemplates/errtemplates.go @@ -0,0 +1,27 @@ +package errtemplates + +import ( + "fmt" + "github.com/pkg/errors" +) + +const ( + envVariableNotDefinedTemplate = "env variable %s not defined" + expectedEnvVariableAsInt = "expected env variable %s as int, received %s instead" + parsingEnvVariableFailedTemplate = "parsing env variable %s failed" +) + +// EnvVariableNotDefined returns an error stating that the given env variable is not defined. +func EnvVariableNotDefined(name string) error { + return errors.Errorf(envVariableNotDefinedTemplate, name) +} + +// ExpectedInt returns an error stating that the given env variable was expected to be an int. +func ExpectedInt(name string, value string) error { + return errors.Errorf(expectedEnvVariableAsInt, name, value) +} + +// ParsingEnvVariableFailed returns a string stating that the given env variable couldn't be parsed properly. +func ParsingEnvVariableFailed(name string) string { + return fmt.Sprintf(parsingEnvVariableFailedTemplate, name) +} diff --git a/registry/internal/metrics/metrics.go b/registry/internal/metrics/metrics.go new file mode 100644 index 0000000..e0b175a --- /dev/null +++ b/registry/internal/metrics/metrics.go @@ -0,0 +1,49 @@ +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + schemaDeletedProm = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "schema_registry", + Name: "schema_deleted", + Help: "Indicates whether the schema has been deleted (1 = schema deleted)", + }, + []string{"id"}) + schemaRegisteredProm = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "schema_registry", + Name: "schema_registered", + Help: "Indicates whether new schema has been registered (1 = schema registered)", + }, + []string{"id", "version"}) + schemaUpdatedProm = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "schema_registry", + Name: "schema_updated", + Help: "Indicates whether the schema has been updated (1 = schema updated)", + }, + []string{"id", "version"}) + schemaVersionDeletedProm = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "schema_registry", + Name: "schema_version_deleted", + Help: "Indicates whether schema version has been deleted (1 = schema version deleted)", + }, + []string{"id", "version"}) +) + +func UpdateSchemaMetricUpdate(id string, ver string) { + schemaUpdatedProm.WithLabelValues(id, ver).Set(1) +} + +func AddedSchemaMetricUpdate(id string, ver string) { + schemaRegisteredProm.WithLabelValues(id, ver).Set(1) +} + +func DeletedSchemaMetricUpdate(id string) { + schemaDeletedProm.WithLabelValues(id).Set(1) +} + +func DeleteSchemaVersionMetricUpdate(id string, ver string) { + schemaVersionDeletedProm.WithLabelValues(id, ver).Set(1) +} diff --git a/registry/licenses/LICENSE-3RD-PARTY.md b/registry/licenses/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..29a82b9 --- /dev/null +++ b/registry/licenses/LICENSE-3RD-PARTY.md @@ -0,0 +1,76 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + +| software | license link | license | +|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|--------------| +| cloud.google.com/go/compute/metadata | https://github.com/googleapis/google-cloud-go/blob/compute/v1.5.0/compute/LICENSE | Apache-2.0 | +| cloud.google.com/go/functions/metadata | https://github.com/googleapis/google-cloud-go/blob/functions/v1.3.0/functions/LICENSE | Apache-2.0 | +| cloud.google.com/go/iam | https://github.com/googleapis/google-cloud-go/blob/iam/v0.3.0/iam/LICENSE | Apache-2.0 | +| cloud.google.com/go/internal | https://github.com/googleapis/google-cloud-go/blob/v0.100.2/LICENSE | Apache-2.0 | +| cloud.google.com/go/pubsub | https://github.com/googleapis/google-cloud-go/blob/pubsub/v1.20.0/pubsub/LICENSE | Apache-2.0 | +| cloud.google.com/go/storage | https://github.com/googleapis/google-cloud-go/blob/storage/v1.22.0/storage/LICENSE | Apache-2.0 | +| github.com/Azure/azure-sdk-for-go/sdk/azcore | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azcore/v0.21.1/sdk/azcore/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/azidentity | https://github.com/Azure/azure-sdk-for-go/blob/sdk/azidentity/v0.13.2/sdk/azidentity/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/internal | https://github.com/Azure/azure-sdk-for-go/blob/sdk/internal/v0.9.1/sdk/internal/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus | https://github.com/Azure/azure-sdk-for-go/blob/sdk/messaging/azservicebus/v0.3.6/sdk/messaging/azservicebus/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/messaging/internal | https://github.com/Azure/azure-sdk-for-go/blob/2b10e91d237e/sdk/messaging/internal/LICENSE.txt | MIT | +| github.com/Azure/azure-sdk-for-go/sdk/storage/azblob | https://github.com/Azure/azure-sdk-for-go/blob/sdk/storage/azblob/v0.3.0/sdk/storage/azblob/LICENSE.txt | MIT | +| github.com/Azure/go-amqp | https://github.com/Azure/go-amqp/blob/v0.17.4/LICENSE | MIT | +| github.com/AzureAD/microsoft-authentication-library-for-go/apps | https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/v0.4.0/LICENSE | MIT | +| github.com/devigned/tab | https://github.com/devigned/tab/blob/v0.1.1/LICENSE | MIT | +| github.com/go-stack/stack | https://github.com/go-stack/stack/blob/v1.8.0/LICENSE.md | MIT | +| github.com/gogo/protobuf | https://github.com/gogo/protobuf/blob/v1.3.2/LICENSE | BSD-3-Clause | +| github.com/golang-jwt/jwt | https://github.com/golang-jwt/jwt/blob/v3.2.1/LICENSE | MIT | +| github.com/golang/groupcache/lru | https://github.com/golang/groupcache/blob/8c9f03a8e57e/LICENSE | Apache-2.0 | +| github.com/golang/mock/gomock | https://github.com/golang/mock/blob/v1.6.0/LICENSE | Apache-2.0 | +| github.com/golang/protobuf | https://github.com/golang/protobuf/blob/v1.5.2/LICENSE | BSD-3-Clause | +| github.com/golang/snappy | https://github.com/golang/snappy/blob/v0.0.4/LICENSE | BSD-3-Clause | +| github.com/google/go-cmp/cmp | https://github.com/google/go-cmp/blob/v0.5.7/LICENSE | BSD-3-Clause | +| github.com/google/uuid | https://github.com/google/uuid/blob/v1.1.2/LICENSE | BSD-3-Clause | +| github.com/googleapis/gax-go/v2 | https://github.com/googleapis/gax-go/blob/v2.2.0/v2/LICENSE | BSD-3-Clause | +| github.com/googleapis/go-type-adapters/adapters | https://github.com/googleapis/go-type-adapters/blob/v1.0.0/LICENSE | Apache-2.0 | +| github.com/gorilla/mux | https://github.com/gorilla/mux/blob/v1.8.0/LICENSE | BSD-3-Clause | +| github.com/hamba/avro | https://github.com/hamba/avro/blob/v1.6.6/LICENCE | MIT | +| github.com/json-iterator/go | https://github.com/json-iterator/go/blob/v1.1.12/LICENSE | MIT | +| github.com/klauspost/compress | https://github.com/klauspost/compress/blob/v1.14.4/LICENSE | Apache-2.0 | +| github.com/klauspost/compress/internal/snapref | https://github.com/klauspost/compress/blob/v1.14.4/internal\snapref\LICENSE | BSD-3-Clause | +| github.com/klauspost/compress/s2 | https://github.com/klauspost/compress/blob/v1.14.4/s2\LICENSE | BSD-3-Clause | +| github.com/klauspost/compress/snappy | https://github.com/klauspost/compress/blob/v1.14.4/snappy\LICENSE | BSD-3-Clause | +| github.com/klauspost/compress/zstd/internal/xxhash | https://github.com/klauspost/compress/blob/v1.14.4/zstd\internal\xxhash\LICENSE.txt | MIT | +| github.com/kylelemons/godebug | https://github.com/kylelemons/godebug/blob/v1.1.0/LICENSE | Apache-2.0 | +| github.com/modern-go/concurrent | https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE | Apache-2.0 | +| github.com/modern-go/reflect2 | https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE | Apache-2.0 | +| github.com/nats-io/nats.go | https://github.com/nats-io/nats.go/blob/v1.15.0/LICENSE | Apache-2.0 | +| github.com/nats-io/nkeys | https://github.com/nats-io/nkeys/blob/v0.3.0/LICENSE | Apache-2.0 | +| github.com/nats-io/nuid | https://github.com/nats-io/nuid/blob/v1.0.1/LICENSE | Apache-2.0 | +| github.com/nats-io/stan.go | https://github.com/nats-io/stan.go/blob/v0.10.2/LICENSE | Apache-2.0 | +| github.com/pierrec/lz4/v4 | https://github.com/pierrec/lz4/blob/v4.1.14/LICENSE | BSD-3-Clause | +| github.com/pkg/browser | https://github.com/pkg/browser/blob/ce105d075bb4/LICENSE | BSD-2-Clause | +| github.com/pkg/errors | https://github.com/pkg/errors/blob/v0.9.1/LICENSE | BSD-2-Clause | +| github.com/robfig/cron/v3 | https://github.com/robfig/cron/blob/v3.0.1/LICENSE | MIT | +| github.com/segmentio/kafka-go | https://github.com/segmentio/kafka-go/blob/v0.4.31/LICENSE | MIT | +| github.com/xdg-go/pbkdf2 | https://github.com/xdg-go/pbkdf2/blob/v1.0.0/LICENSE | Apache-2.0 | +| github.com/xdg-go/scram | https://github.com/xdg-go/scram/blob/v1.0.2/LICENSE | Apache-2.0 | +| github.com/xdg-go/stringprep | https://github.com/xdg-go/stringprep/blob/v1.0.2/LICENSE | Apache-2.0 | +| github.com/youmark/pkcs8 | https://github.com/youmark/pkcs8/blob/1be2e3e5546d/LICENSE | MIT | +| github.com/hashicorp/golang-lru | https://github.com/hashicorp/golang-lru/blob/v0.5.1/LICENSE | MPL-2.0 | +| github.com/spf13/cast | https://github.com/spf13/cast/blob/master/LICENSE | MIT | +| github.com/swaggo/swag | https://github.com/swaggo/swag/blob/master/license | MIT | +| go.mongodb.org/mongo-driver | https://github.com/mongodb/mongo-go-driver/blob/v1.9.0/LICENSE | Apache-2.0 | +| go.opencensus.io | https://github.com/census-instrumentation/opencensus-go/blob/v0.23.0/LICENSE | Apache-2.0 | +| go.uber.org/atomic | https://github.com/uber-go/atomic/blob/v1.7.0/LICENSE.txt | MIT | +| go.uber.org/multierr | https://github.com/uber-go/multierr/blob/v1.6.0/LICENSE.txt | MIT | +| go.uber.org/zap | https://github.com/uber-go/zap/blob/v1.16.0/LICENSE.txt | MIT | +| golang.org/x/crypto | https://cs.opensource.google/go/x/crypto/+/3147a52a:LICENSE | BSD-3-Clause | +| golang.org/x/net | https://cs.opensource.google/go/x/net/+/de3da570:LICENSE | BSD-3-Clause | +| golang.org/x/oauth2 | https://cs.opensource.google/go/x/oauth2/+/6242fa91:LICENSE | BSD-3-Clause | +| golang.org/x/sync | https://cs.opensource.google/go/x/sync/+/036812b2:LICENSE | BSD-3-Clause | +| golang.org/x/sys | https://cs.opensource.google/go/x/sys/+/33da011f:LICENSE | BSD-3-Clause | +| golang.org/x/text | https://cs.opensource.google/go/x/text/+/v0.3.7:LICENSE | BSD-3-Clause | +| golang.org/x/xerrors | https://cs.opensource.google/go/x/xerrors/+/5ec99f83:LICENSE | BSD-3-Clause | +| google.golang.org/api | https://github.com/googleapis/google-api-go-client/blob/v0.74.0/LICENSE | BSD-3-Clause | +| google.golang.org/api/internal/third_party/uritemplates | https://github.com/googleapis/google-api-go-client/blob/v0.74.0/internal\third_party\uritemplates\LICENSE | BSD-3-Clause | +| google.golang.org/genproto | https://github.com/googleapis/go-genproto/blob/9d709892a2bf/LICENSE | Apache-2.0 | +| google.golang.org/grpc | https://github.com/grpc/grpc-go/blob/v1.45.0/LICENSE | Apache-2.0 | +| google.golang.org/protobuf | https://github.com/protocolbuffers/protobuf-go/blob/v1.28.0/LICENSE | BSD-3-Clause | diff --git a/registry/licenses/compatibility-checker/LICENSE-3RD-PARTY.md b/registry/licenses/compatibility-checker/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..73ce6fa --- /dev/null +++ b/registry/licenses/compatibility-checker/LICENSE-3RD-PARTY.md @@ -0,0 +1,127 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - http://logback.qos.ch/logback-classic) + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.2.3 - http://logback.qos.ch/logback-core) + (The Apache License, Version 2.0) kaml (com.charleskorn.kaml:kaml:0.20.0 - https://github.com/charleskorn/kaml) + (The Apache Software License, Version 2.0) Handy URI Templates (com.damnhandy:handy-uri-templates:2.1.8 - https://github.com/damnhandy/Handy-URI-Templates) + (Apache License, Version 2.0) ClassMate (com.fasterxml:classmate:1.5.1 - https://github.com/FasterXML/java-classmate) + (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.13.4 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.13.4 - https://github.com/FasterXML/jackson-core) + (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.13.4.1 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) + (The Apache Software License, Version 2.0) Jackson datatype: org.json (com.fasterxml.jackson.datatype:jackson-datatype-json-org:2.11.4 - http://github.com/FasterXML/jackson-datatypes-misc) + (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) + (The Apache Software License, Version 2.0) Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) + (Apache License, Version 2.0) everit-org/json-schema (com.github.everit-org.json-schema:org.everit.json.schema:1.14.1 - https://github.com/everit-org/json-schema) + (BSD 2-Clause License) zstd-jni (com.github.luben:zstd-jni:1.4.4-7 - https://github.com/luben/zstd-jni) + (Apache-2.0) proto-google-common-protos (com.google.api.grpc:proto-google-common-protos:2.9.3 - https://github.com/googleapis/java-iam/proto-google-common-protos) + (Apache 2.0) error-prone annotations (com.google.errorprone:error_prone_annotations:2.5.1 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations) + (The Apache Software License, Version 2.0) Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess) + (Apache License, Version 2.0) Guava: Google Core Libraries for Java (com.google.guava:guava:30.1.1-jre - https://github.com/google/guava/guava) + (The Apache Software License, Version 2.0) J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/) + (The Apache Software License, Version 2.0) Jimfs (com.google.jimfs:jimfs:1.1 - https://github.com/google/jimfs/jimfs) + (BSD-3-Clause) Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.21.9 - https://developers.google.com/protocol-buffers/protobuf-java/) + (Go License) RE2/J (com.google.re2j:re2j:1.6 - http://github.com/google/re2j) + (Unicode/ICU License) ICU4J (com.ibm.icu:icu4j:71.1 - https://icu.unicode.org/) + (The Apache Software License, Version 2.0) project ':json-path' (com.jayway.jsonpath:json-path:2.4.0 - https://github.com/jayway/JsonPath) + (Apache 2.0) JavaPoet (com.squareup:javapoet:1.13.0 - http://github.com/square/javapoet/) + (The Apache Software License, Version 2.0) KotlinPoet (com.squareup:kotlinpoet:1.7.2 - https://github.com/square/kotlinpoet) + (The Apache Software License, Version 2.0) Okio (com.squareup.okio:okio:2.8.0 - https://github.com/square/okio/) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-compiler:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-grpc-server-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-java-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-kotlin-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-profiles:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire Multiplatform Runtime (Experimental) (com.squareup.wire:wire-runtime:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-schema:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-swift-generator:3.7.1 - https://github.com/square/wire) + (Apache License 2.0) JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk) + (Apache License, Version 2.0) Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/) + (The Apache Software License, Version 2.0) Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/) + (The Apache Software License, Version 2.0) Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/) + (Apache License, Version 2.0) Apache Commons Validator (commons-validator:commons-validator:1.7 - http://commons.apache.org/proper/commons-validator/) + (Apache License Version 2.0) apicurio-common-app-components-logging (io.apicurio:apicurio-common-app-components-logging:0.1.13.Final - https://www.apicur.io/apicurio-common-app-components-logging/) + (Apache License Version 2.0) apicurio-registry-common (io.apicurio:apicurio-registry-common:2.3.1.Final - https://www.apicur.io/apicurio-registry-common/) + (Apache License Version 2.0) apicurio-registry-protobuf-schema-utilities (io.apicurio:apicurio-registry-protobuf-schema-utilities:2.3.1.Final - https://www.apicur.io/apicurio-registry-protobuf-schema-utilities/) + (Apache License Version 2.0) apicurio-registry-schema-util-common (io.apicurio:apicurio-registry-schema-util-common:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-common/) + (Apache License Version 2.0) apicurio-registry-schema-util-json (io.apicurio:apicurio-registry-schema-util-json:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-json/) + (Apache License Version 2.0) apicurio-registry-schema-util-protobuf (io.apicurio:apicurio-registry-schema-util-protobuf:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-protobuf/) + (Apache License 2.0) utils (io.confluent:common-utils:7.2.1 - http://confluent.io/common-utils) + (Apache License 2.0) kafka-schema-registry-client (io.confluent:kafka-schema-registry-client:7.2.1 - http://confluent.io/kafka-schema-registry-client) + (Apache License 2.0) Swift Poet (io.outfoxx:swiftpoet:1.0.0 - https://github.com/outfoxx/swiftpoet) + (BSD New) Sentry-Java client (io.sentry:sentry:1.7.30 - https://github.com/getsentry/sentry-java/sentry) + (Apache License 2.0) swagger-annotations (io.swagger.core.v3:swagger-annotations:2.1.10 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations) + (EDL 1.0) Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) + (EPL 2.0) (GPL2 w/ CPE) Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca) + (Apache License 2.0) Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:2.0.2 - https://beanvalidation.org) + (Eclipse Distribution License - v 1.0) Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) + (Apache 2) Joda-Time (joda-time:joda-time:2.10.2 - https://www.joda.org/joda-time/) + (Apache License, Version 2.0) Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.10.22 - https://bytebuddy.net/byte-buddy) + (Apache License, Version 2.0) Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.10.22 - https://bytebuddy.net/byte-buddy-agent) + (The Apache Software License, Version 2.0) ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/) + (The Apache Software License, Version 2.0) JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/) + (Apache License, Version 2.0) Apache Avro (org.apache.avro:avro:1.11.0 - https://avro.apache.org) + (Apache License, Version 2.0) Apache Commons Compress (org.apache.commons:commons-compress:1.21 - https://commons.apache.org/proper/commons-compress/) + (The Apache Software License, Version 2.0) Apache Kafka (org.apache.kafka:kafka-clients:2.6.0 - https://kafka.apache.org) + (Apache License, Version 2.0) Apache Log4j API (org.apache.logging.log4j:log4j-api:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-api/) + (Apache License, Version 2.0) Apache Log4j to SLF4J Adapter (org.apache.logging.log4j:log4j-to-slf4j:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-to-slf4j/) + (Apache License, Version 2.0) tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.44 - https://tomcat.apache.org/) + (Apache License, Version 2.0) tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.44 - https://tomcat.apache.org/) + (Apache License, Version 2.0) tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.44 - https://tomcat.apache.org/) + (The Apache License, Version 2.0) org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.0 - https://github.com/apiguardian-team/apiguardian) + (Apache License, Version 2.0) AssertJ fluent assertions (org.assertj:assertj-core:3.18.1 - https://assertj.github.io/doc/assertj-core/) + (The MIT License) Checker Qual (org.checkerframework:checker-qual:3.8.0 - https://checkerframework.org) + (BSD License 3) Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/) + (Apache License 2.0) Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:6.1.7.Final - http://hibernate.org/validator/hibernate-validator) + (Apache License, version 2.0) JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.1.Final - http://www.jboss.org) + (EPL 2.0) (GPL2 w/ CPE) jboss-jakarta-jaxrs-api_spec (org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:2.0.1.Final - http://www.jboss.org/jboss-jaxrs-api_2.1_spec) + (The Apache Software License, Version 2.0) IntelliJ IDEA Annotations (org.jetbrains:annotations:13.0 - http://www.jetbrains.org) + (The Apache License, Version 2.0) Kotlin Reflect (org.jetbrains.kotlin:kotlin-reflect:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib (org.jetbrains.kotlin:kotlin-stdlib:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Common (org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Jdk7 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Jdk8 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31 - https://kotlinlang.org/) + (The Apache Software License, Version 2.0) kotlinx-serialization-core (org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.0.1 - https://github.com/Kotlin/kotlinx.serialization) + (The JSON License) JSON in Java (org.json:json:20220320 - https://github.com/douglascrockford/JSON-java) + (Eclipse Public License v2.0) JUnit Jupiter (Aggregator) (org.junit.jupiter:junit-jupiter:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter API (org.junit.jupiter:junit-jupiter-api:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Engine (org.junit.jupiter:junit-jupiter-engine:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Params (org.junit.jupiter:junit-jupiter-params:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Commons (org.junit.platform:junit-platform-commons:1.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Engine API (org.junit.platform:junit-platform-engine:1.7.1 - https://junit.org/junit5/) + (The Apache Software License, Version 2.0) LZ4 and xxHash (org.lz4:lz4-java:1.7.1 - https://github.com/lz4/lz4-java) + (The MIT License) mockito-core (org.mockito:mockito-core:3.6.28 - https://github.com/mockito/mockito) + (The MIT License) mockito-junit-jupiter (org.mockito:mockito-junit-jupiter:3.6.28 - https://github.com/mockito/mockito) + (Apache License, Version 2.0) Objenesis (org.objenesis:objenesis:3.1 - http://objenesis.org) + (The Apache License, Version 2.0) org.opentest4j:opentest4j (org.opentest4j:opentest4j:1.2.0 - https://github.com/ota4j-team/opentest4j) + (BSD) ASM Core (org.ow2.asm:asm:5.0.4 - http://asm.objectweb.org/asm/) + (The MIT License) Project Lombok (org.projectlombok:lombok:1.18.22 - https://projectlombok.org) + (The Apache Software License, Version 2.0) JSONassert (org.skyscreamer:jsonassert:1.5.0 - https://github.com/skyscreamer/JSONassert) + (MIT License) JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.30 - http://www.slf4j.org) + (MIT License) SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org) + (Apache License, Version 2.0) SnakeYAML Engine (org.snakeyaml:snakeyaml-engine:2.1 - http://www.snakeyaml.org) + (Apache License, Version 2.0) Spring AOP (org.springframework:spring-aop:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Beans (org.springframework:spring-beans:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Context (org.springframework:spring-context:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Core (org.springframework:spring-core:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring TestContext Framework (org.springframework:spring-test:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web (org.springframework:spring-web:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web MVC (org.springframework:spring-webmvc:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) spring-boot (org.springframework.boot:spring-boot:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter (org.springframework.boot:spring-boot-starter:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-logging (org.springframework.boot:spring-boot-starter-logging:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-validation (org.springframework.boot:spring-boot-starter-validation:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test (org.springframework.boot:spring-boot-test:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (The Apache Software License, Version 2.0) snappy-java (org.xerial.snappy:snappy-java:1.1.7.3 - https://github.com/xerial/snappy-java) + (The Apache Software License, Version 2.0) org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.7.0 - https://www.xmlunit.org/) + (Apache License, Version 2.0) SnakeYAML (org.yaml:snakeyaml:1.33 - https://bitbucket.org/snakeyaml/snakeyaml) diff --git a/registry/licenses/validity-checker/LICENSE-3RD-PARTY.md b/registry/licenses/validity-checker/LICENSE-3RD-PARTY.md new file mode 100644 index 0000000..5315892 --- /dev/null +++ b/registry/licenses/validity-checker/LICENSE-3RD-PARTY.md @@ -0,0 +1,128 @@ +# Licenses list + +Dependencies sometimes change licenses between versions, please keep this up to date with every new library use. + + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - http://logback.qos.ch/logback-classic) + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.2.3 - http://logback.qos.ch/logback-core) + (The Apache License, Version 2.0) kaml (com.charleskorn.kaml:kaml:0.20.0 - https://github.com/charleskorn/kaml) + (The Apache Software License, Version 2.0) Handy URI Templates (com.damnhandy:handy-uri-templates:2.1.8 - https://github.com/damnhandy/Handy-URI-Templates) + (Apache License, Version 2.0) ClassMate (com.fasterxml:classmate:1.5.1 - https://github.com/FasterXML/java-classmate) + (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.13.4 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.13.4 - https://github.com/FasterXML/jackson-core) + (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.13.4.1 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) + (The Apache Software License, Version 2.0) Jackson datatype: org.json (com.fasterxml.jackson.datatype:jackson-datatype-json-org:2.11.4 - http://github.com/FasterXML/jackson-datatypes-misc) + (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) + (The Apache Software License, Version 2.0) Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) + (The Apache License, Version 2.0) Woodstox (com.fasterxml.woodstox:woodstox-core:6.2.8 - https://github.com/FasterXML/woodstox) + (Apache License, Version 2.0) everit-org/json-schema (com.github.everit-org.json-schema:org.everit.json.schema:1.14.1 - https://github.com/everit-org/json-schema) + (Apache-2.0) proto-google-common-protos (com.google.api.grpc:proto-google-common-protos:2.9.3 - https://github.com/googleapis/java-iam/proto-google-common-protos) + (Apache 2.0) error-prone annotations (com.google.errorprone:error_prone_annotations:2.5.1 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations) + (The Apache Software License, Version 2.0) Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess) + (Apache License, Version 2.0) Guava: Google Core Libraries for Java (com.google.guava:guava:30.1.1-jre - https://github.com/google/guava/guava) + (The Apache Software License, Version 2.0) J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/) + (The Apache Software License, Version 2.0) Jimfs (com.google.jimfs:jimfs:1.1 - https://github.com/google/jimfs/jimfs) + (BSD-3-Clause) Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.21.9 - https://developers.google.com/protocol-buffers/protobuf-java/) + (Go License) RE2/J (com.google.re2j:re2j:1.6 - http://github.com/google/re2j) + (Unicode/ICU License) ICU4J (com.ibm.icu:icu4j:71.1 - https://icu.unicode.org/) + (The Apache Software License, Version 2.0) project ':json-path' (com.jayway.jsonpath:json-path:2.4.0 - https://github.com/jayway/JsonPath) + (Apache 2.0) JavaPoet (com.squareup:javapoet:1.13.0 - http://github.com/square/javapoet/) + (The Apache Software License, Version 2.0) KotlinPoet (com.squareup:kotlinpoet:1.7.2 - https://github.com/square/kotlinpoet) + (The Apache Software License, Version 2.0) Okio (com.squareup.okio:okio:2.8.0 - https://github.com/square/okio/) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-compiler:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-grpc-server-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-java-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-kotlin-generator:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-profiles:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire Multiplatform Runtime (Experimental) (com.squareup.wire:wire-runtime:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-schema:3.7.1 - https://github.com/square/wire) + (The Apache Software License, Version 2.0) Wire (com.squareup.wire:wire-swift-generator:3.7.1 - https://github.com/square/wire) + (Apache License 2.0) JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk) + (Apache License, Version 2.0) Apache Commons Codec (commons-codec:commons-codec:1.15 - https://commons.apache.org/proper/commons-codec/) + (Apache License, Version 2.0) Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/) + (The Apache Software License, Version 2.0) Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/) + (The Apache Software License, Version 2.0) Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/) + (Apache License, Version 2.0) Apache Commons Validator (commons-validator:commons-validator:1.7 - http://commons.apache.org/proper/commons-validator/) + (Apache License Version 2.0) apicurio-common-app-components-logging (io.apicurio:apicurio-common-app-components-logging:0.1.13.Final - https://www.apicur.io/apicurio-common-app-components-logging/) + (Apache License Version 2.0) apicurio-registry-common (io.apicurio:apicurio-registry-common:2.3.1.Final - https://www.apicur.io/apicurio-registry-common/) + (Apache License Version 2.0) apicurio-registry-protobuf-schema-utilities (io.apicurio:apicurio-registry-protobuf-schema-utilities:2.3.1.Final - https://www.apicur.io/apicurio-registry-protobuf-schema-utilities/) + (Apache License Version 2.0) apicurio-registry-schema-util-avro (io.apicurio:apicurio-registry-schema-util-avro:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-avro/) + (Apache License Version 2.0) apicurio-registry-schema-util-common (io.apicurio:apicurio-registry-schema-util-common:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-common/) + (Apache License Version 2.0) apicurio-registry-schema-util-json (io.apicurio:apicurio-registry-schema-util-json:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-json/) + (Apache License Version 2.0) apicurio-registry-schema-util-protobuf (io.apicurio:apicurio-registry-schema-util-protobuf:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-protobuf/) + (Apache License Version 2.0) apicurio-registry-schema-util-xml (io.apicurio:apicurio-registry-schema-util-xml:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-xml/) + (Apache License Version 2.0) apicurio-registry-schema-util-xsd (io.apicurio:apicurio-registry-schema-util-xsd:2.3.1.Final - https://www.apicur.io/apicurio-registry-schema-util-xsd/) + (Apache License 2.0) Swift Poet (io.outfoxx:swiftpoet:1.0.0 - https://github.com/outfoxx/swiftpoet) + (BSD New) Sentry-Java client (io.sentry:sentry:1.7.30 - https://github.com/getsentry/sentry-java/sentry) + (EDL 1.0) Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) + (EPL 2.0) (GPL2 w/ CPE) Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca) + (Apache License 2.0) Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:2.0.2 - https://beanvalidation.org) + (Eclipse Distribution License - v 1.0) Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) + (Apache 2) Joda-Time (joda-time:joda-time:2.10.2 - https://www.joda.org/joda-time/) + (Apache License, Version 2.0) Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.10.22 - https://bytebuddy.net/byte-buddy) + (Apache License, Version 2.0) Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.10.22 - https://bytebuddy.net/byte-buddy-agent) + (The Apache Software License, Version 2.0) ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/) + (The Apache Software License, Version 2.0) JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/) + (Apache License, Version 2.0) Apache Avro (org.apache.avro:avro:1.11.1 - https://avro.apache.org) + (Apache License, Version 2.0) Apache Commons Compress (org.apache.commons:commons-compress:1.21 - https://commons.apache.org/proper/commons-compress/) + (Apache License, Version 2.0) Apache Log4j API (org.apache.logging.log4j:log4j-api:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-api/) + (Apache License, Version 2.0) Apache Log4j to SLF4J Adapter (org.apache.logging.log4j:log4j-to-slf4j:2.13.3 - https://logging.apache.org/log4j/2.x/log4j-to-slf4j/) + (Apache License, Version 2.0) Apache XML Security for Java (org.apache.santuario:xmlsec:3.0.1 - https://santuario.apache.org/) + (Apache License, Version 2.0) tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.44 - https://tomcat.apache.org/) + (Apache License, Version 2.0) tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.44 - https://tomcat.apache.org/) + (Apache License, Version 2.0) tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.44 - https://tomcat.apache.org/) + (The Apache License, Version 2.0) org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.0 - https://github.com/apiguardian-team/apiguardian) + (Apache License, Version 2.0) AssertJ fluent assertions (org.assertj:assertj-core:3.18.1 - https://assertj.github.io/doc/assertj-core/) + (The MIT License) Checker Qual (org.checkerframework:checker-qual:3.8.0 - https://checkerframework.org) + (The BSD License) Stax2 API (org.codehaus.woodstox:stax2-api:4.2.1 - http://github.com/FasterXML/stax2-api) + (BSD License 3) Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/) + (Apache License 2.0) Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:6.1.7.Final - http://hibernate.org/validator/hibernate-validator) + (Apache License, version 2.0) JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.1.Final - http://www.jboss.org) + (EPL 2.0) (GPL2 w/ CPE) jboss-jakarta-jaxrs-api_spec (org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:2.0.1.Final - http://www.jboss.org/jboss-jaxrs-api_2.1_spec) + (The Apache Software License, Version 2.0) IntelliJ IDEA Annotations (org.jetbrains:annotations:13.0 - http://www.jetbrains.org) + (The Apache License, Version 2.0) Kotlin Reflect (org.jetbrains.kotlin:kotlin-reflect:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib (org.jetbrains.kotlin:kotlin-stdlib:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Common (org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Jdk7 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31 - https://kotlinlang.org/) + (The Apache License, Version 2.0) Kotlin Stdlib Jdk8 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31 - https://kotlinlang.org/) + (The Apache Software License, Version 2.0) kotlinx-serialization-core (org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.0.1 - https://github.com/Kotlin/kotlinx.serialization) + (The JSON License) JSON in Java (org.json:json:20220320 - https://github.com/douglascrockford/JSON-java) + (Eclipse Public License v2.0) JUnit Jupiter (Aggregator) (org.junit.jupiter:junit-jupiter:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter API (org.junit.jupiter:junit-jupiter-api:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Engine (org.junit.jupiter:junit-jupiter-engine:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Jupiter Params (org.junit.jupiter:junit-jupiter-params:5.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Commons (org.junit.platform:junit-platform-commons:1.7.1 - https://junit.org/junit5/) + (Eclipse Public License v2.0) JUnit Platform Engine API (org.junit.platform:junit-platform-engine:1.7.1 - https://junit.org/junit5/) + (The MIT License) mockito-core (org.mockito:mockito-core:3.6.28 - https://github.com/mockito/mockito) + (The MIT License) mockito-junit-jupiter (org.mockito:mockito-junit-jupiter:3.6.28 - https://github.com/mockito/mockito) + (Apache License, Version 2.0) Objenesis (org.objenesis:objenesis:3.1 - http://objenesis.org) + (The Apache License, Version 2.0) org.opentest4j:opentest4j (org.opentest4j:opentest4j:1.2.0 - https://github.com/ota4j-team/opentest4j) + (BSD) ASM Core (org.ow2.asm:asm:5.0.4 - http://asm.objectweb.org/asm/) + (The MIT License) Project Lombok (org.projectlombok:lombok:1.18.20 - https://projectlombok.org) + (The Apache Software License, Version 2.0) JSONassert (org.skyscreamer:jsonassert:1.5.0 - https://github.com/skyscreamer/JSONassert) + (MIT License) JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.30 - http://www.slf4j.org) + (MIT License) SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org) + (Apache License, Version 2.0) SnakeYAML Engine (org.snakeyaml:snakeyaml-engine:2.1 - http://www.snakeyaml.org) + (Apache License, Version 2.0) Spring AOP (org.springframework:spring-aop:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Beans (org.springframework:spring-beans:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Context (org.springframework:spring-context:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Core (org.springframework:spring-core:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring TestContext Framework (org.springframework:spring-test:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web (org.springframework:spring-web:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) Spring Web MVC (org.springframework:spring-webmvc:5.3.23 - https://github.com/spring-projects/spring-framework) + (Apache License, Version 2.0) spring-boot (org.springframework.boot:spring-boot:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter (org.springframework.boot:spring-boot-starter:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-logging (org.springframework.boot:spring-boot-starter-logging:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-validation (org.springframework.boot:spring-boot-starter-validation:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.5 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test (org.springframework.boot:spring-boot-test:2.4.4 - https://spring.io/projects/spring-boot) + (Apache License, Version 2.0) spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.4.4 - https://spring.io/projects/spring-boot) + (The Apache Software License, Version 2.0) org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.7.0 - https://www.xmlunit.org/) + (Apache License, Version 2.0) SnakeYAML (org.yaml:snakeyaml:1.33 - https://bitbucket.org/snakeyaml/snakeyaml) + diff --git a/registry/registry/cache.go b/registry/registry/cache.go new file mode 100644 index 0000000..580adca --- /dev/null +++ b/registry/registry/cache.go @@ -0,0 +1,92 @@ +package registry + +import ( + lru "github.com/hashicorp/golang-lru" + "github.com/spf13/cast" + "golang.org/x/sync/singleflight" +) + +// cached decorates Service with a lru cache. +type cached struct { + Repository + cache *lru.TwoQueueCache + group singleflight.Group +} + +// newCache returns a new cached. +func newCache(repository Repository, size int) (*cached, error) { + cache, err := lru.New2Q(size) + if err != nil { + return nil, err + } + + return &cached{ + Repository: repository, + cache: cache, + group: singleflight.Group{}, + }, nil +} + +// GetSchemaVersionByIdAndVersion overrides the Repository.GetSchemaVersionByIdAndVersion method, caching each call to the underlying Repository, while also +// making sure there's only one inflight request for the same key (if multiple goroutines request the same schema, +// only one request is actually sent down, the rest wait for the first one to share its result). +func (c *cached) GetSchemaVersionByIdAndVersion(id, version string) (VersionDetails, error) { + // this should be faster than string concatenation + arrKey := [2]string{id, version} + var err error + v, ok := c.cache.Get(arrKey) + if !ok { + // cache miss, we need a string version of the key to satisfy the singleflight.Group method signature + key := id + "_" + version + v, err, _ = c.group.Do(key, func() (interface{}, error) { + if v, err = c.Repository.GetSchemaVersionByIdAndVersion(id, version); err != nil { + return VersionDetails{}, err + } + c.cache.Add(arrKey, v) + return v, err + }) + } + return v.(VersionDetails), err +} + +// DeleteSchemaVersion overrides the Repository.DeleteSchemaVersion method, caching each call to the underlying Repository, while also +// making sure there's only one inflight request for the same key (if multiple goroutines request the deletion of the same +// Schema version, only one request is actually sent down, the rest wait for the first one to share its result). +func (c *cached) DeleteSchemaVersion(id, version string) (bool, error) { + key := id + "_" + version + bool, err, _ := c.group.Do(key, func() (interface{}, error) { + bool, err := c.Repository.DeleteSchemaVersion(id, version) + if err != nil { + return false, err + } + + arrKey := [2]string{id, version} + c.cache.Remove(arrKey) + return bool, err + }) + return cast.ToBool(bool), err +} + +// DeleteSchema overrides the Repository.DeleteSchema method, caching each call to the underlying Repository, while also +// making sure there's only one inflight request for the same key (if multiple goroutines request the deletion of the same +// Schema, only one request is actually sent down, the rest wait for the first one to share its result). +func (c *cached) DeleteSchema(id string) (bool, error) { + v, err := c.Repository.GetSchemaVersionsById(id) + if err == nil { + //Schema with the given ID exists, and it's not already deactivated + bool, err, _ := c.group.Do(id, func() (interface{}, error) { + bool, err := c.Repository.DeleteSchema(id) + if err != nil { + return false, err + } + // remove schemas that are present in cache + for _, v := range v.VersionDetails { + arrKey := [2]string{v.SchemaID, v.Version} + c.cache.Remove(arrKey) + } + return bool, nil + }) + return cast.ToBool(bool), err + } + return false, nil +} diff --git a/registry/registry/cache_test.go b/registry/registry/cache_test.go new file mode 100644 index 0000000..71f8d2c --- /dev/null +++ b/registry/registry/cache_test.go @@ -0,0 +1,82 @@ +package registry + +import ( + "strconv" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCacheGetSchemaVersionByIdAndVersion(t *testing.T) { + repo := NewMockRepository() + c, err := newCache(repo, 10) + if err != nil { + t.Error(err) + } + id, version := "1", "1" + var storedSchema, cachedSchema VersionDetails + // after the first call the schema should be stored in cache + if storedSchema, err = c.GetSchemaVersionByIdAndVersion(id, version); err != nil { + t.Error(err) + } + // second call returns schema from cache + if cachedSchema, err = c.GetSchemaVersionByIdAndVersion(id, version); err != nil { + t.Error(err) + } + + if c.cache.Len() == 0 { + t.Error("Schema unsuccessfully stored in cache.") + } + if !cmp.Equal(cachedSchema, storedSchema) { + t.Error("Cached schema differs from the stored schema") + } +} + +func TestCacheDeleteSchemaVersion(t *testing.T) { + repo := NewMockRepository() + c, err := newCache(repo, 10) + if err != nil { + t.Error(err) + } + + id, version := "1", "1" + arrKey := [2]string{id, version} + VersionDetails := MockVersionDetails(id, version) + c.cache.Add(arrKey, VersionDetails) + + if _, err = c.DeleteSchemaVersion(id, version); err != nil { + t.Error(err) + } + if _, bool := c.cache.Get(arrKey); bool { + t.Error("Schema is still stored in cache") + } +} + +func TestDeleteSchema(t *testing.T) { + repo := NewMockRepository() + c, err := newCache(repo, 10) + if err != nil { + t.Error(err) + } + id := "mocking" + schema := MockSchema(id) + + for i := 1; i <= 10; i++ { + k := strconv.Itoa(i) + VersionDetails := MockVersionDetails(k, k) + arrKey := [2]string{id, k} + c.cache.Add(arrKey, VersionDetails) + schema.VersionDetails = append(schema.VersionDetails, VersionDetails) + } + repo.SetGetSchemaVersionsByIdResponse(id, schema, nil) + if bool, err := c.DeleteSchema(id); err != nil { + t.Error(err) + } else { + if c.cache.Len() != 0 { + t.Error("Some schemas are still stored in cache") + } else if !bool { + t.Error("Schema does not exist") + } + } + +} diff --git a/registry/registry/internal/hashutils/hash.go b/registry/registry/internal/hashutils/hash.go new file mode 100644 index 0000000..b17b11d --- /dev/null +++ b/registry/registry/internal/hashutils/hash.go @@ -0,0 +1,13 @@ +package hashutils + +import ( + "crypto/sha256" + "encoding/hex" +) + +// SHA256 calculates schema hash using SHA256 algorithm. +func SHA256(data []byte) string { + hasher := sha256.New() + _, _ = hasher.Write(data) + return hex.EncodeToString(hasher.Sum(nil)) +} diff --git a/registry/registry/mock.go b/registry/registry/mock.go new file mode 100644 index 0000000..3ac81df --- /dev/null +++ b/registry/registry/mock.go @@ -0,0 +1,211 @@ +package registry + +import ( + "time" +) + +type mockRepository struct { + createSchemaResponse map[string]mockCreateSchema + getSchemaByIdAndVersionResponse map[string]mockGetSchemaVersionByIdAndVersion + updateSchemaByIdResponse map[string]mockUpdateSchemaById + getSchemaVersionsResponse map[string]mockGetSchemaVersionsById + getAllSchemaVersionsResponse map[string]mockGetAllSchemaVersions + getLatestSchemaVersionResponse map[string]mockGetLatestSchemaVersion + deleteSchemaResponse map[string]mockDeleteSchema + deleteVersionResponse map[string]mockDeleteSchemaVersion + getSchemasResponse map[string]mockGetSchemas + getAllSchemasResponse map[string]mockGetAllSchemas +} + +type mockCompChecker struct { + checkCompResponse map[string]mockCheckComp +} + +type mockValChecker struct { + checkValResponse map[string]mockValComp +} + +type mockCheckComp struct { + ok bool + err error +} + +type mockValComp struct { + ok bool + err error +} + +type mockCreateSchema struct { + VersionDetails VersionDetails + ok bool + err error +} + +type mockGetSchemaVersionByIdAndVersion struct { + VersionDetails VersionDetails + err error +} + +type mockUpdateSchemaById struct { + VersionDetails VersionDetails + ok bool + err error +} + +type mockGetSchemaVersionsById struct { + schema Schema + err error +} + +type mockGetAllSchemaVersions struct { + schema Schema + err error +} + +type mockGetLatestSchemaVersion struct { + schema Schema + err error +} + +type mockDeleteSchema struct { + ok bool + err error +} + +type mockDeleteSchemaVersion struct { + ok bool + err error +} + +type mockGetSchemas struct { + schemas []Schema + err error +} + +type mockGetAllSchemas struct { + schemas []Schema + err error +} + +func MockSchema(id string) Schema { + return Schema{ + SchemaID: id, + SchemaType: "mocking", + Name: "mocking", + VersionDetails: nil, + Description: "mocking", + LastCreated: "mocking", + PublisherID: "mocking", + CompatibilityMode: "none", + ValidityMode: "none", + } +} + +func MockVersionDetails(id, version string) VersionDetails { + return VersionDetails{ + VersionID: id, + Version: version, + SchemaID: "mocking", + Specification: "mocking", + Description: "mocking", + SchemaHash: "mocking", + CreatedAt: time.Time{}, + VersionDeactivated: false, + } +} + +func NewMockRepository() *mockRepository { + return &mockRepository{ + createSchemaResponse: map[string]mockCreateSchema{}, + getSchemaByIdAndVersionResponse: map[string]mockGetSchemaVersionByIdAndVersion{}, + updateSchemaByIdResponse: map[string]mockUpdateSchemaById{}, + getSchemaVersionsResponse: map[string]mockGetSchemaVersionsById{}, + getAllSchemaVersionsResponse: map[string]mockGetAllSchemaVersions{}, + getLatestSchemaVersionResponse: map[string]mockGetLatestSchemaVersion{}, + deleteSchemaResponse: map[string]mockDeleteSchema{}, + deleteVersionResponse: map[string]mockDeleteSchemaVersion{}, + getSchemasResponse: map[string]mockGetSchemas{}, + getAllSchemasResponse: map[string]mockGetAllSchemas{}, + } +} + +func (c *mockCompChecker) Check(_ string, _ []string, _ string) (bool, error) { + return true, nil +} + +func (c *mockValChecker) Check(_, _, _ string) (bool, error) { + return true, nil +} + +func (m *mockRepository) CheckCompatibility(_, _ string) (bool, error) { + return true, nil +} + +func (m *mockRepository) DeleteSchema(_ string) (bool, error) { + return true, nil +} + +func (m *mockRepository) DeleteSchemaVersion(_, _ string) (bool, error) { + return true, nil +} + +func (m *mockRepository) GetSchemas() ([]Schema, error) { + return []Schema{{ + SchemaID: "mocking", + SchemaType: "mocking", + Name: "mocking", + VersionDetails: nil, + Description: "mocking", + LastCreated: "mocking", + PublisherID: "mocking", + CompatibilityMode: "none", + ValidityMode: "none", + }}, nil +} + +func (m *mockRepository) GetAllSchemas() ([]Schema, error) { + return []Schema{{ + SchemaID: "mocking", + SchemaType: "mocking", + Name: "mocking", + VersionDetails: nil, + Description: "mocking", + LastCreated: "mocking", + PublisherID: "mocking", + CompatibilityMode: "none", + ValidityMode: "none", + }}, nil +} + +func (m *mockRepository) GetLatestSchemaVersion(_ string) (VersionDetails, error) { + return MockVersionDetails("mocking", "mocking"), nil +} + +func (m *mockRepository) CreateSchema(_ SchemaRegistrationRequest) (VersionDetails, bool, error) { + return MockVersionDetails("mocking", "mocking"), true, nil +} + +func (m *mockRepository) GetSchemaVersionByIdAndVersion(id string, version string) (VersionDetails, error) { + return MockVersionDetails(id, version), nil +} + +func (m *mockRepository) UpdateSchemaById(id string, _ SchemaUpdateRequest) (VersionDetails, bool, error) { + return MockVersionDetails(id, "mocking"), true, nil +} + +func (m *mockRepository) SetGetSchemaVersionsByIdResponse(id string, schema Schema, err error) { + m.getSchemaVersionsResponse[id] = mockGetSchemaVersionsById{ + schema: schema, + err: err, + } +} + +func (m *mockRepository) GetSchemaVersionsById(id string) (Schema, error) { + response := m.getSchemaVersionsResponse[id] + return response.schema, response.err +} + +func (m *mockRepository) GetAllSchemaVersions(id string) (Schema, error) { + response := m.getSchemaVersionsResponse[id] + return response.schema, response.err +} diff --git a/registry/registry/model.go b/registry/registry/model.go new file mode 100644 index 0000000..12d4108 --- /dev/null +++ b/registry/registry/model.go @@ -0,0 +1,65 @@ +package registry + +import ( + "time" +) + +// Schema is a structure that defines the parent entity in the schema registry +type Schema struct { + SchemaID string `json:"schema_id,omitempty"` + SchemaType string `json:"schema_type"` + Name string `json:"name"` + VersionDetails []VersionDetails `json:"schemas"` + Description string `json:"description"` + LastCreated string `json:"last_created"` + PublisherID string `json:"publisher_id"` + CompatibilityMode string `json:"compatibility_mode"` + ValidityMode string `json:"validity_mode"` +} + +// VersionDetails represent the child entity in the schema registry model. +// The schema (specification) and version with some other details is set here. +type VersionDetails struct { + VersionID string `json:"version_id,omitempty"` + Version string `json:"version"` + SchemaID string `json:"schema_id"` + Specification string `json:"specification"` + Description string `json:"description"` + SchemaHash string `json:"schema_hash"` + CreatedAt time.Time `json:"created_at"` + VersionDeactivated bool `json:"version_deactivated"` + Attributes string `json:"attributes"` +} + +// SchemaRegistrationRequest contains information needed to register a schema. +type SchemaRegistrationRequest struct { + Description string `json:"description"` + Specification string `json:"specification"` + Name string `json:"name"` + SchemaType string `json:"schema_type"` + LastCreated string `json:"last_created"` + PublisherID string `json:"publisher_id"` + CompatibilityMode string `json:"compatibility_mode"` + ValidityMode string `json:"validity_mode"` + Attributes string `json:"attributes"` +} + +// SchemaUpdateRequest contains information needed to update a schema. +type SchemaUpdateRequest struct { + Description string `json:"description"` + Specification string `json:"specification"` + Attributes string `json:"attributes"` +} + +// SchemaCompatibilityRequest contains information needed to check compatibility of schemas +type SchemaCompatibilityRequest struct { + SchemaID string `json:"schema_id"` + NewSchema string `json:"new_schema"` +} + +// SchemaValidityRequest contains information needed to check validity of a schema +type SchemaValidityRequest struct { + NewSchema string `json:"new_schema"` + Format string `json:"format"` + Mode string `json:"mode"` +} diff --git a/registry/registry/repo.go b/registry/registry/repo.go new file mode 100644 index 0000000..58c450a --- /dev/null +++ b/registry/registry/repo.go @@ -0,0 +1,29 @@ +package registry + +import ( + "github.com/pkg/errors" +) + +var ErrNotFound = errors.New("not found") +var ErrUnknownComp = errors.New("unknown value for compatibility_mode") +var ErrUnknownVal = errors.New("unknown value for validity mode") +var ErrNotValid = errors.New("schema is not valid") +var ErrNotComp = errors.New("schemas are not compatible") + +type Repository interface { + CreateSchema(schemaRegisterRequest SchemaRegistrationRequest) (VersionDetails, bool, error) + GetSchemaVersionByIdAndVersion(id string, version string) (VersionDetails, error) + UpdateSchemaById(id string, schemaUpdateRequest SchemaUpdateRequest) (VersionDetails, bool, error) + GetSchemaVersionsById(id string) (Schema, error) + GetAllSchemaVersions(id string) (Schema, error) + GetLatestSchemaVersion(id string) (VersionDetails, error) + DeleteSchema(id string) (bool, error) + DeleteSchemaVersion(id, version string) (bool, error) + GetAllSchemas() ([]Schema, error) + GetSchemas() ([]Schema, error) +} + +// WithCache decorates the given Repository with an in-memory cache of the given size. +func WithCache(repository Repository, size int) (Repository, error) { + return newCache(repository, size) +} diff --git a/registry/registry/repository/firestore/firestore.go b/registry/registry/repository/firestore/firestore.go new file mode 100644 index 0000000..62b0ee1 --- /dev/null +++ b/registry/registry/repository/firestore/firestore.go @@ -0,0 +1,328 @@ +package firestore + +import ( + "cloud.google.com/go/firestore" + "context" + "encoding/base64" + "google.golang.org/api/iterator" + "log" + "os" + "strconv" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/internal/hashutils" +) + +// Rewrite all functions to work differently based on whether the schema is active or not. + +// Firestore implementation for database.DBExecutor interface. +type DB struct { + Collection string + Client *firestore.Client +} + +// CREDENTIAL FILE NEED TO BE SET UNDER ENV VAR "GOOGLE_APPLICATION_CREDENTIALS" +func New() (*DB, error) { + ctx := context.Background() + + collection := os.Getenv("COLLECTION") + projectId := os.Getenv("PROJECT_ID") + + client, initErr := firestore.NewClient(ctx, projectId) + if initErr != nil { + log.Fatalf("Firestore client initialization failed. Server can't start properly.\nError: %s", initErr) + } + return &DB{ + Collection: collection, + Client: client, + }, nil +} + +// DeleteSchema takes the id of the schema which needs to be deleted +// will return bool that indicates if the schema was deleted and error +func (db *DB) DeleteSchema(id string) (bool, error) { + ctx := context.Background() + _, err := db.Client.Collection(db.Collection).Doc(id).Delete(ctx) + if err != nil { + return false, err + } + return true, err +} + +// DeleteSchemaVersion takes the id of the schema and version which needs to be deleted +// will return bool that indicates if the schema was deleted and error +func (db *DB) DeleteSchemaVersion(id, version string) (bool, error) { + ctx := context.Background() + deleted := false // flag to track if the version exists + + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + if err != nil { + + } + // remove the one that has the version==version + var result *Schema + if err = document.DataTo(&result); err != nil { + return false, err + } + var newDetails []VersionDetails + for i, v := range result.VersionDetails { + versionInt, _ := strconv.Atoi(version) + if v.Version != int32(versionInt) { + newDetails = append(newDetails, result.VersionDetails[i:i+1]...) + continue + } + // set deleted to true, so we know that the version existed + deleted = true + } + if deleted { + // update the new version details only if the version exists + _, err = db.Client.Collection(db.Collection).Doc(id).Set(ctx, map[string]interface{}{ + "schemas": newDetails, + }, firestore.MergeAll) + if err != nil { + return false, err + } + } + + return deleted, nil +} + +// GetSchemaVersionByIdAndVersion retrieves a schema by its id and version. Method returns a boolean flag which defines +// if the wanted schema exists. If the schema is found, representing Payload is retrieved. +func (db *DB) GetSchemaVersionByIdAndVersion(id, version string) (registry.VersionDetails, error) { + ctx := context.Background() + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + if err != nil { + log.Printf("could not get schema by that ID: %v", err) + return registry.VersionDetails{}, err + } + var result *Schema + if err = document.DataTo(&result); err != nil { + return registry.VersionDetails{}, err + } + + for i, v := range result.VersionDetails { + versionInt, _ := strconv.Atoi(version) + if v.Version == int32(versionInt) { + newDetails := result.VersionDetails[i : i+1] + return intoRegistryVersionDetails(newDetails[0]), nil + } + } + return registry.VersionDetails{}, err +} + +// GetSchemaVersionsById returns a list of VersionDetails from the database. +// The input arguments are the request context and the document/row ID. +// The return value is a list of model.VersionDetails and an error in case of a fault or failure. +// Has to be rewritten to return only active schemas +func (db *DB) GetSchemaVersionsById(id string) (registry.Schema, error) { + ctx := context.Background() + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + if err != nil { + log.Printf("could not get schema by that ID: %v", err) + return registry.Schema{}, err + } + var result Schema + if err = document.DataTo(&result); err != nil { + return registry.Schema{}, err + } + return intoRegistrySchema(result), nil +} + +// GetAllSchemaVersions returns a list of VersionDetails from the database. +// The input arguments are the request context and the document/row ID. +// The return value is a list of model.VersionDetails and an error in case of a fault or failure. +func (db *DB) GetAllSchemaVersions(id string) (registry.Schema, error) { + ctx := context.Background() + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + if err != nil { + log.Printf("could not get schema by that ID: %v", err) + return registry.Schema{}, err + } + var result Schema + if err = document.DataTo(&result); err != nil { + return registry.Schema{}, err + } + return intoRegistrySchema(result), nil +} + +// GetLatestSchemaVersion retrieves the latest VersionDetails of a schema by its id. +func (db *DB) GetLatestSchemaVersion(id string) (registry.VersionDetails, error) { + document, err := db.Client.Collection(db.Collection).Doc(id).Get(context.Background()) + if err != nil { + log.Printf("could not get schema by that ID: %v", err) + return registry.VersionDetails{}, err + } + var result Schema + if err = document.DataTo(&result); err != nil { + return registry.VersionDetails{}, err + } + + for i, v := range result.VersionDetails { + // because versions start from 1 + if int(v.Version) == len(result.VersionDetails) { + newDetails := result.VersionDetails[i : i+1] + result.VersionDetails = newDetails + return intoRegistryVersionDetails(result.VersionDetails[0]), nil + } + } + return registry.VersionDetails{}, nil +} + +// GetSchemas retrieves all schemas in the Collection +// Has to be rewritten to return only active schemas +func (db *DB) GetSchemas() ([]registry.Schema, error) { + var allSchemas []registry.Schema + iter := db.Client.Collection(db.Collection).Documents(context.Background()) + defer iter.Stop() + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + + var result Schema + if err = doc.DataTo(&result); err != nil { + return nil, err + } + allSchemas = append(allSchemas, intoRegistrySchema(result)) + } + + return allSchemas, nil +} + +// GetAllSchemas retrieves all schemas in the Collection +func (db *DB) GetAllSchemas() ([]registry.Schema, error) { + var allSchemas []registry.Schema + iter := db.Client.Collection(db.Collection).Documents(context.Background()) + defer iter.Stop() + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + + var result Schema + if err = doc.DataTo(&result); err != nil { + return nil, err + } + allSchemas = append(allSchemas, intoRegistrySchema(result)) + } + return allSchemas, nil +} + +// UpdateSchemaById updates the schema Specification e.g. creates a new entry of VersionDetails. +// The input arguments are the request context, followed by the ID string of the document/row ID, +// specification in []byte form and a flag indicating if Schema was manually updated or dynamically evolved. +// The output is a model.InsertInfo structure, a flag indicating if new version of schema was added and an error. +func (db *DB) UpdateSchemaById(id string, schemaUpdateRequest registry.SchemaUpdateRequest) (registry.VersionDetails, bool, error) { + ctx := context.Background() + document, err := db.Client.Collection(db.Collection).Doc(id).Get(ctx) + if err != nil { + log.Printf("could not get schema by that ID: %v", err) + return registry.VersionDetails{}, false, err + } + + var result *Schema + if err = document.DataTo(&result); err != nil { + return registry.VersionDetails{}, false, err + } + + hash := hashutils.SHA256([]byte(schemaUpdateRequest.Specification)) + + if exists, info := db.existsByHash(hash, result); exists { + log.Printf("Schema %v with version %d already exists ", result.SchemaID, info.Version) + return intoRegistryVersionDetails(*info), false, nil + } + + newVersion := int32(len(result.VersionDetails) + 1) + d := &VersionDetails{ + VersionID: id, + SchemaID: id, + Version: newVersion, + SchemaHash: hash, + Specification: base64.StdEncoding.EncodeToString([]byte(schemaUpdateRequest.Specification)), + } + details := result.VersionDetails + details = append(details, *d) + result.VersionDetails = details + + if _, err := db.Client.Collection(db.Collection).Doc(id).Set(ctx, result); err != nil { + log.Println("Could not update new schema") + return registry.VersionDetails{}, false, err + } + + return registry.VersionDetails{ + VersionID: id, + SchemaID: id, + Version: strconv.Itoa(int(newVersion)), + Specification: schemaUpdateRequest.Specification, + Description: schemaUpdateRequest.Description, + SchemaHash: hash, + CreatedAt: time.Now(), + }, true, nil +} + +// CreateSchema persists a new Schema structure into the document or relational database. +// Input arguments are request context, and a DTO describing the basic new schema parameters. +// The output is a model.InsertInfo structure, a flag indicating if new version of schema was added and an error. +func (db *DB) CreateSchema(schemaRegisterRequest registry.SchemaRegistrationRequest) (registry.VersionDetails, bool, error) { + ctx := context.Background() + byteSchema := []byte(schemaRegisterRequest.Specification) + hash := hashutils.SHA256(byteSchema) + + it := db.Client.Collection(db.Collection).Documents(ctx) + for sh, err := it.Next(); err != iterator.Done; sh, err = it.Next() { + if err != nil { + log.Println("Could not read existing data") + return registry.VersionDetails{}, false, err + } + var schema *Schema + err = sh.DataTo(&schema) + if err != nil { + log.Printf("err while transfering schema to struct: %v", err) + return registry.VersionDetails{}, false, err + } + if exists, _ := db.existsByHash(hash, schema); exists { + return intoRegistryVersionDetails(schema.VersionDetails[0]), false, err + } + } + version := int32(1) + doc := db.Client.Collection(db.Collection).NewDoc() + + sc := fillOutSchema(schemaRegisterRequest, doc.ID, hash, version) + if _, err := doc.Set(ctx, sc); err != nil { + log.Println("Could not create new schema") + return registry.VersionDetails{}, false, err + } + return intoRegistryVersionDetails(sc.VersionDetails[0]), true, nil +} + +// existsByHash is a helper function that checks if there is a corresponding hash in a schema. +// the input arguments are a sha-256 hash of the schema specification and a model.Schema struct. +// the output is a flag indicating if the schema exists, and were the flag true the corresponding model.InsertInfo +// struct. +func (db *DB) existsByHash(hash string, schema *Schema) (bool, *VersionDetails) { + var info *VersionDetails + for _, sd := range schema.VersionDetails { + if sd.SchemaHash == hash { + info = &VersionDetails{ + VersionID: sd.VersionID, + Version: sd.Version, + SchemaID: sd.SchemaID, + Specification: sd.Specification, + SchemaHash: hash, + Description: sd.Description, + } + return true, info + } + } + return false, nil +} diff --git a/registry/registry/repository/firestore/model.go b/registry/registry/repository/firestore/model.go new file mode 100644 index 0000000..4b17365 --- /dev/null +++ b/registry/registry/repository/firestore/model.go @@ -0,0 +1,87 @@ +package firestore + +import ( + "encoding/base64" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "strconv" + "time" +) + +// Schema is a structure that defines the parent entity in the schema registry. +type Schema struct { + SchemaID string `json:"schema_id,omitempty" bson:"schema-id,omitempty" firestore:"schema-id"` + SchemaType string `json:"schema_type" bson:"schema-type" firestore:"schema-type"` + Name string `json:"name" bson:"name" firestore:"name"` + Description string `json:"description" bson:"description" firestore:"description"` + LastCreated string `json:"last_created" bson:"last-created" firestore:"last-created"` + PublisherID string `json:"publisher_id" bson:"publisher-id" firestore:"publisher-id"` + VersionDetails []VersionDetails `json:"schemas" bson:"schemas" firestore:"schemas"` +} + +// VersionDetails represents the child entity in the schema registry model. +type VersionDetails struct { + VersionID string `json:"id,omitempty" bson:"_id,omitempty" firestore:"ID"` + Version int32 `json:"version" bson:"version" firestore:"version"` + SchemaID string `json:"schemaID" bson:"schemaID" firestore:"schemaID"` + Description string `json:"description" bson:"description" firestore:"description"` + Specification string `json:"specification" bson:"specification" firestore:"specification"` + SchemaHash string `json:"schema_hash" bson:"schema-hash" firestore:"schema-hash"` + CreatedAt time.Time `json:"creation_date" bson:"creation-date" firestore:"creation-date"` + VersionDeactivated bool `json:"version_deactivated" bson:"version-deactivated" firestore:"version-deactivated"` +} + +// intoRegistrySchema maps Schema from repository to service layer. +func intoRegistrySchema(schema Schema) registry.Schema { + var registryVersionDetails []registry.VersionDetails + for _, versionDetails := range schema.VersionDetails { + registryVersionDetails = append(registryVersionDetails, intoRegistryVersionDetails(versionDetails)) + } + + return registry.Schema{ + SchemaID: schema.SchemaID, + SchemaType: schema.SchemaType, + Name: schema.Name, + VersionDetails: registryVersionDetails, + Description: schema.Description, + LastCreated: schema.LastCreated, + PublisherID: schema.PublisherID, + } +} + +// intoRegistryVersionDetails maps VersionDetails from repository to service layer. +func intoRegistryVersionDetails(VersionDetails VersionDetails) registry.VersionDetails { + return registry.VersionDetails{ + VersionID: VersionDetails.VersionID, + Version: strconv.Itoa(int(VersionDetails.Version)), + SchemaID: VersionDetails.SchemaID, + Specification: VersionDetails.Specification, + Description: VersionDetails.Description, + SchemaHash: VersionDetails.SchemaHash, + CreatedAt: VersionDetails.CreatedAt, + VersionDeactivated: VersionDetails.VersionDeactivated, + } +} + +func fillOutSchema(schema registry.SchemaRegistrationRequest, documentID, hash string, version int32) *Schema { + b64coder := base64.StdEncoding + + return &Schema{ + SchemaID: documentID, + SchemaType: schema.SchemaType, + Name: schema.Name, + VersionDetails: []VersionDetails{ + { + VersionID: documentID, + Version: version, + SchemaID: documentID, + Specification: b64coder.EncodeToString([]byte(schema.Specification)), + Description: "", + SchemaHash: hash, + CreatedAt: time.Now(), + }, + }, + LastCreated: time.Now().String(), + Description: schema.Description, + PublisherID: "", + } +} diff --git a/registry/registry/repository/postgres/env.go b/registry/registry/repository/postgres/env.go new file mode 100644 index 0000000..db13cfc --- /dev/null +++ b/registry/registry/repository/postgres/env.go @@ -0,0 +1,58 @@ +package postgres + +import ( + "os" + + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errtemplates" +) + +type DatabaseConfig struct { + TablePrefix string + Host string + User string + Password string + DatabaseName string +} + +const ( + tablePrefixEnvKey = "SR_TABLE_PREFIX" + hostEnvKey = "SR_HOST" + userEnvKey = "SR_USER" + passwordEnvKey = "SR_PASSWORD" + databaseNameEnvKey = "SR_DBNAME" +) + +func LoadDatabaseConfigFromEnv() (DatabaseConfig, error) { + tablePrefix := os.Getenv(tablePrefixEnvKey) + if tablePrefix == "" { + return DatabaseConfig{}, errtemplates.EnvVariableNotDefined(tablePrefixEnvKey) + } + + host := os.Getenv(hostEnvKey) + if host == "" { + return DatabaseConfig{}, errtemplates.EnvVariableNotDefined(hostEnvKey) + } + + user := os.Getenv(userEnvKey) + if user == "" { + return DatabaseConfig{}, errtemplates.EnvVariableNotDefined(userEnvKey) + } + + password := os.Getenv(passwordEnvKey) + if password == "" { + return DatabaseConfig{}, errtemplates.EnvVariableNotDefined(passwordEnvKey) + } + + dbName := os.Getenv(databaseNameEnvKey) + if dbName == "" { + return DatabaseConfig{}, errtemplates.EnvVariableNotDefined(databaseNameEnvKey) + } + + return DatabaseConfig{ + TablePrefix: tablePrefix, + Host: host, + User: user, + Password: password, + DatabaseName: dbName, + }, nil +} diff --git a/registry/registry/repository/postgres/gorm.go b/registry/registry/repository/postgres/gorm.go new file mode 100644 index 0000000..cbd472b --- /dev/null +++ b/registry/registry/repository/postgres/gorm.go @@ -0,0 +1,38 @@ +package postgres + +import ( + "fmt" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func InitializeGormFromEnv() (*gorm.DB, error) { + config, err := LoadDatabaseConfigFromEnv() + if err != nil { + return nil, err + } + + return InitializeGorm(config) +} + +func InitializeGorm(config DatabaseConfig) (*gorm.DB, error) { + connectionString := fmt.Sprintf( + "host=%s user=%s password=%s dbname=%s port=5432 sslmode=disable", + config.Host, config.User, config.Password, config.DatabaseName, + ) + dialector := postgres.Open(connectionString) + gcfg := &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: config.TablePrefix, + SingularTable: true, + }, + } + + db, err := gorm.Open(dialector, gcfg) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/registry/registry/repository/postgres/initdb.go b/registry/registry/repository/postgres/initdb.go new file mode 100644 index 0000000..f33dc1f --- /dev/null +++ b/registry/registry/repository/postgres/initdb.go @@ -0,0 +1,21 @@ +package postgres + +import ( + "gorm.io/gorm" +) + +// Initdb initializes the schema registry database. +func Initdb(db *gorm.DB) error { + if err := db.Exec("create schema if not exists syntio_schema authorization postgres").Error; err != nil { + return err + } + return db.AutoMigrate(&Schema{}, &VersionDetails{}) +} + +// HealthCheck checks if the necessary tables exist. +// +// Note that this function returns false in case of network issues as well, acting like a health check of sorts. +func HealthCheck(db *gorm.DB) bool { + migrator := db.Migrator() + return migrator.HasTable(&Schema{}) && migrator.HasTable(&VersionDetails{}) +} diff --git a/registry/registry/repository/postgres/model.go b/registry/registry/repository/postgres/model.go new file mode 100644 index 0000000..2de65aa --- /dev/null +++ b/registry/registry/repository/postgres/model.go @@ -0,0 +1,69 @@ +package postgres + +import ( + "strconv" + "time" + + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" +) + +// Schema is a structure that defines the parent entity in the schema registry. +type Schema struct { + SchemaID uint `gorm:"primaryKey;column:schema_id;autoIncrement"` + SchemaType string `gorm:"column:schema_type;type:varchar(8)"` + Name string `gorm:"column:name;type:varchar(256)"` + Description string `gorm:"column:description;type:text"` + LastCreated string `gorm:"column:last_created;type:varchar(8)"` + PublisherID string `gorm:"column:publisher_id;type:varchar(256)"` + VersionDetails []VersionDetails `gorm:"foreignKey:schema_id"` + CompatibilityMode string `gorm:"column:compatibility_mode;type:varchar(256)"` + ValidityMode string `gorm:"column:validity_mode;type:varchar(256)"` +} + +// VersionDetails represents the child entity in the schema registry model. +type VersionDetails struct { + VersionID uint `gorm:"primaryKey;column:version_id;autoIncrement"` + Version string `gorm:"column:version;type:int;index:idver_idx"` + SchemaID uint `gorm:"column:schema_id;index:idver_idx"` + Description string `gorm:"column:description;type:text"` + Specification string `gorm:"column:specification;type:text"` + SchemaHash string `gorm:"column:schema_hash;type:varchar(256)"` + CreatedAt time.Time `gorm:"column:created_at"` + VersionDeactivated bool `gorm:"column:version_deactivated;type:boolean"` + Attributes string `gorm:"column:attributes;type:text"` +} + +// intoRegistrySchema maps Schema from repository to service layer. +func intoRegistrySchema(schema Schema) registry.Schema { + var registryVersionDetails []registry.VersionDetails + for _, versionDetails := range schema.VersionDetails { + registryVersionDetails = append(registryVersionDetails, intoRegistryVersionDetails(versionDetails)) + } + + return registry.Schema{ + SchemaID: strconv.Itoa(int(schema.SchemaID)), + SchemaType: schema.SchemaType, + Name: schema.Name, + VersionDetails: registryVersionDetails, + Description: schema.Description, + LastCreated: schema.LastCreated, + PublisherID: schema.PublisherID, + CompatibilityMode: schema.CompatibilityMode, + ValidityMode: schema.ValidityMode, + } +} + +// intoRegistryVersionDetails maps VersionDetails from repository to service layer. +func intoRegistryVersionDetails(VersionDetails VersionDetails) registry.VersionDetails { + return registry.VersionDetails{ + VersionID: strconv.Itoa(int(VersionDetails.VersionID)), + Version: VersionDetails.Version, + SchemaID: strconv.Itoa(int(VersionDetails.SchemaID)), + Specification: VersionDetails.Specification, + Description: VersionDetails.Description, + SchemaHash: VersionDetails.SchemaHash, + CreatedAt: VersionDetails.CreatedAt, + VersionDeactivated: VersionDetails.VersionDeactivated, + Attributes: VersionDetails.Attributes, + } +} diff --git a/registry/registry/repository/postgres/postgres.go b/registry/registry/repository/postgres/postgres.go new file mode 100644 index 0000000..2ad9a38 --- /dev/null +++ b/registry/registry/repository/postgres/postgres.go @@ -0,0 +1,291 @@ +package postgres + +import ( + "encoding/base64" + "gorm.io/gorm" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/internal/hashutils" +) + +type Repository struct { + db *gorm.DB +} + +// New returns a new instance of Repository. +func New(db *gorm.DB) *Repository { + return &Repository{ + db: db, + } +} + +// GetSchemaVersionByIdAndVersion retrieves a schema version by its id and version. +// Returns registry.ErrNotFound in case there's no schema under the given id and version. +func (r *Repository) GetSchemaVersionByIdAndVersion(id, version string) (registry.VersionDetails, error) { + var details VersionDetails + if err := r.db.Where("schema_id = ? and version = ? and version_deactivated = ?", id, version, false).Take(&details).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return registry.VersionDetails{}, registry.ErrNotFound + } + return registry.VersionDetails{}, err + } + return intoRegistryVersionDetails(details), nil +} + +// GetSchemaVersionsById returns a Schema with all active versions. +// Returns registry.ErrNotFound in case there's no schema under the given id. +func (r *Repository) GetSchemaVersionsById(id string) (registry.Schema, error) { + var schema Schema + err := r.db.Preload("VersionDetails", "version_deactivated = ?", false).Take(&schema, id).Error + if errors.Is(err, gorm.ErrRecordNotFound) || len(schema.VersionDetails) == 0 { + return registry.Schema{}, registry.ErrNotFound + } + if err != nil { + return registry.Schema{}, err + } + return intoRegistrySchema(schema), nil +} + +// GetAllSchemaVersions returns a Schema with all versions. +// Returns registry.ErrNotFound in case there's no schema under the given id. +func (r *Repository) GetAllSchemaVersions(id string) (registry.Schema, error) { + var schema Schema + if err := r.db.Preload("VersionDetails").Take(&schema, id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return registry.Schema{}, registry.ErrNotFound + } + return registry.Schema{}, err + } + return intoRegistrySchema(schema), nil +} + +// GetLatestSchemaVersion returns the latest active version of selected schema. +// Returns registry.ErrNotFound in case there's no schema under the given id. +func (r *Repository) GetLatestSchemaVersion(id string) (registry.VersionDetails, error) { + var details VersionDetails + if err := r.db.Where("schema_id = ? and version_deactivated = ?", id, false).Last(&details).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return registry.VersionDetails{}, registry.ErrNotFound + } + return registry.VersionDetails{}, err + } + return intoRegistryVersionDetails(details), nil +} + +// GetSchemas returns all active Schema instances. +// Returns registry.ErrNotFound in case there's no schemas. +func (r *Repository) GetSchemas() ([]registry.Schema, error) { + var schemaList []Schema + // This query examines if there is at least one active version of the schema and based on that, it determines whether to retrieve the schema. + tx := r.db.Preload("VersionDetails", "version_deactivated = ?", false).Where("EXISTS (SELECT 1 FROM syntio_schema.version_details WHERE syntio_schema.version_details.schema_id = syntio_schema.schema.schema_id AND syntio_schema.version_details.version_deactivated = 'false')").Find(&schemaList) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, registry.ErrNotFound + } + + var registrySchemaList []registry.Schema + for _, schema := range schemaList { + registrySchemaList = append(registrySchemaList, intoRegistrySchema(schema)) + } + return registrySchemaList, nil +} + +// GetAllSchemas returns all Schema instances. +// Returns registry.ErrNotFound in case there's no schemas. +func (r *Repository) GetAllSchemas() ([]registry.Schema, error) { + var schemaList []Schema + tx := r.db.Preload("VersionDetails").Find(&schemaList) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, registry.ErrNotFound + } + + registrySchemaList := make([]registry.Schema, len(schemaList)) + for i, schema := range schemaList { + registrySchemaList[i] = intoRegistrySchema(schema) + } + return registrySchemaList, nil +} + +// CreateSchema inserts a new Schema structure. +// Returns a new VersionDetails structure and a bool flag indicating if a new version of schema was added or if it already existed. +func (r *Repository) CreateSchema(schemaRegisterRequest registry.SchemaRegistrationRequest) (registry.VersionDetails, bool, error) { + specification := []byte(schemaRegisterRequest.Specification) + hash := hashutils.SHA256(specification) + + // Prior to saving the schema in the database we must verify the distinctness of the schema hash and publisher ID. + // To accomplish this, we must join the "VersionDetails" and "Schema" tables on the columns that contain the schema ID, + // while also filtering the schemas with the specified schema hash and publisher ID. If the query does not return a schema, + // it means that a schema with the given criteria does not exist in the database and a new one needs to be created. + var schema Schema + if err := r.db.Table("syntio_schema.schema").Preload("VersionDetails", "schema_hash = ? and version_deactivated = ?", hash, false).Joins("JOIN syntio_schema.version_details ON syntio_schema.version_details.schema_id = syntio_schema.schema.schema_id AND syntio_schema.version_details.schema_hash = ? and syntio_schema.version_details.version_deactivated = ?", hash, false).Where("syntio_schema.schema.publisher_id = ?", schemaRegisterRequest.PublisherID).Take(&schema).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + schema := Schema{ + SchemaType: strings.ToLower(schemaRegisterRequest.SchemaType), + Name: schemaRegisterRequest.Name, + Description: schemaRegisterRequest.Description, + PublisherID: schemaRegisterRequest.PublisherID, + LastCreated: "1", + CompatibilityMode: schemaRegisterRequest.CompatibilityMode, + ValidityMode: schemaRegisterRequest.ValidityMode, + VersionDetails: []VersionDetails{ + { + Version: "1", + Specification: base64.StdEncoding.EncodeToString(specification), + Description: schemaRegisterRequest.Description, + SchemaHash: hash, + CreatedAt: time.Now(), + VersionDeactivated: false, + Attributes: schemaRegisterRequest.Attributes, + }, + }, + } + if err := r.db.Create(&schema).Error; err != nil { + return registry.VersionDetails{}, false, err + } + return intoRegistryVersionDetails(schema.VersionDetails[0]), true, nil + } + return registry.VersionDetails{}, false, err + } + + return intoRegistryVersionDetails(schema.VersionDetails[0]), false, nil +} + +// UpdateSchemaById updates the schema specification and description if sent. +// Returns the new VersionDetails and a flag indicating if a new version of schema was added. +func (r *Repository) UpdateSchemaById(id string, schemaUpdateRequest registry.SchemaUpdateRequest) (registry.VersionDetails, bool, error) { + schemaId, err := strconv.Atoi(id) + if err != nil { + return registry.VersionDetails{}, false, errors.Wrap(err, "wrong type of schemaID") + } + + specification := []byte(schemaUpdateRequest.Specification) + hash := hashutils.SHA256(specification) + + var details VersionDetails + if err = r.db.Where("schema_hash = ? and schema_id = ?", hash, id).Take(&details).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + updated := VersionDetails{} + err = r.db.Transaction(func(tx *gorm.DB) error { + + schema := &Schema{SchemaID: uint(schemaId)} + if err := tx.Select("last_created").Take(&schema).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return registry.ErrNotFound + } + return err + } + + lastCreated, err := strconv.Atoi(schema.LastCreated) + if err != nil { + return errors.Wrap(err, "wrong type of latest version") + } + incrementedLastCreated := strconv.Itoa(lastCreated + 1) + + updated = VersionDetails{ + Version: incrementedLastCreated, + Specification: base64.StdEncoding.EncodeToString(specification), + SchemaHash: hash, + Description: schemaUpdateRequest.Description, + Attributes: schemaUpdateRequest.Attributes, + } + + // append the new version to the VersionDetails array + if err = tx.Model(&schema).Association("VersionDetails").Append(&updated); err != nil { + return errors.Wrap(err, "could not update version details") + } + + // updating description and last_created values in schema table + if err = tx.Model(&schema).Updates(Schema{Description: schemaUpdateRequest.Description, LastCreated: incrementedLastCreated}).Error; err != nil { + return errors.Wrap(err, "could not update schema") + } + + return nil + }) + if err != nil { + return registry.VersionDetails{}, false, err + } + return intoRegistryVersionDetails(updated), true, nil + } + return registry.VersionDetails{}, false, err + } + + if details.VersionDeactivated { + //Activates already existing Schema + var schema Schema + if err := r.db.Take(&schema, id).Error; err != nil { + return registry.VersionDetails{}, false, err + } + lastCreated, err := strconv.Atoi(schema.LastCreated) + if err != nil { + return registry.VersionDetails{}, false, errors.Wrap(err, "wrong type of latest version") + } + incrementedLastCreated := strconv.Itoa(lastCreated + 1) + + // updating description and last_created values in schema table + if err = r.db.Model(&Schema{SchemaID: uint(schemaId)}).Updates(Schema{Description: schemaUpdateRequest.Description, LastCreated: incrementedLastCreated}).Error; err != nil { + return registry.VersionDetails{}, false, errors.Wrap(err, "could not update schema") + } + + // activating the schema version with a new creation time and version number + if err = r.db.Model(&details).Updates(map[string]interface{}{ + "created_at": time.Now(), + "version_deactivated": false, + "version": incrementedLastCreated, + }).Error; err != nil { + return registry.VersionDetails{}, false, errors.Wrap(err, "could not update version details") + } + + details.VersionDeactivated = false + return intoRegistryVersionDetails(details), true, nil + } + return intoRegistryVersionDetails(details), false, nil +} + +// DeleteSchema deactivates a schema. +// Returns a boolean flag indicating if a schema with the given id existed before this call. +func (r *Repository) DeleteSchema(id string) (bool, error) { + var schema Schema + if err := r.db.Preload("VersionDetails", "version_deactivated = ?", false).Take(&schema, id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return false, nil + } + return false, err + } + if len(schema.VersionDetails) == 0 { + return false, nil + } + // deactivation of all active versions + tx := r.db.Model(&schema.VersionDetails).Update("version_deactivated", true) + if tx.Error != nil { + return false, tx.Error + } + return tx.RowsAffected > 0, nil +} + +// DeleteSchemaVersion deactivates the specified schema version. +// Returns a boolean flag indicating if a schema with the given id and version existed before this call. +func (r *Repository) DeleteSchemaVersion(id, version string) (bool, error) { + var details VersionDetails + if err := r.db.Where("schema_id = ? and version = ? and version_deactivated = ?", id, version, false).Take(&details).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return false, nil + } + return false, err + } + + tx := r.db.Model(&details).Update("version_deactivated", true) + if tx.Error != nil { + return false, tx.Error + } + return tx.RowsAffected > 0, nil +} diff --git a/registry/registry/repository/postgres/postgres_test.go b/registry/registry/repository/postgres/postgres_test.go new file mode 100644 index 0000000..26b956d --- /dev/null +++ b/registry/registry/repository/postgres/postgres_test.go @@ -0,0 +1,54 @@ +package postgres + +import ( + "gorm.io/driver/postgres" + "gorm.io/gorm" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + + "github.com/dataphos/aquarium-janitor-standalone-sr/registry/internal/hashutils" +) + +func TestGetSchemaVersionByIdAndVersion(t *testing.T) { + // skip this test until it is not remodeled + t.Skip() + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("failed to create new sqlmock: %s", err) + } + + dialector := postgres.New(postgres.Config{ + DriverName: "postgres", + DSN: "sqlmock_db_1", + PreferSimpleProtocol: true, + Conn: db, + }) + gcfg := &gorm.Config{} + dbInstance, err := gorm.Open(dialector, gcfg) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + pdb := Repository{ + db: dbInstance, + } + resultRow := sqlmock.NewRows([]string{"version_id", "version", "schema_id", "specification", "description", "schema_hash", "created_at", "version_deactivated"}). + AddRow(1, "1", 1, "test_spec", "a description", "9f8f1a88fdc11bf262095a82a607a61086641ad8da16ab4b6e104dd32920d20f", time.Now(), false) + + mock.ExpectQuery(`SELECT * FROM "version_details" WHERE schema_id = $1 and version = $2 and version_deactivated = $3 LIMIT 1`). + WithArgs(1, "1", false). + WillReturnRows(resultRow) + + sd, err := pdb.GetSchemaVersionByIdAndVersion("1", "1") + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "1", sd.Version) + assert.Equal(t, "1", sd.SchemaID) + assert.Equal(t, hashutils.SHA256([]byte("test_spec")), sd.SchemaHash) +} diff --git a/registry/registry/schema.go b/registry/registry/schema.go new file mode 100644 index 0000000..b1f92cb --- /dev/null +++ b/registry/registry/schema.go @@ -0,0 +1,448 @@ +package registry + +import ( + "encoding/json" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" + "github.com/hamba/avro/v2" + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/compatibility" + "github.com/dataphos/aquarium-janitor-standalone-sr/validity" +) + +type Service struct { + Repository Repository + CompChecker compatibility.Checker + ValChecker validity.Checker + GlobalCompMode string + GlobalValMode string +} + +// Attribute search depth limit to prevent infinite recursion +const attSearchDepth = 10 + +const cacheSizeEnv = "CACHE_SIZE" +const defaultCacheSizeEnv = 0 + +type QueryParams struct { + Id string + Version string + SchemaType string + Name string + OrderBy string + Sort string + Limit int + Attributes []string +} + +func New(Repository Repository, CompChecker compatibility.Checker, ValChecker validity.Checker, GlobalCompMode, GlobalValMode string) *Service { + var size int + var err error + cacheSize := os.Getenv(cacheSizeEnv) + if cacheSize == "" { + size = defaultCacheSizeEnv + } else { + size, err = strconv.Atoi(cacheSize) + if err != nil { + log.Println("Cache size can not hold non-numeric data.") + return &Service{} + } + } + + if size > 0 { + log.Println("Using in-memory cache for repository") + Repository, err = WithCache(Repository, size) + if err != nil { + log.Println("Encountered error while trying to create cache.") + return &Service{} + } + } + + return &Service{ + Repository: Repository, + CompChecker: CompChecker, + ValChecker: ValChecker, + GlobalCompMode: GlobalCompMode, + GlobalValMode: GlobalValMode, + } +} + +// GetSchemaVersion gets the schema version with the specific id and version. +func (service *Service) GetSchemaVersion(id, version string) (VersionDetails, error) { + return service.Repository.GetSchemaVersionByIdAndVersion(id, version) +} + +// ListSchemaVersions lists all active schema versions of a specific schema. +func (service *Service) ListSchemaVersions(id string) (Schema, error) { + return service.Repository.GetSchemaVersionsById(id) +} + +// ListAllSchemaVersions lists all schema versions of a specific schema. +func (service *Service) ListAllSchemaVersions(id string) (Schema, error) { + return service.Repository.GetAllSchemaVersions(id) +} + +// GetLatestSchemaVersion gets the latest version of a certain schema. +func (service *Service) GetLatestSchemaVersion(id string) (VersionDetails, error) { + return service.Repository.GetLatestSchemaVersion(id) +} + +// GetSchemas gets all active schemas. +func (service *Service) GetSchemas() ([]Schema, error) { + return service.Repository.GetSchemas() +} + +// GetAllSchemas gets all schemas. +func (service *Service) GetAllSchemas() ([]Schema, error) { + return service.Repository.GetAllSchemas() +} + +// SearchSchemas gets filtered schemas. +func (service *Service) SearchSchemas(params QueryParams) ([]Schema, error) { + schemas, err := service.Repository.GetSchemas() + if err != nil { + return schemas, errors.Wrap(err, "couldn't retrieve schemas") + } + + var filteredSchemas []Schema + for _, schema := range schemas { + if params.Id != "" && schema.SchemaID != params.Id { + continue + } + if params.Name != "" && !strings.Contains(schema.Name, params.Name) { + continue + } + if params.SchemaType != "" && schema.SchemaType != params.SchemaType { + continue + } + + filteredVersions := Schema{ + SchemaID: schema.SchemaID, + SchemaType: schema.SchemaType, + Name: schema.Name, + Description: schema.Description, + LastCreated: schema.LastCreated, + PublisherID: schema.PublisherID, + CompatibilityMode: schema.CompatibilityMode, + ValidityMode: schema.ValidityMode, + } + for _, detail := range schema.VersionDetails { + if params.Version != "" && detail.Version != params.Version { + continue + } + if !containsAttributes(detail, params.Attributes) { + continue + } + filteredVersions.VersionDetails = append(filteredVersions.VersionDetails, detail) + } + if len(filteredVersions.VersionDetails) > 0 { + if params.OrderBy == "version" && len(filteredVersions.VersionDetails) > 1 { + if params.Sort == "asc" { + sort.Slice(filteredVersions.VersionDetails, func(i, j int) bool { + return filteredVersions.VersionDetails[i].Version < filteredVersions.VersionDetails[j].Version + }) + } else if params.Sort == "desc" { + sort.Slice(filteredVersions.VersionDetails, func(i, j int) bool { + return filteredVersions.VersionDetails[i].Version > filteredVersions.VersionDetails[j].Version + }) + } + } + filteredSchemas = append(filteredSchemas, filteredVersions) + } + } + + switch params.OrderBy { + case "name": + if params.Sort == "asc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + return filteredSchemas[i].Name < filteredSchemas[j].Name + }) + } else if params.Sort == "desc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + return filteredSchemas[i].Name > filteredSchemas[j].Name + }) + } + case "id": + if params.Sort == "asc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + l1, l2 := len(filteredSchemas[i].SchemaID), len(filteredSchemas[j].SchemaID) + if l1 != l2 { + return l1 < l2 + } + return filteredSchemas[i].SchemaID < filteredSchemas[j].SchemaID + }) + } else if params.Sort == "desc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + l1, l2 := len(filteredSchemas[i].SchemaID), len(filteredSchemas[j].SchemaID) + if l1 != l2 { + return l1 > l2 + } + return filteredSchemas[i].SchemaID > filteredSchemas[j].SchemaID + }) + } + case "type": + if params.Sort == "asc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + return filteredSchemas[i].SchemaType < filteredSchemas[j].SchemaType + }) + } else if params.Sort == "desc" { + sort.Slice(filteredSchemas, func(i, j int) bool { + return filteredSchemas[i].SchemaType > filteredSchemas[j].SchemaType + }) + } + } + + if params.Limit > 0 && params.Limit < len(filteredSchemas) { + filteredSchemas = filteredSchemas[:params.Limit] + } + return filteredSchemas, nil +} + +func containsAttributes(details VersionDetails, attributes []string) bool { + numMatched := 0 + for i, filterAtt := range attributes { + for _, att := range strings.FieldsFunc(details.Attributes, func(r rune) bool { return r == '/' || r == ',' }) { + if filterAtt == att { + numMatched += 1 + break + } + } + if numMatched != i+1 { + return false + } + } + return true +} + +// CreateSchema creates a new schema. +func (service *Service) CreateSchema(schemaRegisterRequest SchemaRegistrationRequest) (VersionDetails, bool, error) { + if !compatibility.CheckIfValidMode(&schemaRegisterRequest.CompatibilityMode) { + return VersionDetails{}, false, ErrUnknownComp + } + if !validity.CheckIfValidMode(&schemaRegisterRequest.ValidityMode) { + return VersionDetails{}, false, ErrUnknownVal + } + valid, err := service.CheckValidity(schemaRegisterRequest.SchemaType, schemaRegisterRequest.Specification, schemaRegisterRequest.ValidityMode) + if err != nil { + return VersionDetails{}, false, err + } + if !valid { + return VersionDetails{}, false, ErrNotValid + } + //cannot canonicalize schema that is invalid + if strings.ToLower(schemaRegisterRequest.ValidityMode) == "syntax-only" || strings.ToLower(schemaRegisterRequest.ValidityMode) == "full" { + canonicalSpec, err := canonicalizeSchema([]byte(schemaRegisterRequest.Specification), strings.ToLower(schemaRegisterRequest.SchemaType)) + if err != nil { + return VersionDetails{}, false, err + } + schemaRegisterRequest.Specification = canonicalSpec + } + + attributes, err := extractAttributes(schemaRegisterRequest.Specification, strings.ToLower(schemaRegisterRequest.SchemaType), attSearchDepth) + if err != nil { + return VersionDetails{}, false, errors.Wrap(err, "unable to extract attributes") + } + schemaRegisterRequest.Attributes = attributes + + return service.Repository.CreateSchema(schemaRegisterRequest) +} + +// canonicalizeSchema converts the given schema to its canonical form +func canonicalizeSchema(specification []byte, schemaType string) (string, error) { + switch schemaType { + case "json": + var canonicalSpec []byte + var schema map[string]interface{} + err := json.Unmarshal(specification, &schema) + if err != nil { + return "", err + } + + required, ok := schema["required"].([]interface{}) + if ok { + sort.Slice(required, func(i, j int) bool { + return required[i].(string) < required[j].(string) + }) + schema["required"] = required + specification, err = json.Marshal(schema) + if err != nil { + return "", err + } + } + + canonicalSpec, err = jsoncanonicalizer.Transform(specification) + if err != nil { + return "", err + } + return strings.TrimSpace(string(canonicalSpec)), nil + case "avro": + schema, err := avro.Parse(string(specification)) + if err != nil { + return "", err + } + return strings.TrimSpace(schema.String()), nil + default: + return strings.TrimSpace(string(specification)), nil + } +} + +func extractAttributes(specification string, schemaType string, maxDepth int) (string, error) { + switch schemaType { + case "json": + var schema map[string]interface{} + err := json.Unmarshal([]byte(specification), &schema) + if err != nil { + return "", errors.Wrap(err, "couldn't unmarshal schema") + } + + flatSchema := make(map[string]interface{}) + err = flattenJSON("", schema, flatSchema, 0, maxDepth, "/") + if err != nil { + return "", errors.Wrap(err, "unable to flatten json schema") + } + + var allAttributes string + for _, att := range reflect.ValueOf(flatSchema).MapKeys() { + allAttributes += att.String() + "," + } + + if len(allAttributes) > 0 { + return allAttributes[:len(allAttributes)-1], nil + } else { + return "", nil + } + default: + return "", nil + } +} + +func flattenJSON(prefix string, nested interface{}, flat map[string]interface{}, currentDepth int, maxDepth int, delimiter string) error { + if currentDepth >= maxDepth { + flat[prefix] = nested + return nil + } + + switch nested.(type) { + case map[string]interface{}: + for k, v := range nested.(map[string]interface{}) { + newKey := k + if currentDepth == 0 && strings.ToLower(newKey) != "properties" { + continue + } + if currentDepth != 0 { + newKey = prefix + delimiter + newKey + } + err := flattenJSON(newKey, v, flat, currentDepth+1, maxDepth, delimiter) + if err != nil { + return err + } + } + case []interface{}: + for i, v := range nested.([]interface{}) { + newKey := strconv.Itoa(i) + if currentDepth != 0 { + newKey = prefix + delimiter + newKey + } + err := flattenJSON(newKey, v, flat, currentDepth+1, maxDepth, delimiter) + if err != nil { + return err + } + } + default: + flat[prefix] = nested + } + return nil +} + +// UpdateSchema updates the schemas by assigning a new version to it. +func (service *Service) UpdateSchema(id string, schemaUpdateRequest SchemaUpdateRequest) (VersionDetails, bool, error) { + schemas, err := service.ListSchemaVersions(id) + if err != nil { + return VersionDetails{}, false, err + } + + valid, err := service.CheckValidity(schemas.SchemaType, schemaUpdateRequest.Specification, schemas.ValidityMode) + if err != nil { + return VersionDetails{}, false, err + } + if !valid { + return VersionDetails{}, false, ErrNotValid + } + + compatible, err := service.CheckCompatibility(schemaUpdateRequest.Specification, id) + if err != nil { + return VersionDetails{}, false, err + } + if !compatible { + return VersionDetails{}, false, ErrNotComp + } + if strings.ToLower(schemas.ValidityMode) == "syntax-only" || strings.ToLower(schemas.ValidityMode) == "full" { + canonicalSpec, err := canonicalizeSchema([]byte(schemaUpdateRequest.Specification), strings.ToLower(schemas.SchemaType)) + if err != nil { + return VersionDetails{}, false, err + } + schemaUpdateRequest.Specification = canonicalSpec + + } + + attributes, err := extractAttributes(schemaUpdateRequest.Specification, schemas.SchemaType, attSearchDepth) + if err != nil { + return VersionDetails{}, false, errors.Wrap(err, "unable to extract attributes") + } + schemaUpdateRequest.Attributes = attributes + + return service.Repository.UpdateSchemaById(id, schemaUpdateRequest) +} + +// DeleteSchema deletes the schema and its versions. +func (service *Service) DeleteSchema(id string) (bool, error) { + return service.Repository.DeleteSchema(id) +} + +// DeleteSchemaVersion deletes a specific version of a schema. +func (service *Service) DeleteSchemaVersion(id, version string) (bool, error) { + return service.Repository.DeleteSchemaVersion(id, version) +} + +// CheckCompatibility checks if schemas are compatible +func (service *Service) CheckCompatibility(newSchema, id string) (bool, error) { + schemas, err := service.ListSchemaVersions(id) + if err != nil { + return false, err + } + + jsonAttrs := make(map[string]string) + jsonAttrs["id"] = id + jsonAttrs["format"] = schemas.SchemaType + jsonAttrs["schema"] = newSchema + jsonMessage, err := json.Marshal(jsonAttrs) + if err != nil { + return false, err + } + + var stringHistory []string + for _, el := range schemas.VersionDetails { + stringHistory = append(stringHistory, el.Specification) + } + mode := schemas.CompatibilityMode + if schemas.CompatibilityMode == "" { + mode = service.GlobalCompMode + } + + return service.CompChecker.Check(string(jsonMessage), stringHistory, mode) +} + +// CheckValidity checks if a schema is valid +func (service *Service) CheckValidity(schemaType, newSchema, mode string) (bool, error) { + if mode == "" { + mode = service.GlobalValMode + } + return service.ValChecker.Check(newSchema, schemaType, mode) +} diff --git a/registry/registry/schema_test.go b/registry/registry/schema_test.go new file mode 100644 index 0000000..ed68e62 --- /dev/null +++ b/registry/registry/schema_test.go @@ -0,0 +1,116 @@ +package registry + +import ( + "testing" +) + +func Test_DeleteSchema(t *testing.T) { + repo := NewMockRepository() + repo.SetGetSchemaVersionsByIdResponse("mocking", MockSchema("mocking"), nil) + deleted, err := (*Service).DeleteSchema(New(repo, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking") + if err != nil { + t.Errorf("returned error") + } + if !deleted { + t.Errorf("deleted returned false") + } +} + +func Test_DeleteSchemaVersion(t *testing.T) { + deleted, err := (*Service).DeleteSchemaVersion(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking", "mocking") + if err != nil { + t.Errorf("returned error") + } + if !deleted { + t.Errorf("deleted returned false") + } +} + +func Test_GetAllSchemas(t *testing.T) { + schemas, _ := (*Service).GetAllSchemas(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none")) + if schemas[0].SchemaID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_GetSchemas(t *testing.T) { + schemas, _ := (*Service).GetAllSchemas(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none")) + if schemas[0].SchemaID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_GetLatestSchemaVersion(t *testing.T) { + VersionDetails, _ := (*Service).GetLatestSchemaVersion(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking") + if VersionDetails.VersionID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_CreateSchema(t *testing.T) { + sdto := SchemaRegistrationRequest{ + Description: "mocking", + Specification: "mocking", + Name: "mocking", + SchemaType: "mocking", + PublisherID: "mocking", + ValidityMode: "none", + CompatibilityMode: "none", + } + VersionDetails, added, err := (*Service).CreateSchema(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none"), sdto) + if err != nil { + t.Errorf("returned error") + } + + if !added { + t.Errorf("could not add schema") + } + + if VersionDetails.SchemaID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_GetSchemaVersion(t *testing.T) { + VersionDetails, _ := (*Service).GetSchemaVersion(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking", "mocking") + if VersionDetails.SchemaID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_UpdateSchema(t *testing.T) { + sdto := SchemaUpdateRequest{ + Description: "mocking", + Specification: "mocking", + } + VersionDetails, added, err := (*Service).UpdateSchema(New(&mockRepository{}, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking", sdto) + if err != nil { + t.Errorf("returned error") + } + + if !added { + t.Errorf("could not add schema") + } + + if VersionDetails.SchemaID != "mocking" { + t.Errorf("wrong schemaId returned") + } +} + +func Test_GetSchemaVersionsById(t *testing.T) { + repo := NewMockRepository() + repo.SetGetSchemaVersionsByIdResponse("mocking", MockSchema("mocking"), nil) + schema, _ := (*Service).ListSchemaVersions(New(repo, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking") + if schema.SchemaID != "mocking" { + t.Errorf("wrong schema ID returned") + } +} + +func Test_GetAllSchemaVersions(t *testing.T) { + repo := NewMockRepository() + repo.SetGetSchemaVersionsByIdResponse("mocking", MockSchema("mocking"), nil) + schema, _ := (*Service).ListAllSchemaVersions(New(repo, &mockCompChecker{}, &mockValChecker{}, "none", "none"), "mocking") + if schema.SchemaID != "mocking" { + t.Errorf("wrong schema ID returned") + } +} diff --git a/registry/registry/testdata/avro/canonical-schema.avsc b/registry/registry/testdata/avro/canonical-schema.avsc new file mode 100644 index 0000000..82a6082 --- /dev/null +++ b/registry/registry/testdata/avro/canonical-schema.avsc @@ -0,0 +1 @@ +{"name":"my.example.userInfo","type":"record","fields":[{"name":"username","type":"string"},{"name":"age","type":"int"},{"name":"phone","type":"string"},{"name":"housenum","type":"string"},{"name":"address","type":{"name":"my.example.mailing_address","type":"record","fields":[{"name":"street","type":"string"},{"name":"city","type":"string"},{"name":"state_prov","type":"string"},{"name":"country","type":"string"},{"name":"zip","type":"string"}]}}]} diff --git a/registry/registry/testdata/avro/schema-1.avsc b/registry/registry/testdata/avro/schema-1.avsc new file mode 100644 index 0000000..aa47589 --- /dev/null +++ b/registry/registry/testdata/avro/schema-1.avsc @@ -0,0 +1,48 @@ +{ + "namespace" : "my.example", + "name" : "userInfo", + "type" : "record", + "fields" : [{"name" : "username", + "type" : "string", + "default" : "NONE"}, + + {"name" : "age", + "type" : "int", + "default" : -1}, + + {"name" : "phone", + "type" : "string", + "default" : "NONE"}, + + {"name" : "housenum", + "type" : "string", + "default" : "NONE"}, + + {"name" : "address", + "type" : { + "type" : "record", + "name" : "mailing_address", + "fields" : [ + {"name" : "street", + "type" : "string", + "default" : "NONE"}, + + {"name" : "city", + "type" : "string", + "default" : "NONE"}, + + {"name" : "state_prov", + "type" : "string", + "default" : "NONE"}, + + {"name" : "country", + "type" : "string", + "default" : "NONE"}, + + {"name" : "zip", + "type" : "string", + "default" : "NONE"} + ]} + } + ] +} diff --git a/registry/registry/testdata/avro/schema-2.avsc b/registry/registry/testdata/avro/schema-2.avsc new file mode 100644 index 0000000..9815163 --- /dev/null +++ b/registry/registry/testdata/avro/schema-2.avsc @@ -0,0 +1,39 @@ +{ + "name" : "my.example.userInfo", + "type" : "record", + "fields" : [{"name" : "username", + "type" : "string"}, + + {"name" : "age", + "type" : "int", + "default" : -1}, + + {"name" : "phone", + "type" : "string"}, + + {"name" : "housenum", + "type" : "string"}, + + {"name" : "address", + "type" : { + "type" : "record", + "name" : "my.example.mailing_address", + "fields" : [ + {"name" : "street", + "type" : "string"}, + + {"name" : "city", + "type" : "string"}, + + {"name" : "state_prov", + "type" : "string"}, + + {"name" : "country", + "type" : "string"}, + + {"name" : "zip", + "type" : "string"} + ]} + } + ] +} diff --git a/registry/registry/testdata/json/canonical-schema.json b/registry/registry/testdata/json/canonical-schema.json new file mode 100644 index 0000000..19a6998 --- /dev/null +++ b/registry/registry/testdata/json/canonical-schema.json @@ -0,0 +1 @@ +{"$schema":"http://json-schema.org/draft-080/schema","additionalProperties":true,"default":{},"description":"The root schema comprises the entire JSON document.","properties":{"phone":{"default":"","description":"An explanation about the purpose of this instance.","examples":[23541],"title":"The Phone Schema","type":"integer"},"room":{"default":"","description":"An explanation about the purpose of this instance.","examples":[18],"title":"The Room Schema","type":"integer"}},"required":["phone","room"],"title222":"The Root Schema","type":"object"} diff --git a/registry/registry/testdata/json/schema-1.json b/registry/registry/testdata/json/schema-1.json new file mode 100644 index 0000000..76baca2 --- /dev/null +++ b/registry/registry/testdata/json/schema-1.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-080/schema", + "type": "object", + "title222": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": true, + "required": [ + "phone", + "room" + ], + "properties": { + "phone": { + "type": "integer", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + 23541 + ] + }, + "room": { + "type": "integer", + "title": "The Room Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + 18 + ] + } + } +} diff --git a/registry/registry/testdata/json/schema-2.json b/registry/registry/testdata/json/schema-2.json new file mode 100644 index 0000000..58e18ee --- /dev/null +++ b/registry/registry/testdata/json/schema-2.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-080/schema", + "type": "object", + "title222": "The Root Schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "additionalProperties": true, + "required": [ + "room", + "phone" + ], + "properties": { + "phone": { + "type": "integer", + "title": "The Phone Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + 23541 + ] + }, + "room": { + "type": "integer", + "title": "The Room Schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + 18 + ] + } + } +} diff --git a/registry/server/handler.go b/registry/server/handler.go new file mode 100644 index 0000000..f4b0ef6 --- /dev/null +++ b/registry/server/handler.go @@ -0,0 +1,887 @@ +package server + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "strconv" + "strings" + + "github.com/go-chi/chi/v5" + "github.com/pkg/errors" + + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/metrics" + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" + "github.com/dataphos/lib-logger/logger" +) + +type Handler struct { + Service *registry.Service + log logger.Log +} + +// report is a simple wrapper of the system's message for the user. +type report struct { + Message string `json:"message"` +} + +// insertInfo represents a schema registry/evolution response for methods other than GET. +type insertInfo struct { + Id string `json:"identification"` + Version string `json:"version"` + Message string `json:"message"` +} + +// NewHandler is a convenience function which returns a new instance of Handler. +func NewHandler(Service *registry.Service, log logger.Log) *Handler { + return &Handler{ + Service: Service, + log: log, + } +} + +// GetSchemaVersionByIdAndVersion is a GET method that expects parameters "id" and "version" for +// retrieving the schema version from the underlying repository. +// +// It currently writes back either: +// - status 200 with a schema version in JSON format, if the schema is registered and active +// - status 404 with error message, if the schema version is not registered or registered but deactivated +// - status 500 with error message, if an internal server error occurred +// +// @Title Get schema version by schema id and version +// @Summary Get schema version by schema id and version +// @Produce json +// @Param id path string true "schema id" +// @Param version path string true "version" +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/{id}/versions/{version} [get] +func (h Handler) GetSchemaVersionByIdAndVersion(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + version := chi.URLParam(r, "version") + + details, err := h.Service.GetSchemaVersion(id, version) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: fmt.Sprintf("Schema with id=%v and version=%v is not registered", id, version), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(details) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetSpecificationByIdAndVersion is a GET method that expects parameters "id" and "version" for +// retrieving the specification of schema version from the underlying repository. +// +// It currently writes back either: +// - status 200 with a schema in JSON format, if the schema version is registered and active +// - status 404 with error message, if the schema version is not registered or registered but deactivated +// - status 500 with error message, if an internal server error occurred +// +// @Title Get schema specification by schema id and version +// @Summary Get schema specification by schema id and version +// @Produce json +// @Param id path string true "schema id" +// @Param version path string true "version" +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/{id}/versions/{version}/spec [get] +func (h Handler) GetSpecificationByIdAndVersion(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + version := chi.URLParam(r, "version") + + details, err := h.Service.GetSchemaVersion(id, version) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: fmt.Sprintf("Schema with id=%v and version=%v is not registered", id, version), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + specification, err := base64.StdEncoding.DecodeString(details.Specification) + if err != nil { + log.Println(err) + } + + body, _ := json.Marshal(specification) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetSchemaVersionsById is a GET method that expects "id" of the wanted schema and returns all active versions of the schema +// +// It currently gives the following responses: +// - status 200 for a successful invocation along with an instance of the schema structure +// - status 404 if there is no registered or active schema version under the given id +// - status 500 with error message, if an internal server error occurred +// +// @Title Get all active schema versions by schema id +// @Summary Get all active schema versions by schema id +// @Produce json +// @Param id path string true "schema id" +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/{id}/versions [get] +func (h Handler) GetSchemaVersionsById(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + + schemas, err := h.Service.ListSchemaVersions(id) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(schemas) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetAllSchemaVersionsById is a GET method that expects "id" of the wanted schema and returns all versions of the schema +// +// It currently gives the following responses: +// - status 200 for a successful invocation along with an instance of the schema structure +// - status 404 if there is no registered schema version under the given id +// - status 500 with error message, if an internal server error occurred +// +// @Title Get schema by schema id +// @Summary Get schema by schema id +// @Produce json +// @Param id path string true "schema id" +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/{id}/versions/all [get] +func (h Handler) GetAllSchemaVersionsById(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + + schemas, err := h.Service.ListAllSchemaVersions(id) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: fmt.Sprintf("Schema with id=%v is not registered", id), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(schemas) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetLatestSchemaVersionById is a GET method that expects "id" of the wanted schema and returns +// the latest versions of the schema +// +// It currently gives the following responses: +// - status 200 with the latest schema version in JSON format, if the schema is registered +// - status 404 if there is no registered or active schema under the given id +// - status 500 with error message, if an internal server error occurred +// +// @Title Get the latest schema version by schema id +// @Summary Get the latest schema version by schema id +// @Produce json +// @Param id path string true "schema id" +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/{id}/versions/latest [get] +func (h Handler) GetLatestSchemaVersionById(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + + details, err := h.Service.GetLatestSchemaVersion(id) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: fmt.Sprintf("Schema with id=%v is not registered", id), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(details) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetAllSchemas is a GET method that retrieves all schemas +// +// It currently writes back either: +// - status 200 with all schemas in JSON format +// - status 404 with error message if there are no registered schemas +// - status 500 with error message, if an internal server error occurred +// +// @Title Get all schemas +// @Summary Get all schemas +// @Produce json +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas/all [get] +func (h Handler) GetAllSchemas(w http.ResponseWriter, _ *http.Request) { + schemas, err := h.Service.GetAllSchemas() + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: "There are no schemas in Registry", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(schemas) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// GetSchemas is a GET method that retrieves all active schemas +// +// It currently writes back either: +// - status 200 with active schemas in JSON format +// - status 404 with error message if there are no active schemas +// - status 500 with error message, if an internal server error occurred +// +// @Title Get all active schemas +// @Summary Get all active schemas +// @Produce json +// @Success 200 +// @Failure 404 +// @Failure 500 +// @Router /schemas [get] +func (h Handler) GetSchemas(w http.ResponseWriter, _ *http.Request) { + schemas, err := h.Service.GetSchemas() + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + body, _ := json.Marshal(schemas) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// SearchSchemas is a GET method that expects one of the following parameters: id, version, type, name, orderBy, +// sort, limit and gets schemas that match given filter criteria +// +// It currently writes back either: +// - status 200 with filtered schemas in JSON format +// - status 400 with error message, if a bad search query was given +// - status 404 with error message, if there is no schema that matches the given search criteria +// - status 500 with error message, if an internal server error occurred +// +// @Title Search schemas +// @Summary Search schemas +// @Produce json +// @Param id query string false "schema id" +// @Param version query string false "schema version" +// @Param type query string false "schema type" +// @Param name query string false "schema name" +// @Param orderBy query string false "order by name, type, id or version" +// @Param sort query string false "sort schemas either asc or desc" +// @Param limit query string false "maximum number of retrieved schemas matching the criteria" +// @Param attributes query string false "schema attributes" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /schemas/search [get] +func (h Handler) SearchSchemas(w http.ResponseWriter, r *http.Request) { + id := r.URL.Query().Get("id") + version := r.URL.Query().Get("version") + schemaType := r.URL.Query().Get("type") + name := r.URL.Query().Get("name") + orderBy := r.URL.Query().Get("orderBy") + sort := r.URL.Query().Get("sort") + + if orderBy == "" && sort != "" { + orderBy = "id" + } else if orderBy != "" && orderBy != "name" && orderBy != "id" && orderBy != "type" && orderBy != "version" { + body, _ := json.Marshal(report{ + Message: "Bad request: unknown value for orderBy", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + if sort == "" && orderBy != "" { + sort = "asc" + } else if sort != "" && sort != "asc" && sort != "desc" { + body, _ := json.Marshal(report{ + Message: "Bad request: unknown value for sort", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + limitStr := r.URL.Query().Get("limit") + limit := 0 + var err error + if limitStr != "" { + limit, err = strconv.Atoi(limitStr) + if err != nil { + body, _ := json.Marshal(report{ + Message: "Bad request: limit must be integer", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + } + + var attributes []string + if r.URL.Query().Get("attributes") != "" { + attributes = strings.Split(r.URL.Query().Get("attributes"), ",") + } + + queryParams := registry.QueryParams{ + Id: id, + Version: version, + SchemaType: schemaType, + Name: name, + OrderBy: orderBy, + Sort: sort, + Limit: limit, + Attributes: attributes, + } + + schemas, err := h.Service.SearchSchemas(queryParams) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + if schemas == nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + + body, _ := json.Marshal(schemas) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +// PostSchema is a POST function that registers the received schema to the underlying repository. +// +// The expected input schema JSON should contain following fields: +// - Description string +// - Specification string +// - Name string +// - SchemaType string +// - LastCreated string +// - PublisherID string +// - CompatibilityMode string +// - ValidityMode string +// +// It currently writes back either: +// - status 201 with newly created version details in JSON format +// - status 400 with error message, if the schema isn't valid or the values for validity and/or compatibility mode are missing +// - status 409 with error message, if the schema already exists +// - status 500 with error message, if an internal server error occurred +// +// In case of correct invocation the function writes back a JSON with fields: +// - Identification int64 +// - Version int32 +// - Message string +// +// @Title Post new schema +// @Summary Post new schema +// @Accept json +// @Produce json +// @Param data body registry.SchemaRegistrationRequest false "schema registration request" +// @Success 201 +// @Failure 400 +// @Failure 409 +// @Failure 500 +// @Router /schemas [post] +func (h Handler) PostSchema(w http.ResponseWriter, r *http.Request) { + registerRequest, err := readSchemaRegisterRequest(r.Body) + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + details, added, err := h.Service.CreateSchema(registerRequest) + if err != nil { + if errors.Is(err, registry.ErrUnknownComp) { + body, _ := json.Marshal(report{ + Message: "Bad request: unknown value for compatibility_mode", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + if errors.Is(err, registry.ErrUnknownVal) { + body, _ := json.Marshal(report{ + Message: "Bad request: unknown value for validity_mode", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + if errors.Is(err, registry.ErrNotValid) { + body, _ := json.Marshal(report{ + Message: "Schema is not valid", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + if !added { + body, _ := json.Marshal(insertInfo{ + Id: details.SchemaID, + Version: details.Version, + Message: fmt.Sprintf("Schema already exists at id=%v", details.SchemaID), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusConflict, + }) + return + } + + body, _ := json.Marshal(insertInfo{ + Id: details.SchemaID, + Version: details.Version, + Message: "Schema successfully created", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusCreated, + }) + metrics.AddedSchemaMetricUpdate(details.SchemaID, details.Version) +} + +// PutSchema registers a new schema version in the Schema Registry. The new version is connected to other schemas +// by schema id from the request URL. +// The expected input schema JSON should contain the following field: +// - Specification string +// The input can also include the following field: +// - Description string +// +// It currently writes back either: +// - status 200 with updated version details in JSON format +// - status 400 with error message, if the schemas aren't compatible +// - status 404 if there is no registered or active schema version under the given id +// - status 409 with error message, if the schema already exists +// - status 500 with error message, if an internal server error occurred +// +// In case of correct invocation the function writes back a JSON with fields: +// - Identification int64 +// - Version int32 +// - Message string +// +// In case of a bad invocation, it only returns the message. +// @Title Put new schema version +// @Summary Put new schema version +// @Accept json +// @Produce json +// @Param id path string true "schema id" +// @Param data body registry.SchemaUpdateRequest true "schema update request" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Failure 409 +// @Failure 500 +// @Router /schemas/{id} [put] +func (h Handler) PutSchema(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + + updateRequest, err := readSchemaUpdateRequest(r.Body) + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + details, updated, err := h.Service.UpdateSchema(id, updateRequest) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + body, _ := json.Marshal(report{ + Message: fmt.Sprintf("Schema with id=%v doesn't exist", id), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + if errors.Is(err, registry.ErrNotComp) { + body, _ := json.Marshal(report{ + Message: "Schemas are not compatible", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusBadRequest, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + if !updated { + body, _ := json.Marshal(insertInfo{ + Id: details.SchemaID, + Version: details.Version, + Message: fmt.Sprintf("Schema already exists at id=%s", details.SchemaID), + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusConflict, + }) + return + } + + body, _ := json.Marshal(insertInfo{ + Id: details.SchemaID, + Version: details.Version, + Message: "Schema successfully updated", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) + metrics.UpdateSchemaMetricUpdate(details.SchemaID, details.Version) +} + +// DeleteSchema is a DELETE method that deactivates a schema. +// It expects the "id" of the wanted schema +// +// It currently gives the following responses: +// - status 200 for a successful invocation along with an instance of the schema structure +// - status 400 if the deletion caused an error +// - status 404 if the schema does not exist or is already deactivated +// +// @Title Delete schema by schema id +// @Summary Delete schema by schema id +// @Produce json +// @Param id path string true "schema id" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Router /schemas/{id} [delete] +func (h Handler) DeleteSchema(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + + deleted, err := h.Service.DeleteSchema(id) + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + if !deleted { + body, _ := json.Marshal(report{Message: fmt.Sprintf("Schema with id=%s doesn't exist", id)}) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + body, _ := json.Marshal(report{Message: fmt.Sprintf("Schema with id=%s successfully deleted", id)}) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) + metrics.DeletedSchemaMetricUpdate(id) +} + +// DeleteSchemaVersion is a DELETE method that deletes a schema version. +// It expects the "id" and "version" of the wanted schema +// +// It currently gives the following responses: +// - status 200 for a successful invocation along with an instance of the schema structure +// - status 400 if the deletion caused an error +// - status 404 if the schema version does not exist or is already deactivated +// +// @Title Delete schema version by schema id and version +// @Summary Delete schema version by schema id and version +// @Accept json +// @Produce json +// @Param id path string true "schema id" +// @Param version path string true "version" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Router /schemas/{id}/versions/{version} [delete] +func (h Handler) DeleteSchemaVersion(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + version := chi.URLParam(r, "version") + + deleted, err := h.Service.DeleteSchemaVersion(id, version) + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + if !deleted { + body, _ := json.Marshal(report{Message: fmt.Sprintf("Schema with id=%s and version=%s doesn't exist", id, version)}) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusNotFound, + }) + return + } + + body, _ := json.Marshal(report{Message: fmt.Sprintf("Schema with id=%s and version=%s successfully deleted", id, version)}) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) + metrics.DeleteSchemaVersionMetricUpdate(id, version) +} + +// HealthCheck is a GET method that gives the response status 200 to signalize +// that the Schema Registry component is up and running. +func (h Handler) HealthCheck(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h Handler) SchemaCompatibility(w http.ResponseWriter, r *http.Request) { + compRequest, err := readSchemaCompatibilityRequest(r.Body) + + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + log.Println(fmt.Errorf("couldn't close request body")) + return + } + }(r.Body) + + compatible, err := h.Service.CheckCompatibility(compRequest.SchemaID, compRequest.NewSchema) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + if !compatible { + body, _ := json.Marshal(insertInfo{ + Message: "Schemas are not compatible", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusConflict, + }) + return + } + + body, _ := json.Marshal(compatible) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} + +func (h Handler) SchemaValidity(w http.ResponseWriter, r *http.Request) { + valRequest, err := readSchemaValidityRequest(r.Body) + if err != nil { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusBadRequest)), + Code: http.StatusBadRequest, + }) + return + } + + valid, err := h.Service.CheckValidity(valRequest.Format, valRequest.NewSchema, valRequest.Mode) + if err != nil { + if errors.Is(err, registry.ErrNotFound) { + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusNotFound)), + Code: http.StatusNotFound, + }) + return + } + + writeResponse(w, responseBodyAndCode{ + Body: serializeErrorMessage(http.StatusText(http.StatusInternalServerError)), + Code: http.StatusInternalServerError, + }) + return + } + + if !valid { + body, _ := json.Marshal(insertInfo{ + Message: "Schema is not valid", + }) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusConflict, + }) + return + } + + body, _ := json.Marshal(valid) + writeResponse(w, responseBodyAndCode{ + Body: body, + Code: http.StatusOK, + }) +} diff --git a/registry/server/log.go b/registry/server/log.go new file mode 100644 index 0000000..157f95c --- /dev/null +++ b/registry/server/log.go @@ -0,0 +1,44 @@ +package server + +import ( + "net/http" + "strconv" + "time" + + "github.com/go-chi/chi/v5/middleware" + + "github.com/dataphos/aquarium-janitor-standalone-sr/internal/errcodes" + "github.com/dataphos/lib-logger/logger" +) + +func RequestLogger(log logger.Log) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) + + t1 := time.Now() + defer func() { + fields := logger.F{ + "method": r.Method, + "path": r.URL.Path, + "remote_adrr": r.RemoteAddr, + "status": strconv.Itoa(ww.Status()), + "content_length": strconv.FormatInt(r.ContentLength, 10), + "bytes": strconv.Itoa(ww.BytesWritten()), + "response_time": strconv.FormatInt(time.Since(t1).Milliseconds(), 10), + } + + status := ww.Status() + if status >= 100 && status < 400 { + log.Infow("request completed", fields) + } else { + log.Errorw("request not completed successfully", errcodes.FromHttpStatusCode(status), fields) + } + }() + + next.ServeHTTP(ww, r) + } + + return http.HandlerFunc(fn) + } +} diff --git a/registry/server/server.go b/registry/server/server.go new file mode 100644 index 0000000..f1d3133 --- /dev/null +++ b/registry/server/server.go @@ -0,0 +1,66 @@ +// Package server contains the Schema registry REST Server configuration and start-up functions. +package server + +import ( + httpSwagger "github.com/swaggo/http-swagger" + "net/http" + "time" + + _ "github.com/dataphos/aquarium-janitor-standalone-sr/docs" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +// New sets up the schema registry endpoints. +func New(h *Handler) http.Handler { + router := chi.NewRouter() + + router.Use(middleware.StripSlashes) + router.Use(middleware.RealIP) + router.Use(middleware.Recoverer) + router.Use(middleware.Timeout(30 * time.Second)) + + router.Use(RequestLogger(h.log)) + + router.Route("/schemas", func(router chi.Router) { + router.Get("/", h.GetSchemas) + router.Post("/", h.PostSchema) + router.Get("/all", h.GetAllSchemas) + + router.Route("/{id}", func(router chi.Router) { + router.Delete("/", h.DeleteSchema) + router.Put("/", h.PutSchema) + + router.Route("/versions", func(router chi.Router) { + router.Get("/", h.GetSchemaVersionsById) + router.Get("/latest", h.GetLatestSchemaVersionById) + router.Get("/all", h.GetAllSchemaVersionsById) + + router.Route("/{version}", func(router chi.Router) { + router.Get("/", h.GetSchemaVersionByIdAndVersion) + router.Delete("/", h.DeleteSchemaVersion) + + router.Route("/spec", func(router chi.Router) { + router.Get("/", h.GetSpecificationByIdAndVersion) + }) + }) + }) + }) + + router.Get("/search", h.SearchSchemas) + }) + + router.Get("/health", h.HealthCheck) + + router.Post("/check/compatibility", h.SchemaCompatibility) + router.Get("/check/compatibility/health", h.HealthCheck) + + router.Post("/check/validity", h.SchemaValidity) + router.Get("/check/validity/health", h.HealthCheck) + + router.Get("/swagger/*", httpSwagger.Handler( + httpSwagger.URL("http://localhost:8080/swagger/doc.json"), //The url pointing to API definition + )) + + return router +} diff --git a/registry/server/util.go b/registry/server/util.go new file mode 100644 index 0000000..c441c46 --- /dev/null +++ b/registry/server/util.go @@ -0,0 +1,81 @@ +package server + +import ( + "encoding/json" + "io" + "net/http" + + "github.com/dataphos/aquarium-janitor-standalone-sr/registry" +) + +type responseBodyAndCode struct { + Body []byte + Code int +} + +func writeResponse(w http.ResponseWriter, response responseBodyAndCode) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.Code) + _, _ = w.Write(response.Body) +} + +func serializeErrorMessage(message string) []byte { + encoded, _ := json.Marshal(report{Message: message}) + return encoded +} + +func readSchemaRegisterRequest(body io.ReadCloser) (registry.SchemaRegistrationRequest, error) { + encoded, err := io.ReadAll(body) + if err != nil { + return registry.SchemaRegistrationRequest{}, err + } + + var schemaRegisterRequest registry.SchemaRegistrationRequest + if err = json.Unmarshal(encoded, &schemaRegisterRequest); err != nil { + return registry.SchemaRegistrationRequest{}, err + } + + return schemaRegisterRequest, nil +} + +func readSchemaUpdateRequest(body io.ReadCloser) (registry.SchemaUpdateRequest, error) { + encoded, err := io.ReadAll(body) + if err != nil { + return registry.SchemaUpdateRequest{}, err + } + + var schemaUpdateRequest registry.SchemaUpdateRequest + if err = json.Unmarshal(encoded, &schemaUpdateRequest); err != nil { + return registry.SchemaUpdateRequest{}, err + } + + return schemaUpdateRequest, nil +} + +func readSchemaCompatibilityRequest(body io.ReadCloser) (registry.SchemaCompatibilityRequest, error) { + encoded, err := io.ReadAll(body) + if err != nil { + return registry.SchemaCompatibilityRequest{}, err + } + + var schemaCompatibilityRequest registry.SchemaCompatibilityRequest + if err = json.Unmarshal(encoded, &schemaCompatibilityRequest); err != nil { + return registry.SchemaCompatibilityRequest{}, err + } + + return schemaCompatibilityRequest, nil +} + +func readSchemaValidityRequest(body io.ReadCloser) (registry.SchemaValidityRequest, error) { + encoded, err := io.ReadAll(body) + if err != nil { + return registry.SchemaValidityRequest{}, err + } + + var schemaValidityRequest registry.SchemaValidityRequest + if err = json.Unmarshal(encoded, &schemaValidityRequest); err != nil { + return registry.SchemaValidityRequest{}, err + } + + return schemaValidityRequest, nil +} diff --git a/registry/validity/checker.go b/registry/validity/checker.go new file mode 100644 index 0000000..35a400b --- /dev/null +++ b/registry/validity/checker.go @@ -0,0 +1,11 @@ +package validity + +type Checker interface { + Check(schema, schemaType, mode string) (bool, error) +} + +type CheckerFunc func(schema, schemaType, mode string) (bool, error) + +func (f CheckerFunc) Check(schema, schemaType, mode string) (bool, error) { + return f(schema, schemaType, mode) +} diff --git a/registry/validity/checker_test.go b/registry/validity/checker_test.go new file mode 100644 index 0000000..82f6842 --- /dev/null +++ b/registry/validity/checker_test.go @@ -0,0 +1,89 @@ +package validity + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestNewExternalChecker(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err := NewExternalChecker(ctx, "http://localhost:8089", 1*time.Second) + + if err != nil { + t.Fatal(err) + } +} + +func TestValidityChecker_Check(t *testing.T) { + if os.Getenv("MANUAL_TEST") == "" { + t.Skip() + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + checker, err := NewExternalCheckerFromEnv(ctx) + if err != nil { + t.Fatal(err) + } + + type Data struct { + Schema string + } + + tt := []struct { + name string + schemaFilename string + schemaType string + validity string + valid bool + }{ + {"valid_json_syntax1", "valid_json_syntax1.json", "json", "syntax-only", true}, + {"invalid_json_syntax1", "invalid_json_syntax1.json", "json", "syntax-only", false}, + {"invalid_json_full1", "invalid_json_full1.json", "json", "full", false}, + {"valid_avro_full1", "valid_avro_full1.json", "avro", "full", true}, + {"invalid_avro_full1", "invalid_avro_full1.json", "avro", "full", false}, + {"invalid_avro_syntax1", "invalid_avro_syntax1.json", "avro", "syntax-only", false}, + } + + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + testdataDir := filepath.Join(basepath, "testdata") + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + content, err := os.ReadFile(filepath.Join(testdataDir, tc.schemaFilename)) + if err != nil { + t.Error(err) + } + + var payload Data + err = json.Unmarshal(content, &payload) + if err != nil { + t.Error(err) + } + + newSchema := payload.Schema + + valid, err := checker.Check(newSchema, tc.schemaType, tc.validity) + if err != nil { + t.Errorf("validity error: %s", err) + } + if valid != tc.valid { + if valid { + t.Errorf("message valid, invalid expected") + } else { + t.Errorf("message invalid, valid expected") + } + } + }) + } +} diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-common-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-common-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..f30d04c4391bee529709c57dada8a3cda7252ac5 GIT binary patch literal 118628 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 TfIu9;f9m@o5V9PwGz0k`VZ-o8 literal 0 HcmV?d00001 diff --git a/registry/validity/external/validity-checker/lib/apicurio-registry-protobuf-schema-utilities-2.2.5.Final.jar b/registry/validity/external/validity-checker/lib/apicurio-registry-protobuf-schema-utilities-2.2.5.Final.jar new file mode 100644 index 0000000000000000000000000000000000000000..45aee9f708c80394553c33e1262e3ccb207541f6 GIT binary patch literal 499104 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⋘Odyb6lK^<-z32&2{}{49ah|mM50vNl}A@ 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 z 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