From 785241237e8a3079960fa91aa623fb3572f227f7 Mon Sep 17 00:00:00 2001 From: Jim Date: Fri, 13 May 2022 13:53:22 -0400 Subject: [PATCH] refactor (kms): adopt the go-kms-wrapping/extras/kms package (#2027) * feature (db): add Db.UnderlyingDB() This is needed to allow for integration with bits that need a *dbw.DB * feature (kms): add new go-kms-wrapping/extras/kms dependency * refactor (kms): schema changes required to adopt extras/kms pkg * refactor (kms/iam): rename to DeprecateCreateKeysTx(...) * refactor (kms): remove deprecated test * refactor (kms): refactor Kms type This refactor includes renaming the existing type to DeprecatedKms and then refactoring the Kms type to become a wrapper of go-kms-wrapping/extras/kms * refactor (kms): delete all the unneeded bits All this stuff is not needed now that we're using go-kms-wrapping/extras/kms * refactor (db): fixup tests after kms refactor * refactor (kms/tests): use testing.TB for test helpers Our test helper packages were not possible to use with benchmarks. This refactor switches to testing.TB to allow both tests and benchmarks to use the helpers. * tests (session benchmarks): refactor to use new Kms type * refactor (schema): rm test which relies on deprecated Kms code * refactor (kms): post rebase on main changes required * chore (kms refactor): re-add unit test from main * refactor (kms): uses migrations that don't include KMS schema changes --- go.mod | 38 +- go.sum | 861 +++++++++++- internal/cmd/base/dev.go | 6 +- internal/cmd/base/initial_resources.go | 36 +- internal/cmd/base/servers.go | 9 +- internal/cmd/commands/server/server.go | 16 +- internal/daemon/controller/auth/auth.go | 2 +- internal/daemon/controller/controller.go | 6 +- internal/daemon/controller/controller_test.go | 5 +- .../sessions/session_list_benchmarks_test.go | 4 +- internal/db/read_writer.go | 5 + .../postgres/30/01_kms_domain_types.up.sql | 103 ++ .../oss/postgres/30/02_kms_version.up.sql | 40 + .../oss/postgres/30/03_kms_keys.up.sql | 37 + .../oss/postgres/30/04_kms_keys.up.sql | 281 ++++ .../migrations/oss/postgres_18_01_test.go | 162 --- .../migrations/oss/postgres_24_01_test.go | 166 --- .../migrations/oss/postgres_28_02_test.go | 151 --- .../migrations/oss/postgres_29_01_test.go | 140 -- .../migrations/oss/postgres_30_01_test.go | 587 +++++++++ .../sqltest/initdb.d/03_widgets_persona.sql | 10 +- internal/iam/repository_scope.go | 18 +- internal/iam/repository_test.go | 4 +- internal/iam/testing.go | 2 +- internal/kms/audit_key.go | 82 -- internal/kms/audit_key_test.go | 209 --- internal/kms/audit_key_version.go | 122 -- internal/kms/audit_key_version_test.go | 250 ---- internal/kms/const.go | 80 +- internal/kms/database_key.go | 82 -- internal/kms/database_key_test.go | 206 --- internal/kms/database_key_version.go | 121 -- internal/kms/database_key_version_test.go | 249 ---- internal/kms/external_wrappers.go | 28 + internal/kms/external_wrappers_test.go | 46 + internal/kms/ids.go | 151 --- internal/kms/ids_test.go | 84 -- internal/kms/immutable_fields_test.go | 1165 ----------------- internal/kms/kms.go | 557 +++----- internal/kms/kms_ext_test.go | 245 +++- internal/kms/kms_test.go | 216 ++- internal/kms/oidc_key.go | 83 -- internal/kms/oidc_key_test.go | 206 --- internal/kms/oidc_key_version.go | 122 -- internal/kms/oidc_key_version_test.go | 249 ---- internal/kms/oplog_key.go | 79 -- internal/kms/oplog_key_test.go | 206 --- internal/kms/oplog_key_version.go | 118 -- internal/kms/oplog_key_version_test.go | 249 ---- internal/kms/option_test.go | 7 + internal/kms/options.go | 34 +- internal/kms/repository.go | 200 --- internal/kms/repository_audit_key.go | 163 --- internal/kms/repository_audit_key_test.go | 298 ----- internal/kms/repository_audit_key_version.go | 176 --- .../kms/repository_audit_key_version_test.go | 367 ------ internal/kms/repository_database_key.go | 163 --- internal/kms/repository_database_key_test.go | 295 ----- .../kms/repository_database_key_version.go | 176 --- .../repository_database_key_version_test.go | 367 ------ internal/kms/repository_oidc_key.go | 162 --- internal/kms/repository_oidc_key_test.go | 295 ----- internal/kms/repository_oidc_key_version.go | 176 --- .../kms/repository_oidc_key_version_test.go | 367 ------ internal/kms/repository_oplog_key.go | 162 --- internal/kms/repository_oplog_key_test.go | 295 ----- internal/kms/repository_oplog_key_version.go | 176 --- .../kms/repository_oplog_key_version_test.go | 367 ------ internal/kms/repository_root_key.go | 146 --- internal/kms/repository_root_key_test.go | 270 ---- internal/kms/repository_root_key_version.go | 160 --- .../kms/repository_root_key_version_test.go | 363 ----- internal/kms/repository_session_key.go | 162 --- internal/kms/repository_session_key_test.go | 296 ----- .../kms/repository_session_key_version.go | 176 --- .../repository_session_key_version_test.go | 367 ------ internal/kms/repository_test.go | 288 ---- internal/kms/repository_token_key.go | 162 --- internal/kms/repository_token_key_test.go | 295 ----- internal/kms/repository_token_key_version.go | 176 --- .../kms/repository_token_key_version_test.go | 367 ------ internal/kms/root_key.go | 84 -- internal/kms/root_key_test.go | 210 --- internal/kms/root_key_version.go | 114 -- internal/kms/root_key_version_test.go | 219 ---- internal/kms/session_key.go | 79 -- internal/kms/session_key_test.go | 206 --- internal/kms/session_key_version.go | 118 -- internal/kms/session_key_version_test.go | 249 ---- internal/kms/testing.go | 264 +--- internal/kms/testing_test.go | 150 --- internal/kms/token_key.go | 79 -- internal/kms/token_key_test.go | 206 --- internal/kms/token_key_version.go | 118 -- internal/kms/token_key_version_test.go | 249 ---- internal/servers/repository_test.go | 4 + internal/session/repository_test.go | 17 +- 97 files changed, 2580 insertions(+), 15154 deletions(-) create mode 100644 internal/db/schema/migrations/oss/postgres/30/01_kms_domain_types.up.sql create mode 100644 internal/db/schema/migrations/oss/postgres/30/02_kms_version.up.sql create mode 100644 internal/db/schema/migrations/oss/postgres/30/03_kms_keys.up.sql create mode 100644 internal/db/schema/migrations/oss/postgres/30/04_kms_keys.up.sql delete mode 100644 internal/db/schema/migrations/oss/postgres_18_01_test.go delete mode 100644 internal/db/schema/migrations/oss/postgres_24_01_test.go delete mode 100644 internal/db/schema/migrations/oss/postgres_28_02_test.go delete mode 100644 internal/db/schema/migrations/oss/postgres_29_01_test.go create mode 100644 internal/db/schema/migrations/oss/postgres_30_01_test.go delete mode 100644 internal/kms/audit_key.go delete mode 100644 internal/kms/audit_key_test.go delete mode 100644 internal/kms/audit_key_version.go delete mode 100644 internal/kms/audit_key_version_test.go delete mode 100644 internal/kms/database_key.go delete mode 100644 internal/kms/database_key_test.go delete mode 100644 internal/kms/database_key_version.go delete mode 100644 internal/kms/database_key_version_test.go create mode 100644 internal/kms/external_wrappers.go create mode 100644 internal/kms/external_wrappers_test.go delete mode 100644 internal/kms/ids.go delete mode 100644 internal/kms/ids_test.go delete mode 100644 internal/kms/immutable_fields_test.go delete mode 100644 internal/kms/oidc_key.go delete mode 100644 internal/kms/oidc_key_test.go delete mode 100644 internal/kms/oidc_key_version.go delete mode 100644 internal/kms/oidc_key_version_test.go delete mode 100644 internal/kms/oplog_key.go delete mode 100644 internal/kms/oplog_key_test.go delete mode 100644 internal/kms/oplog_key_version.go delete mode 100644 internal/kms/oplog_key_version_test.go delete mode 100644 internal/kms/repository.go delete mode 100644 internal/kms/repository_audit_key.go delete mode 100644 internal/kms/repository_audit_key_test.go delete mode 100644 internal/kms/repository_audit_key_version.go delete mode 100644 internal/kms/repository_audit_key_version_test.go delete mode 100644 internal/kms/repository_database_key.go delete mode 100644 internal/kms/repository_database_key_test.go delete mode 100644 internal/kms/repository_database_key_version.go delete mode 100644 internal/kms/repository_database_key_version_test.go delete mode 100644 internal/kms/repository_oidc_key.go delete mode 100644 internal/kms/repository_oidc_key_test.go delete mode 100644 internal/kms/repository_oidc_key_version.go delete mode 100644 internal/kms/repository_oidc_key_version_test.go delete mode 100644 internal/kms/repository_oplog_key.go delete mode 100644 internal/kms/repository_oplog_key_test.go delete mode 100644 internal/kms/repository_oplog_key_version.go delete mode 100644 internal/kms/repository_oplog_key_version_test.go delete mode 100644 internal/kms/repository_root_key.go delete mode 100644 internal/kms/repository_root_key_test.go delete mode 100644 internal/kms/repository_root_key_version.go delete mode 100644 internal/kms/repository_root_key_version_test.go delete mode 100644 internal/kms/repository_session_key.go delete mode 100644 internal/kms/repository_session_key_test.go delete mode 100644 internal/kms/repository_session_key_version.go delete mode 100644 internal/kms/repository_session_key_version_test.go delete mode 100644 internal/kms/repository_test.go delete mode 100644 internal/kms/repository_token_key.go delete mode 100644 internal/kms/repository_token_key_test.go delete mode 100644 internal/kms/repository_token_key_version.go delete mode 100644 internal/kms/repository_token_key_version_test.go delete mode 100644 internal/kms/root_key.go delete mode 100644 internal/kms/root_key_test.go delete mode 100644 internal/kms/root_key_version.go delete mode 100644 internal/kms/root_key_version_test.go delete mode 100644 internal/kms/session_key.go delete mode 100644 internal/kms/session_key_test.go delete mode 100644 internal/kms/session_key_version.go delete mode 100644 internal/kms/session_key_version_test.go delete mode 100644 internal/kms/testing_test.go delete mode 100644 internal/kms/token_key.go delete mode 100644 internal/kms/token_key_test.go delete mode 100644 internal/kms/token_key_version.go delete mode 100644 internal/kms/token_key_version_test.go diff --git a/go.mod b/go.mod index b76ebc2ad..5243dd0c4 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/fatih/structs v1.1.0 github.com/favadi/protoc-go-inject-tag v1.3.0 github.com/godbus/dbus/v5 v5.0.6 // indirect - github.com/golang-migrate/migrate/v4 v4.14.1 + github.com/golang-migrate/migrate/v4 v4.15.1 github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.7 @@ -28,7 +28,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-hclog v1.1.0 - github.com/hashicorp/go-kms-wrapping/v2 v2.0.4 + github.com/hashicorp/go-kms-wrapping/v2 v2.0.5-0.20220321175502-0989a9b6deb1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-rootcerts v1.0.2 @@ -83,7 +83,7 @@ require ( nhooyr.io/websocket v1.8.7 ) -require github.com/hashicorp/go-dbw v0.0.0-20211215222256-2ff0d37184ff // this is a branch and should be updated before merging +require github.com/hashicorp/go-dbw v0.0.0-20220412153211-c470aec9369f // this is a branch and should be updated before merging require ( github.com/prometheus/client_golang v1.12.1 @@ -93,12 +93,13 @@ require ( require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/AlecAivazis/survey/v2 v2.2.9 // indirect - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/apex/log v1.9.0 // indirect @@ -108,14 +109,13 @@ require ( github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cenkalti/backoff/v4 v4.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc // indirect + github.com/containerd/continuity v0.1.0 // indirect github.com/coreos/go-oidc/v3 v3.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dhui/dktest v0.3.4 // indirect github.com/docker/cli v20.10.7+incompatible // indirect - github.com/docker/docker v20.10.7+incompatible // indirect + github.com/docker/docker v20.10.9+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect @@ -126,6 +126,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20220512190651-85bdcdd684e6 // indirect github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.2 // indirect github.com/hashicorp/go-plugin v1.4.3 // indirect github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 // indirect @@ -147,30 +148,31 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.3 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.13.5 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/lib/pq v1.10.2 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/oklog/run v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v1.0.0-rc9 // indirect + github.com/opencontainers/runc v1.0.2 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/sirupsen/logrus v1.7.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/urfave/cli/v2 v2.3.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -188,6 +190,14 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gorm.io/driver/sqlite v1.2.4 // indirect - gotest.tools/v3 v3.0.3 // indirect + modernc.org/cc/v3 v3.32.4 // indirect + modernc.org/ccgo/v3 v3.9.2 // indirect + modernc.org/libc v1.9.5 // indirect + modernc.org/mathutil v1.2.2 // indirect + modernc.org/memory v1.0.4 // indirect + modernc.org/opt v0.1.1 // indirect + modernc.org/sqlite v1.10.6 // indirect + modernc.org/strutil v1.1.0 // indirect + modernc.org/token v1.0.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index a2b2f40f2..71314f498 100644 --- a/go.sum +++ b/go.sum @@ -13,9 +13,16 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP 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.63.0/go.mod h1:GmezbQc7T2snqkEXWfZ0sy0VfkB/ivI2DdtJL2DEmlg= -cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4= 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.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.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY= 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= @@ -28,22 +35,42 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k 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/spanner v1.9.0/go.mod h1:xvlEn0NZ5v1iJPYsBnUVRDNvccDxsBTEi16pJRKQVws= +cloud.google.com/go/spanner v1.24.0/go.mod h1:EZI0yH1D/PrXK0XH9Ba5LGXTXWeqZv0ClOD/19a0Z58= 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= 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= 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/AlecAivazis/survey/v2 v2.2.9 h1:LWvJtUswz/W9/zVVXELrmlvdwWcKE60ZAw0FWV9vssk= github.com/AlecAivazis/survey/v2 v2.2.9/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 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/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= +github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= +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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -55,14 +82,36 @@ github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030I github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= 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/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/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 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= @@ -71,22 +120,54 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= +github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= +github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= +github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU= +github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= +github.com/aws/aws-sdk-go-v2/credentials v1.3.2/go.mod h1:PACKuTJdt6AlXvEq8rFI4eDmoqDFC5DpVKQbWysaDgM= +github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.4.0/go.mod h1:Mj/U8OpDbcVcoctrYwA2bak8k/HFPdcLzI/vaiXMwuM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.4.0/go.mod h1:eHwXu2+uE/T6gpnYWwBwqoeqRf9IXyCcolyOWDRAErQ= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.5.4/go.mod h1:Ex7XQmbFmgFHrjUX6TN3mApKW5Hglyga+F7wZHTtYhA= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.0/go.mod h1:Q5jATQc+f1MfZp3PDMhn6ry18hGvE0i8yvbXoKbnZaE= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.2.2/go.mod h1:EASdTcM1lGhUe1/p4gkojHwlGJkeoRjjr1sRCzup3Is= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.3.0/go.mod h1:v8ygadNyATSm6elwJ/4gzJwcFhri9RqS8skgHKiwXPU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.2/go.mod h1:NXmNI41bdEsJMrD0v9rUvbGCB5GwdBEpKvUvIY3vTFg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.5.2/go.mod h1:QuL2Ym8BkrLmN4lUofXYq6000/i5jPjosCNK//t6gak= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.2/go.mod h1:np7TMuJNT83O0oDOSF8i4dF3dvGqA6hPYYo6YYkzgRA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.12.0/go.mod h1:6J++A5xpo7QDsIeSqPK4UHqMSyPOCopa+zKtqAMhqVQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.16.1/go.mod h1:CQe/KvWV1AqRc65KqeJjrLzr5X2ijnFTTVzJW0VBRCI= +github.com/aws/aws-sdk-go-v2/service/sso v1.3.2/go.mod h1:J21I6kF+d/6XHVk7kp/cx9YVD2TMD2TbLwtRGVcinXo= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= +github.com/aws/aws-sdk-go-v2/service/sts v1.6.1/go.mod h1:hLZ/AnkIKHLuPGjEiyghNEdvJ2PP0MgOxcmv9EBJ4xs= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= +github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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= @@ -94,45 +175,158 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= 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/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= 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/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-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= -github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.3 h1:ijQT13JedHSHrQGWFcGEwzcNKrAGIiZ+jSD5QQG07SY= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc h1:lDK/G7OlwUnJW3O6nv/8M89bMupV6FuLK6FXmC3ueWc= -github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc/v3 v3.0.0 h1:/mAA0XMgYJw2Uqm7WKGCsKnjitE/+A0FFbOmiRJm7LQ= github.com/coreos/go-oidc/v3 v3.0.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -140,7 +334,12 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -148,36 +347,55 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec h1:NfhRXXFDPxcF5Cwo06DzeIaE7uuJtAUhsDwH3LNsjos= -github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= +github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ= -github.com/dhui/dktest v0.3.4 h1:VbUEcaSP+U2/yUr9d2JhSThXYEnDlGabRSHe2rIE46E= -github.com/dhui/dktest v0.3.4/go.mod h1:4m4n6lmXlmVfESth7mzdcv8nBI5mOb5UROPqjM02csU= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dhui/dktest v0.3.7 h1:jWjWgHAPDAdqgUr7lAsB3bqB2DKWC3OaA+isfekjRew= +github.com/dhui/dktest v0.3.7/go.mod h1:nYMOkafiA07WchSwKnKFUSbGMb2hMm5DrCGiXYG6gwM= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v20.10.7+incompatible h1:pv/3NqibQKphWZiAskMzdz8w0PRbtTaEB+f6NwdU7Is= github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.9+incompatible h1:JlsVnETOjM2RLQa0Cc1XCIspUdXW3Zenq9P54uXBm6k= +github.com/docker/docker v20.10.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -188,28 +406,54 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/favadi/protoc-go-inject-tag v1.3.0 h1:JPrmsmc/uBShG85uY5xGZIa5WJ0IaNZn6LZhQR9tIQE= github.com/favadi/protoc-go-inject-tag v1.3.0/go.mod h1:SSkUBgfqw2IJ2p7NPNKWk0Idwxt/qIt2LQgFPUgRGtc= +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/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +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/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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= 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 v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -226,30 +470,67 @@ github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr6 github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= +github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE= -github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0= +github.com/golang-migrate/migrate/v4 v4.15.1 h1:Sakl3Nm6+wQKq0Q62tpFMi5a503bgGhceo2icrgQ9vM= +github.com/golang-migrate/migrate/v4 v4.15.1/go.mod h1:/CrBenUbcDqsW29jGTR/XFqCfVi/Y6mHXlooCcSOJMQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +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 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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= @@ -260,6 +541,8 @@ 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.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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= @@ -276,15 +559,17 @@ 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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 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 v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v2.0.0+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= @@ -292,15 +577,21 @@ 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 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.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/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= @@ -308,26 +599,46 @@ 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-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-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0 h1:ESEyqQqXXFIcImj/BE8oKEX37Zsuceb2cZI+EL/zNCY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0/go.mod h1:XnLCLFp3tjoZJszVKjfpyAK6J8sYIcQXWQxmqLWF21I= @@ -338,6 +649,7 @@ github.com/hashicorp/dawdle v0.4.0 h1:nAE+aCoAmVulgCPPPrp6oGOykjPhxEe4VUNms/mTKe github.com/hashicorp/dawdle v0.4.0/go.mod h1:gOBY8rFXpW4Rw39up1FIacw/1pG/fO779LfchCY3KUw= github.com/hashicorp/dbassert v0.0.0-20210708202608-ecf920cf1ed8 h1:/3iubtqEdLgdXB6ue+WAKvbcpn313jjL5mQvU5ByymE= github.com/hashicorp/dbassert v0.0.0-20210708202608-ecf920cf1ed8/go.mod h1:+B5eZq7vXqN4Gxkgjm4ub1bwG6OTcYzFL0r+bMvWorg= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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= @@ -351,8 +663,10 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-dbw v0.0.0-20211215222256-2ff0d37184ff h1:jUa73mulKrSJaWD5AVpsvhWgoCCQy5NeGJdZrXggga8= -github.com/hashicorp/go-dbw v0.0.0-20211215222256-2ff0d37184ff/go.mod h1:oh0okaxgqjJMPBSav3mSYPmyEbW7bVWQvRvkwJaQiIg= +github.com/hashicorp/go-dbw v0.0.0-20220409193558-ba55a31040a1 h1:G3tzu6oK/wVrw9ioQvZ1iRAEDQAOEaxBVumy5sF8xRM= +github.com/hashicorp/go-dbw v0.0.0-20220409193558-ba55a31040a1/go.mod h1:w9gD0GS/RPaf1BQ//LmdWfQpW8SFwamwL1hmtzQ58p0= +github.com/hashicorp/go-dbw v0.0.0-20220412153211-c470aec9369f h1:W9IOXASfpDhDY/msdD15bc92IhRVehphYcbVyxYxUUk= +github.com/hashicorp/go-dbw v0.0.0-20220412153211-c470aec9369f/go.mod h1:w9gD0GS/RPaf1BQ//LmdWfQpW8SFwamwL1hmtzQ58p0= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -365,10 +679,13 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= +github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20220512190651-85bdcdd684e6 h1:3BknAN8P8326GPQac8e3iM132lwtwkO/3OilBU67S1I= +github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20220512190651-85bdcdd684e6/go.mod h1:TzFKcCsMKyMwFiMfH2MfO8SXqsFQLxzR7Z8JZiGzpK4= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.2 h1:it114Kjpk79JVh6AfxFMP5oi1gb+RPzcSLiG3zF/J0w= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.2/go.mod h1:b9mq0bG5xJ10ZcTEQJLZ22O9y71hIt2MGTLqROA/SAM= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.4 h1:7BSAm60AqJom/TRb73wmaCzwco9A+Qolr/wCi0PORmY= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.4/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.5-0.20220321175502-0989a9b6deb1 h1:UFHzbA/voyzrVfxvm83LW6Hq2gd43F0mgchFnqrinjA= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.5-0.20220321175502-0989a9b6deb1/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -441,10 +758,15 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= 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/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -452,13 +774,16 @@ github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgO github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -474,14 +799,20 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.7/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk= @@ -489,12 +820,18 @@ github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76I github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0= github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc= github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= @@ -517,14 +854,23 @@ github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZ 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.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= 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.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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= @@ -532,19 +878,30 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr 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/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 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.2/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= @@ -556,6 +913,7 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -569,11 +927,20 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +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.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -583,24 +950,32 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= @@ -620,13 +995,20 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= 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= @@ -634,49 +1016,92 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN 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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= 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/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/oligot/go-mod-upgrade v0.6.1 h1:AZnCiEAOxOMxpKZWjFWFNm/i6QjZVBozuKjuB8EzRCk= github.com/oligot/go-mod-upgrade v0.6.1/go.mod h1:5Gyau3jUXqXrGhYxGkGqrxxgR90Lzd1yt/9YQp9sn1w= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 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.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest/v3 v3.6.0/go.mod h1:4ZOpj8qBUmh8fcBSVzkH2bws2s91JdGvHUqan4GHEuQ= github.com/ory/dockertest/v3 v3.7.0 h1:Bijzonc69Ont3OU0a3TWKJ1Rzlh3TsDXP1JrTAkSmsM= github.com/ory/dockertest/v3 v3.7.0/go.mod h1:PvCCgnP7AfBZeVrzwiUTjZx/IUXlGLC1zQlUQrLIlUE= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +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/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw= github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= 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= @@ -689,34 +1114,55 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 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 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 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 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 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 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/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 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 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.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -727,36 +1173,58 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 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/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 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.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0= -github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU= +github.com/snowflakedb/gosnowflake v1.6.3/go.mod h1:6hLajn6yxuJ4xUHZegMekpq9rnQbGJ7TMwXjgTmA6lg= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -766,7 +1234,11 @@ github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= @@ -774,39 +1246,70 @@ github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/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 v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= 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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/dburl v0.9.0 h1:ME8QfRqZz/YDwf+VVEe9sq4wgEZCAOdYcUTeuAf+wQQ= github.com/xo/dburl v0.9.0/go.mod h1:7Uupe87dIDxNrbKFRrpw6bAf2l3/rqU42iwlpq1nyjY= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yhat/scrape v0.0.0-20161128144610-24b7890b0945/go.mod h1:4vRFPPNYllgCacoj+0FoKOjTW68rUhEfqPLiEJaK2w8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 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/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc= github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= -go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= 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.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -826,41 +1329,61 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +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-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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/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/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= @@ -871,7 +1394,9 @@ 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 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +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= @@ -881,6 +1406,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB 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.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -888,8 +1415,10 @@ golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73r 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/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-20181220203305-927f97764cc3/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-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -897,13 +1426,18 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn 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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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-20190619014844-b5b0513f8c1b/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/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= @@ -918,16 +1452,24 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ 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-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/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-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -937,13 +1479,21 @@ 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-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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-20190412183630-56d357773e84/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= @@ -957,6 +1507,7 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -964,28 +1515,47 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/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-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/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-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/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-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/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-20200217220822-9197077df867/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= @@ -996,23 +1566,48 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/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-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-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/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-20210616045830-e2b7044e8c71/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-20210818153620-00dd8d7831e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/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-20220330033206-e17cdc41300f h1:rlezHXNlxYWvBCzNses9Dlc7nGFaNMJeqLolcmQSSZY= @@ -1032,30 +1627,41 @@ 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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-20181030221726-6c7e314b6563/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-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/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-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/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-20190624222133-a101b041ded4/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-20190823170909-c4a336ef6a2f/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1086,13 +1692,21 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/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-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200818005847-188abfa75333/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-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/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.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1102,6 +1716,13 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/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= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= 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= @@ -1118,6 +1739,15 @@ 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/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1128,6 +1758,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID 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/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 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= @@ -1135,6 +1766,7 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRn 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-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 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= @@ -1143,6 +1775,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx 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-20200117163144-32f20d992d24/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= @@ -1160,21 +1793,43 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY 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-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/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-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/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-20201110150050-8816d57aaa9a/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-20210207032614-bba0dbe2a9ea/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-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-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-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U= +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-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210726143408-b02e89920bf0/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 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.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= 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= @@ -1183,10 +1838,18 @@ 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.32.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.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= @@ -1210,10 +1873,13 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1225,9 +1891,14 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eR gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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= @@ -1242,10 +1913,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= gorm.io/driver/postgres v1.2.2 h1:Ka9W6feOU+rPM9m007eYLMD4QoZuYGBnQ3Jp0faGSwg= gorm.io/driver/postgres v1.2.2/go.mod h1:Ik3tK+a3FMp8ORZl29v4b3M0RsgXsaeMXh9s9eVMXco= gorm.io/driver/sqlite v1.2.4 h1:jx16ESo1WzNjgBJNSbhEDoMKJnlhkU8BuBR2C0GC7D8= gorm.io/driver/sqlite v1.2.4/go.mod h1:n8/CTEIEmo7lKrehQI4pd+rz6O514tMkBeCAR5UTXLs= +gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.3 h1:/JS6z+GStEQvJNW3t1FTwJwG/gZ+A7crFdRqtvG5ehA= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= @@ -1260,17 +1934,65 @@ 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= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= +modernc.org/cc/v3 v3.32.4 h1:1ScT6MCQRWwvwVdERhGPsPq0f55J1/pFEOCiqM7zc78= +modernc.org/cc/v3 v3.32.4/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878= +modernc.org/ccgo/v3 v3.9.2 h1:mOLFgduk60HFuPmxSix3AluTEh7zhozkby+e1VDo/ro= +modernc.org/ccgo/v3 v3.9.2/go.mod h1:gnJpy6NIVqkETT+L5zPsQFj7L2kkhfPMzOghRNv/CFo= modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw= modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= +modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= +modernc.org/libc v1.9.5 h1:zv111ldxmP7DJ5mOIqzRbza7ZDl3kh4ncKfASB2jIYY= +modernc.org/libc v1.9.5/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM= +modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= +modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY= modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= +modernc.org/sqlite v1.10.6 h1:iNDTQbULcm0IJAqrzCm2JcCqxaKRS94rJ5/clBMRmc8= +modernc.org/sqlite v1.10.6/go.mod h1:Z9FEjUtZP4qFEg6/SiADg9XCER7aYy9a/j7Pg9P7CPs= +modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/tcl v1.5.2/go.mod h1:pmJYOLgpiys3oI4AeAafkcUfE+TKKilminxNyU/+Zlo= +modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= +modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4= mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8= @@ -1278,7 +2000,14 @@ mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= 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/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/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/cmd/base/dev.go b/internal/cmd/base/dev.go index cf692f343..3e83670dd 100644 --- a/internal/cmd/base/dev.go +++ b/internal/cmd/base/dev.go @@ -328,11 +328,7 @@ func (b *Server) CreateDevOidcAuthMethod(ctx context.Context) error { func (b *Server) createInitialOidcAuthMethod(ctx context.Context) (*oidc.AuthMethod, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, fmt.Errorf("error creating kms cache: %w", err) } diff --git a/internal/cmd/base/initial_resources.go b/internal/cmd/base/initial_resources.go index 3f2560429..e32f27611 100644 --- a/internal/cmd/base/initial_resources.go +++ b/internal/cmd/base/initial_resources.go @@ -22,11 +22,7 @@ import ( func (b *Server) CreateInitialLoginRole(ctx context.Context) (*iam.Role, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, fmt.Errorf("error creating kms cache: %w", err) } @@ -80,11 +76,7 @@ func (b *Server) CreateInitialLoginRole(ctx context.Context) (*iam.Role, error) func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password.AuthMethod, *iam.User, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, nil, fmt.Errorf("error creating kms cache: %w", err) } @@ -279,11 +271,7 @@ func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scope, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, nil, fmt.Errorf("error creating kms cache: %w", err) } @@ -362,11 +350,7 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop func (b *Server) CreateInitialHostResources(ctx context.Context) (*static.HostCatalog, *static.HostSet, *static.Host, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, nil, nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, nil, nil, fmt.Errorf("error creating kms cache: %w", err) } @@ -473,11 +457,7 @@ func (b *Server) CreateInitialHostResources(ctx context.Context) (*static.HostCa func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error) { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, fmt.Errorf("error creating kms cache: %w", err) } @@ -608,11 +588,7 @@ func (b *Server) RegisterHostPlugin(ctx context.Context, name string, plg plgpb. } rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return nil, fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return nil, fmt.Errorf("error creating kms cache: %w", err) } diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index 2b0f4c0d6..92a314ba6 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -649,11 +649,7 @@ func (b *Server) ConnectToDatabase(ctx context.Context, dialect string) error { func (b *Server) CreateGlobalKmsKeys(ctx context.Context) error { rw := db.New(b.Database) - kmsRepo, err := kms.NewRepository(rw, rw) - if err != nil { - return fmt.Errorf("error creating kms repository: %w", err) - } - kmsCache, err := kms.NewKms(kmsRepo) + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { return fmt.Errorf("error creating kms cache: %w", err) } @@ -674,8 +670,7 @@ func (b *Server) CreateGlobalKmsKeys(ctx context.Context) error { } }() - _, err = kms.CreateKeysTx(cancelCtx, rw, rw, b.RootKms, b.SecureRandomReader, scope.Global.String()) - if err != nil { + if err = kmsCache.CreateKeys(cancelCtx, scope.Global.String(), kms.WithRandomReader(b.SecureRandomReader)); err != nil { return fmt.Errorf("error creating global scope kms keys: %w", err) } diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 1b28e2fbf..f91291b9f 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -23,7 +23,6 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/observability/event" - "github.com/hashicorp/boundary/internal/types/scope" kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms" "github.com/hashicorp/boundary/sdk/wrapper" "github.com/hashicorp/go-hclog" @@ -788,18 +787,13 @@ func (c *Command) verifyKmsSetup() error { const op = "server.(Command).verifyKmsExists" rw := db.New(c.Database) - kmsRepo, err := kms.NewRepository(rw, rw) + ctx := context.Background() + kmsCache, err := kms.New(ctx, rw, rw) if err != nil { - return fmt.Errorf("error creating kms repository: %w", err) + return fmt.Errorf("error creating kms: %w", err) } - rks, err := kmsRepo.ListRootKeys(c.Context, kms.WithLimit(1)) - if err != nil { + if err := kmsCache.VerifyGlobalRoot(ctx); err != nil { return err } - for _, rk := range rks { - if rk.GetScopeId() == scope.Global.String() { - return nil - } - } - return errors.NewDeprecated(errors.MigrationIntegrity, op, "can't find global scoped root key") + return nil } diff --git a/internal/daemon/controller/auth/auth.go b/internal/daemon/controller/auth/auth.go index 54b729644..91c122bd1 100644 --- a/internal/daemon/controller/auth/auth.go +++ b/internal/daemon/controller/auth/auth.go @@ -396,7 +396,7 @@ func (v *verifier) decryptToken(ctx context.Context) { v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown) return } - wrapper := v.kms.GetExternalWrappers().Recovery() + wrapper := v.kms.GetExternalWrappers(ctx).Recovery() if wrapper == nil { event.WriteError(ctx, op, stderrors.New("no recovery KMS is available")) v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown) diff --git a/internal/daemon/controller/controller.go b/internal/daemon/controller/controller.go index c028e1c84..c89386c92 100644 --- a/internal/daemon/controller/controller.go +++ b/internal/daemon/controller/controller.go @@ -204,11 +204,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { // Set up repo stuff dbase := db.New(c.conf.Database) - kmsRepo, err := kms.NewRepository(dbase, dbase) - if err != nil { - return nil, fmt.Errorf("error creating kms repository: %w", err) - } - c.kms, err = kms.NewKms(kmsRepo) + c.kms, err = kms.New(ctx, dbase, dbase) if err != nil { return nil, fmt.Errorf("error creating kms cache: %w", err) } diff --git a/internal/daemon/controller/controller_test.go b/internal/daemon/controller/controller_test.go index 20c732fda..160886595 100644 --- a/internal/daemon/controller/controller_test.go +++ b/internal/daemon/controller/controller_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/hashicorp/boundary/internal/cmd/base" - "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/types/scope" @@ -51,8 +50,8 @@ func TestController_New(t *testing.T) { verifyFn() // this tests a scenario where there is NOT an audit DEK - db.TestDeleteWhere(t, conf.Server.Database, func() interface{} { i := kms.AllocAuditKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conf.Server.Database, func() interface{} { i := kms.AllocOidcKey(); return &i }(), "1=1") + kms.TestKmsDeleteKeyPurpose(t, conf.Database, kms.KeyPurposeAudit) + kms.TestKmsDeleteKeyPurpose(t, conf.Database, kms.KeyPurposeOidc) // re-init an empty cache and assert that the DEKs are not there. kmsCache := kms.TestKms(t, conf.Server.Database, conf.RootKms) diff --git a/internal/daemon/controller/handlers/sessions/session_list_benchmarks_test.go b/internal/daemon/controller/handlers/sessions/session_list_benchmarks_test.go index 010e088c9..73401dae3 100644 --- a/internal/daemon/controller/handlers/sessions/session_list_benchmarks_test.go +++ b/internal/daemon/controller/handlers/sessions/session_list_benchmarks_test.go @@ -74,9 +74,7 @@ func BenchmarkSessionList(b *testing.B) { ctx := context.Background() conn, _ := db.TestSetup(b, "postgres", db.WithTemplate(template.name)) rw := db.New(conn) - kmsRepo, err := kms.NewRepository(rw, rw) - require.NoError(b, err) - kmsThing, err := kms.NewKms(kmsRepo) + kmsThing, err := kms.New(ctx, rw, rw) require.NoError(b, err) wrap, err := dbtest.GetBoundaryBenchmarksRootKeyWrapper(ctx) require.NoError(b, err) diff --git a/internal/db/read_writer.go b/internal/db/read_writer.go index 49d77c733..cc3d2bde1 100644 --- a/internal/db/read_writer.go +++ b/internal/db/read_writer.go @@ -208,6 +208,11 @@ func New(underlying *DB) *Db { return &Db{underlying: underlying} } +// UnderlyingDB returns the underlying *dbw.DB +func (rw *Db) UnderlyingDB() *dbw.DB { + return rw.underlying.wrapped +} + // Exec will execute the sql with the values as parameters. The int returned // is the number of rows affected by the sql. WithDebug is supported. func (rw *Db) Exec(ctx context.Context, sql string, values []interface{}, opt ...Option) (int, error) { diff --git a/internal/db/schema/migrations/oss/postgres/30/01_kms_domain_types.up.sql b/internal/db/schema/migrations/oss/postgres/30/01_kms_domain_types.up.sql new file mode 100644 index 000000000..bc55a9169 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/30/01_kms_domain_types.up.sql @@ -0,0 +1,103 @@ +begin; + +-- make the required schema changes to adopt +-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2 +-- this migration is from: +-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/01_domain_types.up.sql + +create domain kms_private_id as text +not null +check( + length(trim(value)) > 0 +); +comment on domain kms_private_id is + 'standard column for private id'; + +create domain kms_scope_id as text +check( + length(trim(value)) > 0 +); +comment on domain kms_scope_id is +'standard column for scope id'; + +create domain kms_timestamp as + timestamp with time zone + default current_timestamp; +comment on domain kms_timestamp is +'Standard timestamp for all create_time and update_time columns'; + +create domain kms_version as bigint + default 1 + not null + check( + value > 0 + ); +comment on domain kms_version is +'standard column for row version'; + +-- kms_immutable_columns() will make the column names immutable which are passed as +-- parameters when the trigger is created. It raises error code 23601 which is a +-- class 23 integrity constraint violation: immutable column +create function kms_immutable_columns() + returns trigger +as $$ +declare + col_name text; + new_value text; + old_value text; +begin + foreach col_name in array tg_argv loop + execute format('SELECT $1.%I', col_name) into new_value using new; + execute format('SELECT $1.%I', col_name) into old_value using old; + if new_value is distinct from old_value then + raise exception 'immutable column: %.%', tg_table_name, col_name using + errcode = '23601', + schema = tg_table_schema, + table = tg_table_name, + column = col_name; + end if; + end loop; + return new; +end; +$$ language plpgsql; + +comment on function + kms_immutable_columns() +is + 'function used in before update triggers to make columns immutable'; + + +create function kms_default_create_time() + returns trigger +as $$ +begin + if new.create_time is distinct from now() then + new.create_time = now(); + end if; + return new; +end; +$$ language plpgsql; +comment on function + kms_default_create_time() +is + 'function used to properly set create_time columns'; + +create function + kms_update_time_column() + returns trigger +as $$ +begin + if row(new.*) is distinct from row(old.*) then + new.update_time = now(); + return new; + else + return old; + end if; +end; +$$ language plpgsql; +comment on function + kms_update_time_column() +is + 'function used in before update triggers to properly set update_time columns'; + +commit; \ No newline at end of file diff --git a/internal/db/schema/migrations/oss/postgres/30/02_kms_version.up.sql b/internal/db/schema/migrations/oss/postgres/30/02_kms_version.up.sql new file mode 100644 index 000000000..9eecc2b7f --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/30/02_kms_version.up.sql @@ -0,0 +1,40 @@ +begin; + +-- make the required schema changes to adopt +-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2 +-- this migration is from: +-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/02_version.up.sql + +create table kms_schema_version( + version text not null, + create_time kms_timestamp, + update_time kms_timestamp +); +comment on table kms_schema_version is + 'kms_schema_version contains the kms schema version'; + +-- this index ensures that there will only ever be one row in the +-- table. see: +-- https://www.postgresql.org/docs/current/indexes-expressional.html +create unique index kms_schema_version_one_row +ON kms_schema_version((version is not null)); + + -- define the immutable fields for kms_root_key (all of them) +create trigger kms_immutable_columns +before +update on kms_schema_version + for each row execute procedure kms_immutable_columns('create_time'); + +create trigger kms_default_create_time_column +before +insert on kms_schema_version + for each row execute procedure kms_default_create_time(); + +create trigger kms_update_time_column +before +update on kms_schema_version + for each row execute procedure kms_update_time_column(); + +insert into kms_schema_version(version) values('v0.0.1'); + +commit; \ No newline at end of file diff --git a/internal/db/schema/migrations/oss/postgres/30/03_kms_keys.up.sql b/internal/db/schema/migrations/oss/postgres/30/03_kms_keys.up.sql new file mode 100644 index 000000000..9ff06933c --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/30/03_kms_keys.up.sql @@ -0,0 +1,37 @@ +begin; + +-- make the required schema changes to adopt +-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2 +-- this migration is from: +-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/03_keys.up.sql + +-- we need to replace the existing function and there are existing tables that +-- depend on it.. so let's just create/replace it + +-- kms_version_column() will increment the version column whenever row data +-- is inserted and should only be used in an before insert trigger. This +-- function will overwrite any explicit values to the version column. +create or replace function kms_version_column() + returns trigger +as $$ +declare + _key_id text; + _max bigint; +begin + execute format('SELECT $1.%I', tg_argv[0]) into _key_id using new; + execute format('select max(version) + 1 from %I where %I = $1', tg_relid::regclass, tg_argv[0]) using _key_id into _max; + if _max is null then + _max = 1; + end if; + new.version = _max; + return new; +end; +$$ language plpgsql; + +comment on function + kms_version_column() +is + 'function used in before insert triggers to properly set version columns for kms_* tables with a version column'; + + +commit; \ No newline at end of file diff --git a/internal/db/schema/migrations/oss/postgres/30/04_kms_keys.up.sql b/internal/db/schema/migrations/oss/postgres/30/04_kms_keys.up.sql new file mode 100644 index 000000000..c5643d401 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/30/04_kms_keys.up.sql @@ -0,0 +1,281 @@ +begin; + +-- make the required schema changes to adopt +-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2 +-- this migration is from: +-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/04_keys.up.sql + + +alter table kms_root_key rename to kms_deprecated_root_key; +alter table kms_root_key_version rename to kms_deprecated_root_key_version; + +create table kms_root_key ( + private_id kms_private_id primary key, + scope_id kms_scope_id not null unique -- there can only be one root key for a scope. + references iam_scope(public_id) + on delete cascade + on update cascade, + create_time kms_timestamp +); +comment on table kms_root_key is + 'kms_root_key defines a root key for a scope'; + +-- define the immutable fields for kms_root_key (all of them) +create trigger kms_immutable_columns +before +update on kms_root_key + for each row execute procedure kms_immutable_columns('private_id', 'scope_id', 'create_time'); + +-- not adding the kms_default_create_time_column trigger until after we've +-- converted the data (we don't want the timestamp to change) + +create table kms_root_key_version ( + private_id kms_private_id primary key, + root_key_id kms_private_id not null + constraint kms_root_key_fkey + references kms_root_key(private_id) + on delete cascade + on update cascade, + version kms_version, + key bytea not null + constraint not_empty_key + check ( + length(key) > 0 + ), + create_time kms_timestamp, + constraint kms_root_key_version_root_key_id_version_uq + unique(root_key_id, version) +); +comment on table kms_root_key_version is + 'kms_root_key_version contains versions of a kms_root_key'; + + -- define the immutable fields for kms_root_key_version (all of them) +create trigger kms_immutable_columns +before +update on kms_root_key_version + for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'version', 'key', 'create_time'); + +-- not adding the kms_default_create_time_column or kms_version_column triggers +-- until after we've converted the data (we don't want the timestamp or versions +-- to change) + +create table kms_data_key ( + private_id kms_private_id primary key, + root_key_id kms_private_id not null + constraint kms_root_key_fkey + references kms_root_key(private_id) + on delete cascade + on update cascade, + purpose text not null + constraint not_start_end_whitespace_purpose + check (length(trim(purpose)) = length(purpose)), + create_time kms_timestamp, + constraint kms_data_key_root_key_id_purpose_uq + unique (root_key_id, purpose) -- there can only be one dek for a specific purpose per root key +); +comment on table kms_data_key is + 'kms_data_key contains deks (data keys) for specific purposes'; + + -- define the immutable fields for kms_data_key (all of them) +create trigger kms_immutable_columns +before +update on kms_data_key + for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'purpose', 'create_time'); + +-- not adding the kms_default_create_time_column trigger until after we've +-- converted the data (we don't want the timestamp to change) + +create table kms_data_key_version ( + private_id kms_private_id primary key, + data_key_id kms_private_id not null + constraint kms_data_key_fkey + references kms_data_key(private_id) + on delete cascade + on update cascade, + root_key_version_id kms_private_id not null + constraint kms_root_key_version_fkey + references kms_root_key_version(private_id) + on delete cascade + on update cascade, + version kms_version, + key bytea not null + constraint not_empty_key + check ( + length(key) > 0 + ), + create_time kms_timestamp, + constraint kms_data_key_version_data_key_id_version_uq + unique(data_key_id, version) +); +comment on table kms_data_key is + 'kms_data_key_version contains versions of a kms_data_key (dek aka data keys)'; + + -- define the immutable fields for kms_data_key_version (all of them) +create trigger kms_immutable_columns +before +update on kms_data_key_version + for each row execute procedure immutable_columns('private_id', 'data_key_id', 'root_key_version_id', 'version', 'key', 'create_time'); + +-- not adding the kms_default_create_time_column or kms_version_column triggers +-- until after we've converted the data (we don't want the timestamp or versions +-- to change) + +-- ############################################################################ +-- Next: we will convert all the existing KEKs/DEKs into the new schema model +-- before adding triggers for create_time, and version +-- this is important, especially for the version column! + +-- convert KEK tables +insert into kms_root_key (private_id, scope_id, create_time) +select private_id, scope_id, create_time +from kms_deprecated_root_key; + +insert into kms_root_key_version (private_id, root_key_id, version, key, create_time) +select private_id, root_key_id, version, key, create_time +from kms_deprecated_root_key_version; + +-- convert database DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'database', create_time +from kms_database_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, database_key_id, root_key_version_id, version, key, create_time +from kms_database_key_version; + +-- convert oplog DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'oplog', create_time +from kms_oplog_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, oplog_key_id, root_key_version_id, version, key, create_time +from kms_oplog_key_version; + +-- convert the audit DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'audit', create_time +from kms_audit_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, audit_key_id, root_key_version_id, version, key, create_time +from kms_audit_key_version; + +-- convert the oidc DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'oidc', create_time +from kms_oidc_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, oidc_key_id, root_key_version_id, version, key, create_time +from kms_oidc_key_version; + +-- convert the token DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'tokens', create_time +from kms_token_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, token_key_id, root_key_version_id, version, key, create_time +from kms_token_key_version; + +-- convert the session DEK tables +insert into kms_data_key (private_id, root_key_id, purpose, create_time) +select private_id, root_key_id, 'sessions', create_time +from kms_session_key; + +insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time) +select private_id, session_key_id, root_key_version_id, version, key, create_time +from kms_session_key_version; + +-- ############################################################################ +-- post conversion, we add the required triggers +create trigger kms_default_create_time_column +before +insert on kms_root_key + for each row execute procedure kms_default_create_time(); + +create trigger kms_default_create_time_column +before +insert on kms_root_key_version + for each row execute procedure kms_default_create_time(); + +create trigger kms_version_column +before insert on kms_root_key_version + for each row execute procedure kms_version_column('root_key_id'); + +create trigger default_create_time_column +before +insert on kms_data_key + for each row execute procedure kms_default_create_time(); + +create trigger default_create_time +before +insert on kms_data_key_version + for each row execute procedure kms_default_create_time(); + +create trigger kms_version_column +before insert on kms_data_key_version + for each row execute procedure kms_version_column('data_key_id'); + +-- Next: we will convert all the existing DEKs FKs to the new model +alter table credential_vault_token drop constraint kms_database_key_version_fkey; +alter table credential_vault_token +add constraint kms_data_key_version_fkey + foreign key(key_id) + references kms_data_key_version (private_id) + on delete restrict + on update cascade; + +alter table credential_vault_client_certificate drop constraint kms_database_key_version_fkey; +alter table credential_vault_client_certificate +add constraint kms_data_key_version_fkey + foreign key(key_id) + references kms_data_key_version (private_id) + on delete restrict + on update cascade; + +alter table auth_oidc_method drop constraint kms_database_key_version_fkey; +alter table auth_oidc_method +add constraint kms_data_key_version_fkey + foreign key(key_id) + references kms_data_key_version (private_id) + on delete restrict + on update cascade; + +alter table host_plugin_catalog_secret drop constraint kms_database_key_version_fkey; +alter table host_plugin_catalog_secret +add constraint kms_data_key_version_fkey + foreign key(key_id) + references kms_data_key_version (private_id) + on delete restrict + on update cascade; + +alter table session_credential drop constraint kms_database_key_version_fkey; +alter table session_credential +add constraint kms_data_key_version_fkey + foreign key(key_id) + references kms_data_key_version (private_id) + on delete restrict + on update cascade; + +-- rename tables so we know that they won't be used by mistake +alter table kms_database_key_version rename to kms_deprecated_database_key_version; +alter table kms_database_key rename to kms_deprecated_database_key; + +alter table kms_oplog_key_version rename to kms_deprecated_oplog_key_version; +alter table kms_oplog_key rename to kms_deprecated_oplog_key; + +alter table kms_audit_key_version rename to kms_deprecated_audit_key_version; +alter table kms_audit_key rename to kms_audit_database_key; + +alter table kms_oidc_key_version rename to kms_deprecated_oidc_key_version; +alter table kms_oidc_key rename to kms_deprecated_oidc_key; + +alter table kms_session_key_version rename to kms_deprecated_session_key_version; +alter table kms_session_key rename to kms_deprecated_session_key; + +alter table kms_token_key_version rename to kms_deprecated_token_key_version; +alter table kms_token_key rename to kms_deprecated_token_key; + +commit; \ No newline at end of file diff --git a/internal/db/schema/migrations/oss/postgres_18_01_test.go b/internal/db/schema/migrations/oss/postgres_18_01_test.go deleted file mode 100644 index 7b65ab84a..000000000 --- a/internal/db/schema/migrations/oss/postgres_18_01_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package oss_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/db/common" - "github.com/hashicorp/boundary/internal/db/schema" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/servers" - "github.com/hashicorp/boundary/testing/dbtest" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestMigrations_Nonce(t *testing.T) { - const ( - priorMigration = 16005 - currentMigration = 18001 - ) - - t.Parallel() - assert, require := assert.New(t), require.New(t) - ctx := context.Background() - dialect := dbtest.Postgres - - c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1)) - require.NoError(err) - t.Cleanup(func() { - require.NoError(c()) - }) - d, err := common.SqlOpen(dialect, u) - require.NoError(err) - - // migration to the prior migration (before the one we want to test) - m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err := m.CurrentState(ctx) - require.NoError(err) - want := &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: priorMigration, - DatabaseSchemaVersion: priorMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // get a connection - dbType, err := db.StringToDbType(dialect) - require.NoError(err) - conn, err := db.Open(dbType, u) - require.NoError(err) - rw := db.New(conn) - - // okay, now we can seed the database with test data and validate existing - // functionality. At the end of this we will have two values in the table - // with no purpose. - { - // Create an old version of the struct - type RecoveryNonce struct { - Nonce string - } - - require.NoError(rw.CreateItems(ctx, []interface{}{ - &RecoveryNonce{Nonce: "abcd"}, - &RecoveryNonce{Nonce: "dcba"}, - })) - - var results []*RecoveryNonce - require.NoError(rw.SearchWhere(ctx, &results, "", nil)) - require.Len(results, 2) - } - - // now we're ready for the migration we want to test. - m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err = m.CurrentState(ctx) - require.NoError(err) - want = &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: currentMigration, - DatabaseSchemaVersion: currentMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // now we have migrated and we will validate functionality; we'll do this - // via the repo - { - wrapper := db.TestWrapper(t) - kmsCache := kms.TestKms(t, conn, wrapper) - rw := db.New(conn) - repo, err := servers.NewRepository(rw, rw, kmsCache) - require.NoError(err) - require.NotNil(repo) - - // First list and validate that the upgrade adjusted purpose correctly - results, err := repo.ListNonces(ctx, servers.NoncePurposeRecovery) - require.NoError(err) - assert.Len(results, 2) - for _, n := range results { - assert.Equal(servers.NoncePurposeRecovery, n.Purpose) - } - - // Test the constraint, first via the repo, then directly - const badPurpose = "foobar" - err = repo.AddNonce(ctx, "xyz", badPurpose) - require.Error(err) - assert.Contains(err.Error(), "unknown nonce purpose") - - // Check that null errors - require.Error(rw.CreateItems(ctx, []interface{}{ - &servers.Nonce{Nonce: "dcba"}, - })) - // Check that bad purpose errors - require.Error(rw.CreateItems(ctx, []interface{}{ - &servers.Nonce{Nonce: "dcba", Purpose: badPurpose}, - })) - - // Add some valid values, ensure that we can then list for both purposes - // and get different values - require.NoError(repo.AddNonce(ctx, "wxyz", servers.NoncePurposeWorkerAuth)) - require.NoError(repo.AddNonce(ctx, "zyxw", servers.NoncePurposeWorkerAuth)) - results, err = repo.ListNonces(ctx, servers.NoncePurposeRecovery) - require.NoError(err) - assert.Len(results, 2) - for _, n := range results { - assert.Equal(servers.NoncePurposeRecovery, n.Purpose) - } - results, err = repo.ListNonces(ctx, servers.NoncePurposeWorkerAuth) - require.NoError(err) - assert.Len(results, 2) - for _, n := range results { - assert.Equal(servers.NoncePurposeWorkerAuth, n.Purpose) - } - - // Last: add the same nonce, ensure we error - require.NoError(repo.AddNonce(ctx, "double", servers.NoncePurposeWorkerAuth)) - err = repo.AddNonce(ctx, "double", servers.NoncePurposeWorkerAuth) - require.Error(err) - require.Contains(err.Error(), "duplicate key value") - } -} diff --git a/internal/db/schema/migrations/oss/postgres_24_01_test.go b/internal/db/schema/migrations/oss/postgres_24_01_test.go deleted file mode 100644 index bb1893d4b..000000000 --- a/internal/db/schema/migrations/oss/postgres_24_01_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package oss_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/authtoken" - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/db/common" - "github.com/hashicorp/boundary/internal/db/schema" - "github.com/hashicorp/boundary/internal/host/static" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/session" - "github.com/hashicorp/boundary/internal/target" - "github.com/hashicorp/boundary/internal/target/tcp" - "github.com/hashicorp/boundary/testing/dbtest" - "github.com/stretchr/testify/require" -) - -func TestMigrations_SessionState(t *testing.T) { - t.Parallel() - require := require.New(t) - - const ( - priorMigration = 21002 - currentMigration = 24001 - ) - dialect := dbtest.Postgres - ctx := context.Background() - - c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1)) - require.NoError(err) - t.Cleanup(func() { - require.NoError(c()) - }) - d, err := common.SqlOpen(dialect, u) - require.NoError(err) - - // migration to the prior migration (before the one we want to test) - m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err := m.CurrentState(ctx) - require.NoError(err) - want := &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: priorMigration, - DatabaseSchemaVersion: priorMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // Seed the database with test data - dbType, err := db.StringToDbType(dialect) - require.NoError(err) - - conn, err := db.Open(dbType, u) - require.NoError(err) - - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - require.NotNil(prj) - - hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0] - hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] - static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - - tar := tcp.TestTarget(ctx, t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()})) - - kmsCache := kms.TestKms(t, conn, wrapper) - - { - at := authtoken.TestAuthToken(t, conn, kmsCache, org.GetPublicId()) - uId := at.GetIamUserId() - - sess := session.TestSession(t, conn, wrapper, session.ComposedOf{ - UserId: uId, - HostId: h.GetPublicId(), - TargetId: tar.GetPublicId(), - HostSetId: hs.GetPublicId(), - AuthTokenId: at.GetPublicId(), - ScopeId: prj.GetPublicId(), - Endpoint: "tcp://127.0.0.1:22", - ConnectionLimit: -1, - }) - - session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, - "127.0.0.2", 23, "127.0.0.1") - } - - // now we're ready for the migration we want to test. - m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err = m.CurrentState(ctx) - require.NoError(err) - want = &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: currentMigration, - DatabaseSchemaVersion: currentMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - sessionRepo, err := session.NewRepository(rw, rw, kmsCache) - connectionRepo, err := session.NewConnectionRepository(ctx, rw, rw, kmsCache) - require.NoError(err) - - // Ensure session is cancelled - repoSessions, err := sessionRepo.ListSessions(ctx) - require.NoError(err) - var sessionTermReason []string - var repoSessionId string - for i := 0; i < len(repoSessions); i++ { - s := repoSessions[i] - repoSessionId = s.PublicId - sessionTermReason = append(sessionTermReason, s.TerminationReason) - } - require.Equal([]string{"canceled"}, sessionTermReason) - - // Ensure connection is also cancelled - connections, err := connectionRepo.ListConnectionsBySessionId(ctx, repoSessionId) - require.NoError(err) - - var connTermReason []string - for i := 0; i < len(connections); i++ { - c := connections[i] - connTermReason = append(connTermReason, c.ClosedReason) - } - require.Equal([]string{"canceled"}, connTermReason) - - // Validate new table contents - rows, err := d.QueryContext(ctx, "select * from session_valid_state") - require.NoError(err) - - var validStates []string - for rows.Next() { - var a, b string - require.NoError(rows.Scan(&a, &b)) - validStates = append(validStates, []string{a, b}...) - } - require.Equal([]string{ - "pending", "pending", "pending", "active", "pending", "terminated", - "pending", "canceling", "active", "canceling", "active", "terminated", "canceling", "terminated", - }, validStates) -} diff --git a/internal/db/schema/migrations/oss/postgres_28_02_test.go b/internal/db/schema/migrations/oss/postgres_28_02_test.go deleted file mode 100644 index d10967cd7..000000000 --- a/internal/db/schema/migrations/oss/postgres_28_02_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package oss_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/authtoken" - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/db/common" - "github.com/hashicorp/boundary/internal/db/schema" - "github.com/hashicorp/boundary/internal/host/static" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/session" - "github.com/hashicorp/boundary/internal/target" - "github.com/hashicorp/boundary/internal/target/tcp" - "github.com/hashicorp/boundary/internal/types/resource" - "github.com/hashicorp/boundary/testing/dbtest" - "github.com/stretchr/testify/require" -) - -func TestMigrations_SessionStateTrigger(t *testing.T) { - t.Parallel() - require := require.New(t) - - const ( - priorMigration = 27002 - currentMigration = 28002 - ) - dialect := dbtest.Postgres - ctx := context.Background() - - c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1)) - require.NoError(err) - t.Cleanup(func() { - require.NoError(c()) - }) - d, err := common.SqlOpen(dialect, u) - require.NoError(err) - - // migration to the prior migration (before the one we want to test) - m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err := m.CurrentState(ctx) - require.NoError(err) - want := &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: priorMigration, - DatabaseSchemaVersion: priorMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // Seed the database with test data - dbType, err := db.StringToDbType(dialect) - require.NoError(err) - - conn, err := db.Open(dbType, u) - require.NoError(err) - - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - require.NotNil(prj) - - hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0] - hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] - static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - tar := tcp.TestTarget(ctx, t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()})) - kmsCache := kms.TestKms(t, conn, wrapper) - - serverId := "worker" - tofu := session.TestTofu(t) - session.TestWorker(t, conn, wrapper, session.WithServerId(serverId)) - at := authtoken.TestAuthToken(t, conn, kmsCache, org.GetPublicId()) - uId := at.GetIamUserId() - sess := session.TestSession(t, conn, wrapper, session.ComposedOf{ - UserId: uId, - HostId: h.GetPublicId(), - TargetId: tar.GetPublicId(), - HostSetId: hs.GetPublicId(), - AuthTokenId: at.GetPublicId(), - ScopeId: prj.GetPublicId(), - Endpoint: "tcp://127.0.0.1:22", - ConnectionLimit: 1, - }) - - sessionRepo, err := session.NewRepository(rw, rw, kmsCache) - require.NoError(err) - - // Make and transition a valid session through pending, active, canceling, and terminated - // Unfortunately, could not recreate an invalid session P-A-T-C using the session repo - _, _, err = sessionRepo.ActivateSession(ctx, sess.PublicId, sess.Version, serverId, resource.Worker.String(), tofu) - require.NoError(err) - connection := session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, - "127.0.0.2", 23, "127.0.0.1") - session.TestConnectionState(t, conn, connection.PublicId, session.StatusConnected) - session.TestConnectionState(t, conn, connection.PublicId, session.StatusClosed) - _, err = sessionRepo.CancelSession(ctx, sess.PublicId, sess.Version+1) - require.NoError(err) - sessionRepo.TerminateCompletedSessions(ctx) - - repoSessions, err := sessionRepo.ListSessions(ctx) - require.NoError(err) - var numStates int - for _, s := range repoSessions { - numStates = len(s.States) - } - require.Equal(4, numStates) - - // now we're ready for the migration we want to test. - m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err = m.CurrentState(ctx) - require.NoError(err) - want = &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: currentMigration, - DatabaseSchemaVersion: currentMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // Check that we haven't removed a state - repoSessions, err = sessionRepo.ListSessions(ctx) - require.NoError(err) - for _, s := range repoSessions { - numStates = len(s.States) - } - require.Equal(4, numStates) -} diff --git a/internal/db/schema/migrations/oss/postgres_29_01_test.go b/internal/db/schema/migrations/oss/postgres_29_01_test.go deleted file mode 100644 index 32206bc04..000000000 --- a/internal/db/schema/migrations/oss/postgres_29_01_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package oss_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/authtoken" - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/db/common" - "github.com/hashicorp/boundary/internal/db/schema" - "github.com/hashicorp/boundary/internal/host/static" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/session" - "github.com/hashicorp/boundary/internal/target" - "github.com/hashicorp/boundary/internal/target/tcp" - "github.com/hashicorp/boundary/internal/types/resource" - "github.com/hashicorp/boundary/testing/dbtest" - "github.com/stretchr/testify/require" -) - -func TestMigrations_SessionFKeyDelete(t *testing.T) { - t.Parallel() - require := require.New(t) - - const ( - priorMigration = 28002 - currentMigration = 29001 - ) - dialect := dbtest.Postgres - ctx := context.Background() - - c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1)) - require.NoError(err) - t.Cleanup(func() { - require.NoError(c()) - }) - d, err := common.SqlOpen(dialect, u) - require.NoError(err) - - // migration to the prior migration (before the one we want to test) - m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err := m.CurrentState(ctx) - require.NoError(err) - want := &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: priorMigration, - DatabaseSchemaVersion: priorMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // Seed the database with test data - dbType, err := db.StringToDbType(dialect) - require.NoError(err) - - conn, err := db.Open(dbType, u) - require.NoError(err) - - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - require.NotNil(prj) - - hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0] - hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] - static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - tar := tcp.TestTarget(ctx, t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()})) - kmsCache := kms.TestKms(t, conn, wrapper) - targetRepo, err := target.NewRepository(rw, rw, kmsCache) - require.NoError(err) - - serverId := "worker" - tofu := session.TestTofu(t) - session.TestWorker(t, conn, wrapper, session.WithServerId(serverId)) - at := authtoken.TestAuthToken(t, conn, kmsCache, org.GetPublicId()) - uId := at.GetIamUserId() - sess := session.TestSession(t, conn, wrapper, session.ComposedOf{ - UserId: uId, - HostId: h.GetPublicId(), - TargetId: tar.GetPublicId(), - HostSetId: hs.GetPublicId(), - AuthTokenId: at.GetPublicId(), - ScopeId: prj.GetPublicId(), - Endpoint: "tcp://127.0.0.1:22", - ConnectionLimit: 1, - }) - - sessionRepo, err := session.NewRepository(rw, rw, kmsCache) - require.NoError(err) - - // Create and terminate session without canceling - _, _, err = sessionRepo.ActivateSession(ctx, sess.PublicId, sess.Version, serverId, resource.Worker.String(), tofu) - require.NoError(err) - session.TestState(t, conn, sess.PublicId, session.StatusTerminated) - - // Delete target; expect a session_state violation and failure to delete target - rows, err := targetRepo.DeleteTarget(ctx, tar.GetPublicId()) - require.Errorf(err, "target.(Repository).DeleteTarget: db.DoTx: target.(Repository).DeleteTarget: db.Delete: insert or update on table \"session_state\" violates foreign key constraint \"session_valid_state_enm_fkey\": integrity violation: error #1003") - require.Equal(0, rows) - - // now we're ready for the migration we want to test. - m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( - schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}), - )) - require.NoError(err) - - require.NoError(m.ApplyMigrations(ctx)) - state, err = m.CurrentState(ctx) - require.NoError(err) - want = &schema.State{ - Initialized: true, - Editions: []schema.EditionState{ - { - Name: "oss", - BinarySchemaVersion: currentMigration, - DatabaseSchemaVersion: currentMigration, - DatabaseSchemaState: schema.Equal, - }, - }, - } - require.Equal(want, state) - - // Try to delete target again, should succeed without error - rows, err = targetRepo.DeleteTarget(ctx, tar.GetPublicId()) - require.NoError(err) - require.Equal(1, rows) -} diff --git a/internal/db/schema/migrations/oss/postgres_30_01_test.go b/internal/db/schema/migrations/oss/postgres_30_01_test.go new file mode 100644 index 000000000..539ffd32e --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres_30_01_test.go @@ -0,0 +1,587 @@ +package oss_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/db/common" + "github.com/hashicorp/boundary/internal/db/schema" + "github.com/hashicorp/boundary/internal/iam" + "github.com/hashicorp/boundary/testing/dbtest" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMigrations_KMS_Refactor(t *testing.T) { + const ( + priorMigration = 28002 + currentMigration = 30004 + ) + + t.Parallel() + ctx := context.Background() + dialect := dbtest.Postgres + + c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1)) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, c()) + }) + d, err := common.SqlOpen(dialect, u) + require.NoError(t, err) + + // migration to the prior migration (before the one we want to test) + m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( + schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}), + )) + require.NoError(t, err) + + require.NoError(t, m.ApplyMigrations(ctx)) + state, err := m.CurrentState(ctx) + require.NoError(t, err) + want := &schema.State{ + Initialized: true, + Editions: []schema.EditionState{ + { + Name: "oss", + BinarySchemaVersion: priorMigration, + DatabaseSchemaVersion: priorMigration, + DatabaseSchemaState: schema.Equal, + }, + }, + } + require.Equal(t, want, state) + + // get a connection + dbType, err := db.StringToDbType(dialect) + require.NoError(t, err) + conn, err := db.Open(dbType, u) + require.NoError(t, err) + rw := db.New(conn) + + generateTestKeys(t, rw) + // load up the current KEKs and their versions + existingKeks := loadKeks(t, rw) + existingKeksVersions := loadKekVersions(t, rw) + + // load up the current DEKs and their versions + existingDeks := loadCurrentDeks(t, rw) + existingKeyVersions := loadCurrentDekVersions(t, rw) + + // now we're ready for the migration we want to test. + m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions( + schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}), + )) + require.NoError(t, err) + + require.NoError(t, m.ApplyMigrations(ctx)) + state, err = m.CurrentState(ctx) + require.NoError(t, err) + want = &schema.State{ + Initialized: true, + Editions: []schema.EditionState{ + { + Name: "oss", + BinarySchemaVersion: currentMigration, + DatabaseSchemaVersion: currentMigration, + DatabaseSchemaState: schema.Equal, + }, + }, + } + require.Equal(t, want, state) + // Now read all the converted keys and see if we have transformed them correctly + { + // get a new connection + dbType, err := db.StringToDbType(dialect) + require.NoError(t, err) + conn, err := db.Open(dbType, u) + require.NoError(t, err) + rw := db.New(conn) + + newKeks := loadKeks(t, rw) + assert.ElementsMatch(t, newKeks, existingKeks) + + newKeksVersions := loadKekVersions(t, rw) + assert.ElementsMatch(t, newKeksVersions, existingKeksVersions) + + newDeks := loadNewDeks(t, rw) + assert.ElementsMatch(t, newDeks, existingDeks) + + newKeyVersions := loadNewDekVersions(t, rw) + assert.ElementsMatch(t, newKeyVersions, existingKeyVersions) + } +} + +// we can't use the new KMS bits since all the tables have changed, so we'll +// generate a bit of test data by hand +func generateTestKeys(t *testing.T, rw *db.Db) { + t.Helper() + require := require.New(t) + testCtx := context.Background() + + for i := 0; i < 10; i++ { + k := kek{ + PrivateId: testId(t, "rk"), + ScopeId: testScope(t, rw).PublicId, + } + require.NoError(rw.Create(testCtx, &k)) + + var kv kekVersion + for i := 0; i < 2; i++ { + kv = kekVersion{ + PrivateId: testId(t, "rkv"), + RootKeyId: k.PrivateId, + Version: 1 + uint32(i), + Key: []byte("test-key"), + } + require.NoError(rw.Create(testCtx, &kv)) + } + + { + dbk := kmsDatabaseKey{ + PrivateId: testId(t, "dk"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &dbk)) + dbkv := kmsDatabaseKeyVersion{ + PrivateId: testId(t, "dkv"), + DatabaseKeyId: dbk.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &dbkv)) + } + { + ak := kmsAuditKey{ + PrivateId: testId(t, "ak"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &ak)) + akv := kmsAuditKeyVersion{ + PrivateId: testId(t, "dkv"), + AuditKeyId: ak.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &akv)) + } + { + oidck := kmsOidcKey{ + PrivateId: testId(t, "oidck"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &oidck)) + oidckv := kmsOidcKeyVersion{ + PrivateId: testId(t, "dkv"), + OidcKeyId: oidck.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &oidckv)) + } + { + opk := kmsOplogKey{ + PrivateId: testId(t, "opk"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &opk)) + opkv := kmsOplogKeyVersion{ + PrivateId: testId(t, "dkv"), + OplogKeyId: opk.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &opkv)) + } + { + sk := kmsSessionKey{ + PrivateId: testId(t, "sk"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &sk)) + skv := kmsSessionKeyVersion{ + PrivateId: testId(t, "dkv"), + SessionKeyId: sk.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &skv)) + } + { + tk := kmsTokenKey{ + PrivateId: testId(t, "tk"), + RootKeyId: k.PrivateId, + } + require.NoError(rw.Create(testCtx, &tk)) + tkv := kmsTokenKeyVersion{ + PrivateId: testId(t, "dkv"), + TokenKeyId: tk.PrivateId, + RootKeyVersionId: kv.PrivateId, + Key: []byte("test-key"), + Version: 1, + } + require.NoError(rw.Create(testCtx, &tkv)) + } + + } +} + +func loadKeks(t *testing.T, rw *db.Db) []kek { + t.Helper() + testCtx := context.Background() + rows, err := rw.Query(testCtx, `select private_id, scope_id, create_time from kms_root_key order by private_id`, nil) + require.NoError(t, err) + require.NoError(t, err) + var keks []kek + for rows.Next() { + var key kek + require.NoError(t, rw.ScanRows(context.Background(), rows, &key)) + keks = append(keks, key) + } + return keks +} + +func loadKekVersions(t *testing.T, rw *db.Db) []kekVersion { + t.Helper() + testCtx := context.Background() + rows, err := rw.Query(testCtx, `select private_id, root_key_id, version, key, create_time from kms_root_key_version order by private_id`, nil) + require.NoError(t, err) + require.NoError(t, err) + var kekVersions []kekVersion + for rows.Next() { + var v kekVersion + require.NoError(t, rw.ScanRows(context.Background(), rows, &v)) + kekVersions = append(kekVersions, v) + } + return kekVersions +} + +func loadNewDeks(t *testing.T, rw *db.Db) []dek { + t.Helper() + testCtx := context.Background() + rows, err := rw.Query(testCtx, `select private_id, root_key_id, create_time, purpose from kms_data_key order by private_id`, nil) + require.NoError(t, err) + require.NoError(t, err) + var deks []dek + for rows.Next() { + var key dek + require.NoError(t, rw.ScanRows(context.Background(), rows, &key)) + deks = append(deks, key) + } + return deks +} + +func loadCurrentDeks(t *testing.T, rw *db.Db) []dek { + t.Helper() + testCtx := context.Background() + var deks []dek + for _, purpose := range []string{"audit", "database", "oidc", "oplog", "sessions", "tokens"} { + var table string + switch purpose { + case "audit": + table = "kms_audit_key" + case "database": + table = "kms_database_key" + case "oidc": + table = "kms_oidc_key" + case "oplog": + table = "kms_oplog_key" + case "sessions": + table = "kms_session_key" + case "tokens": + table = "kms_token_key" + default: + t.Fatalf("not a supported dek %q", purpose) + } + sql := fmt.Sprintf(`select private_id, root_key_id, create_time, '%s' as purpose from %s order by private_id`, purpose, table) + rows, err := rw.Query(testCtx, sql, nil) + require.NoError(t, err) + require.NoError(t, err) + for rows.Next() { + var key dek + require.NoError(t, rw.ScanRows(context.Background(), rows, &key)) + deks = append(deks, key) + } + } + return deks +} + +func loadNewDekVersions(t *testing.T, rw *db.Db) []dekVersion { + t.Helper() + testCtx := context.Background() + rows, err := rw.Query(testCtx, `select private_id, data_key_id, root_key_version_id, version, key, create_time from kms_data_key_version order by private_id`, nil) + require.NoError(t, err) + require.NoError(t, err) + var dekVersions []dekVersion + for rows.Next() { + var v dekVersion + require.NoError(t, rw.ScanRows(context.Background(), rows, &v)) + dekVersions = append(dekVersions, v) + } + return dekVersions +} + +func loadCurrentDekVersions(t *testing.T, rw *db.Db) []dekVersion { + t.Helper() + testCtx := context.Background() + var dekVersions []dekVersion + for _, versionType := range []string{"audit", "database", "oidc", "oplog", "session", "token"} { + var table string + switch versionType { + case "audit": + table = "kms_audit_key_version" + case "database": + table = "kms_database_key_version" + case "oidc": + table = "kms_oidc_key_version" + case "oplog": + table = "kms_oplog_key_version" + case "session": + table = "kms_session_key_version" + case "token": + table = "kms_token_key_version" + } + sql := fmt.Sprintf(`select private_id, %s_key_id, root_key_version_id, key, version, create_time from %s order by private_id`, versionType, table) + rows, err := rw.Query(testCtx, sql, nil) + require.NoError(t, err) + require.NoError(t, err) + for rows.Next() { + result := map[string]interface{}{} + require.NoError(t, rw.ScanRows(context.Background(), rows, &result)) + var v dekVersion + switch versionType { + case "audit": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["audit_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + case "database": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["database_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + case "oidc": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["oidc_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + case "oplog": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["oplog_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + case "session": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["session_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + case "token": + v = dekVersion{ + PrivateId: result["private_id"].(string), + DataKeyId: result["token_key_id"].(string), + RootKeyVersionId: result["root_key_version_id"].(string), + Key: result["key"].([]byte), + Version: uint32(result["version"].(int64)), + CreateTime: result["create_time"].(time.Time), + } + } + dekVersions = append(dekVersions, v) + } + } + return dekVersions +} + +func testId(t testing.TB, prefix string) string { + t.Helper() + id, err := db.NewPublicId(prefix) + require.NoError(t, err) + return id +} + +func testScope(t *testing.T, rw *db.Db) *iam.Scope { + t.Helper() + require := require.New(t) + testCtx := context.Background() + + s, err := iam.NewOrg() + require.NoError(err) + s.PublicId = testId(t, "o") + + require.NoError(rw.Create(testCtx, &s)) + return s +} + +type kek struct { + PrivateId string + ScopeId string + CreateTime time.Time +} + +func (*kek) TableName() string { return "kms_root_key" } + +type kekVersion struct { + PrivateId string + RootKeyId string + Version uint32 + Key []byte + CreateTime time.Time +} + +func (*kekVersion) TableName() string { return "kms_root_key_version" } + +type dek struct { + PrivateId string + RootKeyId string + CreateTime time.Time + Purpose string +} +type dekVersion struct { + PrivateId string + DataKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +type kmsDatabaseKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsDatabaseKey) TableName() string { return "kms_database_key" } + +type kmsDatabaseKeyVersion struct { + PrivateId string + DatabaseKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsDatabaseKeyVersion) TableName() string { return "kms_database_key_version" } + +type kmsAuditKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsAuditKey) TableName() string { return "kms_audit_key" } + +type kmsAuditKeyVersion struct { + PrivateId string + AuditKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsAuditKeyVersion) TableName() string { return "kms_audit_key_version" } + +type kmsOidcKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsOidcKey) TableName() string { return "kms_oidc_key" } + +type kmsOidcKeyVersion struct { + PrivateId string + OidcKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsOidcKeyVersion) TableName() string { return "kms_oidc_key_version" } + +type kmsOplogKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsOplogKey) TableName() string { return "kms_oplog_key" } + +type kmsOplogKeyVersion struct { + PrivateId string + OplogKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsOplogKeyVersion) TableName() string { return "kms_oplog_key_version" } + +type kmsSessionKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsSessionKey) TableName() string { return "kms_session_key" } + +type kmsSessionKeyVersion struct { + PrivateId string + SessionKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsSessionKeyVersion) TableName() string { return "kms_session_key_version" } + +type kmsTokenKey struct { + PrivateId string + RootKeyId string + CreateTime time.Time +} + +func (*kmsTokenKey) TableName() string { return "kms_token_key" } + +type kmsTokenKeyVersion struct { + PrivateId string + TokenKeyId string + RootKeyVersionId string + Key []byte + Version uint32 + CreateTime time.Time +} + +func (*kmsTokenKeyVersion) TableName() string { return "kms_token_key_version" } diff --git a/internal/db/sqltest/initdb.d/03_widgets_persona.sql b/internal/db/sqltest/initdb.d/03_widgets_persona.sql index 8abbb0b49..c6aef2661 100644 --- a/internal/db/sqltest/initdb.d/03_widgets_persona.sql +++ b/internal/db/sqltest/initdb.d/03_widgets_persona.sql @@ -105,13 +105,13 @@ begin; values ('krkv___widget', 'krk___widget', 'krk___widget'::bytea); - insert into kms_database_key - (private_id, root_key_id) + insert into kms_data_key + (private_id, root_key_id, purpose) values - ('kdk____widget', 'krk___widget'); + ('kdk____widget', 'krk___widget', 'database'); - insert into kms_database_key_version - (private_id, database_key_id, root_key_version_id, key) + insert into kms_data_key_version + (private_id, data_key_id, root_key_version_id, key) values ('kdkv___widget', 'kdk____widget', 'krkv___widget', 'kdk____widget'::bytea); diff --git a/internal/iam/repository_scope.go b/internal/iam/repository_scope.go index 6db6c0256..103196700 100644 --- a/internal/iam/repository_scope.go +++ b/internal/iam/repository_scope.go @@ -31,7 +31,6 @@ func (r *Repository) CreateScope(ctx context.Context, s *Scope, userId string, o } var parentOplogWrapper wrapping.Wrapper - var externalWrappers *kms.ExternalWrappers var err error switch s.Type { case scope.Unknown.String(): @@ -47,7 +46,6 @@ func (r *Repository) CreateScope(ctx context.Context, s *Scope, userId string, o default: parentOplogWrapper, err = r.kms.GetWrapper(ctx, s.ParentId, kms.KeyPurposeOplog) } - externalWrappers = r.kms.GetExternalWrappers() } if err != nil { return nil, errors.New(ctx, errors.InvalidParameter, op, "unable to get oplog wrapper") @@ -174,17 +172,17 @@ func (r *Repository) CreateScope(ctx context.Context, s *Scope, userId string, o s := scopeRaw.(*Scope) - // Create the scope's keys - _, err = kms.CreateKeysTx(ctx, dbr, w, externalWrappers.Root(), reader, s.PublicId) + txnKms, err := kms.NewUsingReaderWriter(ctx, dbr, w) if err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("error creating transaction's kms")) + } + if err := txnKms.AddExternalWrappers(ctx, kms.WithRootWrapper(r.kms.GetExternalWrappers(ctx).Root())); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("error adding external root wrapper to transaction's kms")) + } + if err := txnKms.CreateKeys(ctx, s.PublicId, kms.WithRandomReader(reader), kms.WithReaderWriter(dbr, w)); err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("error creating scope keys")) } - - kmsRepo, err := kms.NewRepository(dbr, w) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg("error creating new kms repo")) - } - childOplogWrapper, err := r.kms.GetWrapper(ctx, s.PublicId, kms.KeyPurposeOplog, kms.WithRepository(kmsRepo)) + childOplogWrapper, err := txnKms.GetWrapper(ctx, s.PublicId, kms.KeyPurposeOplog) if err != nil { return errors.New(ctx, errors.InvalidParameter, op, "unable to get oplog wrapper") } diff --git a/internal/iam/repository_test.go b/internal/iam/repository_test.go index bb1b4d4a9..7b27a264d 100644 --- a/internal/iam/repository_test.go +++ b/internal/iam/repository_test.go @@ -160,8 +160,8 @@ func Test_Repository_delete(t *testing.T) { err = db.TestVerifyOplog(t, rw, s.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(5*time.Second)) require.NoError(err) }) - rk := kms.AllocRootKey() - db.TestDeleteWhere(t, conn, &rk, "1=1") + kms.TestKmsDeleteAllKeys(t, conn) + t.Run("nil-resource", func(t *testing.T) { assert, require := assert.New(t), require.New(t) diff --git a/internal/iam/testing.go b/internal/iam/testing.go index 81f9cb3be..e5e782863 100644 --- a/internal/iam/testing.go +++ b/internal/iam/testing.go @@ -24,7 +24,7 @@ func TestRepo(t testing.TB, conn *db.DB, rootWrapper wrapping.Wrapper, opt ...Op kmsCache := kms.TestKms(t, conn, rootWrapper) wrapper, err := kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeOplog) if err != nil { - _, err = kms.CreateKeysTx(context.Background(), rw, rw, rootWrapper, rand.Reader, scope.Global.String()) + err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader)) require.NoError(err) wrapper, err = kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeOplog) if err != nil { diff --git a/internal/kms/audit_key.go b/internal/kms/audit_key.go deleted file mode 100644 index 91bbb956d..000000000 --- a/internal/kms/audit_key.go +++ /dev/null @@ -1,82 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultAuditKeyTableName = "kms_audit_key" -) - -type AuditKey struct { - *store.AuditKey - tableName string `gorm:"-"` -} - -// NewAuditKey creates a new in memory audit key. This key is used for crypto -// operations on audit entries. No options are currently supported. -func NewAuditKey(ctx context.Context, rootKeyId string, _ ...Option) (*AuditKey, error) { - const op = "kms.NewAuditKey" - if rootKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - k := &AuditKey{ - AuditKey: &store.AuditKey{ - RootKeyId: rootKeyId, - }, - } - return k, nil -} - -// AllocAuditKey will allocate a AuditKey -func AllocAuditKey() AuditKey { - return AuditKey{ - AuditKey: &store.AuditKey{}, - } -} - -// Clone creates a clone of the AuditKey -func (k *AuditKey) Clone() interface{} { - cp := proto.Clone(k.AuditKey) - return &AuditKey{ - AuditKey: cp.(*store.AuditKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *AuditKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(AuditKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *AuditKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultAuditKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *AuditKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/audit_key_test.go b/internal/kms/audit_key_test.go deleted file mode 100644 index 2037a4ae2..000000000 --- a/internal/kms/audit_key_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the AuditKey attributes are -// immutable and those tests are covered by TestAuditKey_ImmutableFields - -func TestAuditKey_Create(t *testing.T) { - t.Parallel() - testCtx := context.Background() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.AuditKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.AuditKey { - k := kms.AllocAuditKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKey(); return &i }(), "1=1") - got, err := kms.NewAuditKey(testCtx, tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.AuditKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestAuditKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.AuditKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestAuditKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.AuditKey { - k := kms.AllocAuditKey() - id, err := db.NewPublicId(kms.AuditKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocAuditKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocAuditKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestAuditKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestAuditKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.AuditKey).AuditKey, k.AuditKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestAuditKey(t, conn, rk.PrivateId) - k2 := kms.TestAuditKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.AuditKey).AuditKey, k2.AuditKey)) - }) -} - -func TestAuditKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultAuditKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocAuditKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocAuditKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/audit_key_version.go b/internal/kms/audit_key_version.go deleted file mode 100644 index cb5971e65..000000000 --- a/internal/kms/audit_key_version.go +++ /dev/null @@ -1,122 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultAuditKeyVersionTableName = "kms_audit_key_version" -) - -type AuditKeyVersion struct { - *store.AuditKeyVersion - tableName string `gorm:"-"` -} - -// NewAuditKeyVersion creates a new in memory audit key version. This key is -// used for crypto operations on audit entries. No options are currently -// supported. -func NewAuditKeyVersion(ctx context.Context, auditKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*AuditKeyVersion, error) { - const op = "kms.NewAuditKeyVersion" - if auditKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing audit key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - - k := &AuditKeyVersion{ - AuditKeyVersion: &store.AuditKeyVersion{ - AuditKeyId: auditKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocAuditKeyVersion allocates a AuditKeyVersion -func AllocAuditKeyVersion() AuditKeyVersion { - return AuditKeyVersion{ - AuditKeyVersion: &store.AuditKeyVersion{}, - } -} - -// Clone creates a clone of the AuditKeyVersion -func (k *AuditKeyVersion) Clone() interface{} { - cp := proto.Clone(k.AuditKeyVersion) - return &AuditKeyVersion{ - AuditKeyVersion: cp.(*store.AuditKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the audit key -// version before it's written. -func (k *AuditKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(AuditKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.AuditKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing audit key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *AuditKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultAuditKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *AuditKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the audit key version's key -func (k *AuditKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(AuditKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.AuditKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.AuditKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the audit key version's key -func (k *AuditKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(AuditKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.AuditKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.AuditKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/audit_key_version_test.go b/internal/kms/audit_key_version_test.go deleted file mode 100644 index 431f617d8..000000000 --- a/internal/kms/audit_key_version_test.go +++ /dev/null @@ -1,250 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the AuditKeyVersion attributes are -// immutable and those tests are covered by TestAuditKey_ImmutableFields - -func TestAuditKeyVersion_Create(t *testing.T) { - t.Parallel() - testCtx := context.Background() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - type args struct { - AuditKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.AuditKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-audit-id", - args: args{ - key: []byte("audit key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - AuditKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - AuditKeyId: dk.PrivateId, - key: []byte("audit key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - AuditKeyId: dk.PrivateId, - key: []byte("audit key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.AuditKeyVersion { - k := kms.AllocAuditKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("audit key") - k.AuditKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKeyVersion(); return &i }(), "1=1") - got, err := kms.NewAuditKeyVersion(testCtx, tt.args.AuditKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.AuditKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestAuditKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.AuditKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestAuditKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("audit key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.AuditKeyVersion { - k := kms.AllocAuditKeyVersion() - id, err := db.NewPublicId(kms.AuditKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocAuditKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocAuditKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestAuditKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestAuditKey(t, conn, rk.PrivateId) - kv := kms.TestAuditKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.AuditKeyVersion).AuditKeyVersion, kv.AuditKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestAuditKey(t, conn, rk.PrivateId) - k2 := kms.TestAuditKey(t, conn, rk2.PrivateId) - kv := kms.TestAuditKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - kv2 := kms.TestAuditKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test db key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.AuditKeyVersion).AuditKeyVersion, kv2.AuditKeyVersion)) - }) -} - -func TestAuditKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultAuditKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocAuditKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocAuditKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/const.go b/internal/kms/const.go index 54020a20d..a08fddf3d 100644 --- a/internal/kms/const.go +++ b/internal/kms/const.go @@ -24,6 +24,9 @@ const ( // KeyPurposeRecovery is used for recovery access KeyPurposeRecovery + // KeyPurposeWorkerAuth is used for worker auth + KeyPurposeWorkerAuth + // KeyPurposeTokens is used for token encryption KeyPurposeTokens @@ -36,6 +39,9 @@ const ( // KeyPurposeAudit is used for audit operations KeyPurposeAudit + + // KeyPurposeRootKey is used as the root key + KeyPurposeRootKey ) // String returns the key purpose cast as a string, just so it can be called as @@ -48,6 +54,8 @@ func (k KeyPurpose) String() string { return "oplog" case KeyPurposeRecovery: return "recovery" + case KeyPurposeWorkerAuth: + return "workerauth" case KeyPurposeTokens: return "tokens" case KeyPurposeSessions: @@ -56,67 +64,21 @@ func (k KeyPurpose) String() string { return "oidc" case KeyPurposeAudit: return "audit" - default: - return "unknown" - } -} - -// KeyType allows the kms repo to return a map[KeyType]Key which can be easily -// used without type casting. -type KeyType uint - -const ( - KeyTypeUnknown KeyType = iota - KeyTypeRootKey - KeyTypeRootKeyVersion - KeyTypeDatabaseKey - KeyTypeDatabaseKeyVersion - KeyTypeOplogKey - KeyTypeOplogKeyVersion - KeyTypeTokenKey - KeyTypeTokenKeyVersion - KeyTypeSessionKey - KeyTypeSessionKeyVersion - KeyTypeOidcKey - KeyTypeOidcKeyVersion - KeyTypeAuditKey - KeyTypeAuditKeyVersion -) - -// String returns the key type cast as a string, just so it can be called as -// a function instead of direct casting elsewhere, yw -func (k KeyType) String() string { - switch k { - case KeyTypeRootKey: + case KeyPurposeRootKey: return "rootKey" - case KeyTypeRootKeyVersion: - return "rootKeyVersion" - case KeyTypeDatabaseKey: - return "databaseKey" - case KeyTypeDatabaseKeyVersion: - return "databaseKeyVersion" - case KeyTypeOplogKey: - return "oplogKey" - case KeyTypeOplogKeyVersion: - return "oplogKeyVersion" - case KeyTypeTokenKey: - return "tokenKey" - case KeyTypeTokenKeyVersion: - return "tokenKeyVersion" - case KeyTypeSessionKey: - return "sessionKey" - case KeyTypeSessionKeyVersion: - return "sessionKeyVersion" - case KeyTypeOidcKey: - return "oidcKey" - case KeyTypeOidcKeyVersion: - return "oidcKeyVersion" - case KeyTypeAuditKey: - return "auditKey" - case KeyTypeAuditKeyVersion: - return "auditKeyVersion" - default: return "unknown" } } + +// ValidDekPurposes returns the current list of valid DEK key purposes +func ValidDekPurposes() []KeyPurpose { + return []KeyPurpose{ + KeyPurposeDatabase, + KeyPurposeOplog, + KeyPurposeTokens, + KeyPurposeSessions, + KeyPurposeOidc, + KeyPurposeAudit, + } +} diff --git a/internal/kms/database_key.go b/internal/kms/database_key.go deleted file mode 100644 index ae81f2674..000000000 --- a/internal/kms/database_key.go +++ /dev/null @@ -1,82 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultDatabaseKeyTableName = "kms_database_key" -) - -type DatabaseKey struct { - *store.DatabaseKey - tableName string `gorm:"-"` -} - -// NewDatabaseKey creates a new in memory database key. No options -// are currently supported. -func NewDatabaseKey(rootKeyId string, _ ...Option) (*DatabaseKey, error) { - const op = "kms.NewDatabaseKey" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - c := &DatabaseKey{ - DatabaseKey: &store.DatabaseKey{ - RootKeyId: rootKeyId, - }, - } - return c, nil -} - -// AllocDatabaseKey will allocate a DatabaseKey -func AllocDatabaseKey() DatabaseKey { - return DatabaseKey{ - DatabaseKey: &store.DatabaseKey{}, - } -} - -// Clone creates a clone of the DatabaseKey -func (k *DatabaseKey) Clone() interface{} { - cp := proto.Clone(k.DatabaseKey) - return &DatabaseKey{ - DatabaseKey: cp.(*store.DatabaseKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *DatabaseKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(DatabaseKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *DatabaseKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultDatabaseKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *DatabaseKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/database_key_test.go b/internal/kms/database_key_test.go deleted file mode 100644 index 340a562b7..000000000 --- a/internal/kms/database_key_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the DatabaseKey attributes are -// immutable and those tests are covered by TestDatabaseKey_ImmutableFields - -func TestDatabaseKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.DatabaseKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.DatabaseKey { - k := kms.AllocDatabaseKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKey(); return &i }(), "1=1") - got, err := kms.NewDatabaseKey(tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.DatabaseKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestDatabaseKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.DatabaseKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestDatabaseKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.DatabaseKey { - k := kms.AllocDatabaseKey() - id, err := db.NewPublicId(kms.DatabaseKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocDatabaseKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocDatabaseKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestDatabaseKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestDatabaseKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.DatabaseKey).DatabaseKey, k.DatabaseKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestDatabaseKey(t, conn, rk.PrivateId) - k2 := kms.TestDatabaseKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.DatabaseKey).DatabaseKey, k2.DatabaseKey)) - }) -} - -func TestDatabaseKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultDatabaseKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocDatabaseKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocDatabaseKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/database_key_version.go b/internal/kms/database_key_version.go deleted file mode 100644 index d2787a706..000000000 --- a/internal/kms/database_key_version.go +++ /dev/null @@ -1,121 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultDatabaseKeyVersionTableName = "kms_database_key_version" -) - -type DatabaseKeyVersion struct { - *store.DatabaseKeyVersion - tableName string `gorm:"-"` -} - -// NewDatabaseKeyVersion creates a new in memory database key version. No options are -// currently supported. -func NewDatabaseKeyVersion(databaseKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*DatabaseKeyVersion, error) { - const op = "kms.NewDatabaseKeyVersion" - if databaseKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing database key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key version id") - } - - k := &DatabaseKeyVersion{ - DatabaseKeyVersion: &store.DatabaseKeyVersion{ - DatabaseKeyId: databaseKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocDatabaseKeyVersion allocates a DatabaseKeyVersion -func AllocDatabaseKeyVersion() DatabaseKeyVersion { - return DatabaseKeyVersion{ - DatabaseKeyVersion: &store.DatabaseKeyVersion{}, - } -} - -// Clone creates a clone of the DatabaseKeyVersion -func (k *DatabaseKeyVersion) Clone() interface{} { - cp := proto.Clone(k.DatabaseKeyVersion) - return &DatabaseKeyVersion{ - DatabaseKeyVersion: cp.(*store.DatabaseKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the database key -// version before it's written. -func (k *DatabaseKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(DatabaseKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.DatabaseKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing database key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *DatabaseKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultDatabaseKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *DatabaseKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the database key version's key -func (k *DatabaseKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(DatabaseKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.DatabaseKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.DatabaseKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the database key version's key -func (k *DatabaseKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(DatabaseKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.DatabaseKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.DatabaseKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/database_key_version_test.go b/internal/kms/database_key_version_test.go deleted file mode 100644 index a879b6997..000000000 --- a/internal/kms/database_key_version_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the DatabaseKeyVersion attributes are -// immutable and those tests are covered by TestDatabaseKey_ImmutableFields - -func TestDatabaseKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - type args struct { - databaseKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.DatabaseKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-database-id", - args: args{ - key: []byte("database key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - databaseKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - databaseKeyId: dk.PrivateId, - key: []byte("database key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - databaseKeyId: dk.PrivateId, - key: []byte("database key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.DatabaseKeyVersion { - k := kms.AllocDatabaseKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("database key") - k.DatabaseKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKeyVersion(); return &i }(), "1=1") - got, err := kms.NewDatabaseKeyVersion(tt.args.databaseKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.DatabaseKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestDatabaseKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.DatabaseKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("database key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.DatabaseKeyVersion { - k := kms.AllocDatabaseKeyVersion() - id, err := db.NewPublicId(kms.DatabaseKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocDatabaseKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocDatabaseKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestDatabaseKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestDatabaseKey(t, conn, rk.PrivateId) - kv := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.DatabaseKeyVersion).DatabaseKeyVersion, kv.DatabaseKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestDatabaseKey(t, conn, rk.PrivateId) - k2 := kms.TestDatabaseKey(t, conn, rk2.PrivateId) - kv := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - kv2 := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test db key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.DatabaseKeyVersion).DatabaseKeyVersion, kv2.DatabaseKeyVersion)) - }) -} - -func TestDatabaseKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultDatabaseKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocDatabaseKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocDatabaseKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/external_wrappers.go b/internal/kms/external_wrappers.go new file mode 100644 index 000000000..48507f12d --- /dev/null +++ b/internal/kms/external_wrappers.go @@ -0,0 +1,28 @@ +package kms + +import ( + wrapping "github.com/hashicorp/go-kms-wrapping/v2" +) + +// ExternalWrappers holds wrappers defined outside of Boundary, e.g. in its +// configuration file. +type ExternalWrappers struct { + root wrapping.Wrapper + workerAuth wrapping.Wrapper + recovery wrapping.Wrapper +} + +// Root returns the wrapper for root keys +func (e *ExternalWrappers) Root() wrapping.Wrapper { + return e.root +} + +// WorkerAuth returns the wrapper for worker authentication +func (e *ExternalWrappers) WorkerAuth() wrapping.Wrapper { + return e.workerAuth +} + +// Recovery returns the wrapper for recovery operations +func (e *ExternalWrappers) Recovery() wrapping.Wrapper { + return e.recovery +} diff --git a/internal/kms/external_wrappers_test.go b/internal/kms/external_wrappers_test.go new file mode 100644 index 000000000..be43c61a6 --- /dev/null +++ b/internal/kms/external_wrappers_test.go @@ -0,0 +1,46 @@ +package kms + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/boundary/internal/db" + wrapping "github.com/hashicorp/go-kms-wrapping/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExternalWrappers(t *testing.T) { + t.Parallel() + assert, require := assert.New(t), require.New(t) + + testCtx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rootWrapper := db.TestWrapper(t) + recoveryWrapper := db.TestWrapper(t) + workerAuthWrapper := db.TestWrapper(t) + + k := TestKms(t, conn, rootWrapper) + err := k.AddExternalWrappers(testCtx, WithRecoveryWrapper(recoveryWrapper), WithWorkerAuthWrapper(workerAuthWrapper)) + require.NoError(err) + + assert.Equal(rootWrapper, k.GetExternalWrappers(testCtx).Root()) + assert.Equal(recoveryWrapper, k.GetExternalWrappers(testCtx).Recovery()) + assert.Equal(workerAuthWrapper, k.GetExternalWrappers(testCtx).WorkerAuth()) + + err = k.AddExternalWrappers(testCtx, WithRootWrapper(&invalidWrapper{})) + assert.Error(err) + err = k.AddExternalWrappers(testCtx, WithRecoveryWrapper(&invalidWrapper{})) + assert.Error(err) + err = k.AddExternalWrappers(testCtx, WithWorkerAuthWrapper(&invalidWrapper{})) + assert.Error(err) +} + +type invalidWrapper struct { + wrapping.Wrapper +} + +func (w *invalidWrapper) KeyId(context.Context) (string, error) { + return "", fmt.Errorf("invalid-error") +} diff --git a/internal/kms/ids.go b/internal/kms/ids.go deleted file mode 100644 index d4c021ff0..000000000 --- a/internal/kms/ids.go +++ /dev/null @@ -1,151 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" -) - -const ( - RootKeyPrefix = "krk" - RootKeyVersionPrefix = "krkv" - DatabaseKeyPrefix = "kdk" - DatabaseKeyVersionPrefix = "kdkv" - OplogKeyPrefix = "kopk" - OplogKeyVersionPrefix = "kopkv" - TokenKeyPrefix = "ktk" - TokenKeyVersionPrefix = "ktv" - SessionKeyPrefix = "ksk" - SessionKeyVersionPrefix = "kskv" - OidcKeyPrefix = "koidck" - OidcKeyVersionPrefix = "koidckv" - AuditKeyPrefix = "kak" - AuditKeyVersionPrefix = "kakv" -) - -func newRootKeyId() (string, error) { - const op = "kms.newRootKeyId" - id, err := db.NewPublicId(RootKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newRootKeyVersionId() (string, error) { - const op = "kms.newRootKeyVersionId" - id, err := db.NewPublicId(RootKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newDatabaseKeyId() (string, error) { - const op = "kms.newDatabaseKeyId" - id, err := db.NewPublicId(DatabaseKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newDatabaseKeyVersionId() (string, error) { - const op = "kms.newDatabaseKeyVersionId" - id, err := db.NewPublicId(DatabaseKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newOplogKeyId() (string, error) { - const op = "kms.newOplogKeyId" - id, err := db.NewPublicId(OplogKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newOplogKeyVersionId() (string, error) { - const op = "kms.newOplogKeyVersionId" - id, err := db.NewPublicId(OplogKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newTokenKeyId() (string, error) { - const op = "kms.newTokenKeyId" - id, err := db.NewPublicId(TokenKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newTokenKeyVersionId() (string, error) { - const op = "kms.newTokenKeyVersionId" - id, err := db.NewPublicId(TokenKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newSessionKeyId() (string, error) { - const op = "kms.newSessionKeyId" - id, err := db.NewPublicId(SessionKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newSessionKeyVersionId() (string, error) { - const op = "kms.newSessionKeyVersionId" - id, err := db.NewPublicId(SessionKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newOidcKeyId() (string, error) { - const op = "kms.newOidcKeyId" - id, err := db.NewPublicId(OidcKeyPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newOidcKeyVersionId() (string, error) { - const op = "kms.newOidcKeyVersionId" - id, err := db.NewPublicId(OidcKeyVersionPrefix) - if err != nil { - return "", errors.WrapDeprecated(err, op) - } - return id, nil -} - -func newAuditKeyId(ctx context.Context) (string, error) { - const op = "kms.newAuditKeyId" - id, err := db.NewPublicId(AuditKeyPrefix) - if err != nil { - return "", errors.Wrap(ctx, err, op) - } - return id, nil -} - -func newAuditKeyVersionId(ctx context.Context) (string, error) { - const op = "kms.newAuditKeyVersionId" - id, err := db.NewPublicId(AuditKeyVersionPrefix) - if err != nil { - return "", errors.Wrap(ctx, err, op) - } - return id, nil -} diff --git a/internal/kms/ids_test.go b/internal/kms/ids_test.go deleted file mode 100644 index 3cb2a3b51..000000000 --- a/internal/kms/ids_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package kms - -import ( - "context" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Ids(t *testing.T) { - t.Parallel() - t.Run("krk", func(t *testing.T) { - id, err := newRootKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, RootKeyPrefix+"_")) - }) - t.Run("krkv", func(t *testing.T) { - id, err := newRootKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, RootKeyVersionPrefix+"_")) - }) - t.Run("kdk", func(t *testing.T) { - id, err := newDatabaseKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, DatabaseKeyPrefix+"_")) - }) - t.Run("kdkv", func(t *testing.T) { - id, err := newDatabaseKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, DatabaseKeyVersionPrefix+"_")) - }) - t.Run("kopk", func(t *testing.T) { - id, err := newOplogKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, OplogKeyPrefix+"_")) - }) - t.Run("kopkv", func(t *testing.T) { - id, err := newOplogKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, OplogKeyVersionPrefix+"_")) - }) - t.Run("ktk", func(t *testing.T) { - id, err := newTokenKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, TokenKeyPrefix+"_")) - }) - t.Run("ktkv", func(t *testing.T) { - id, err := newTokenKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, TokenKeyVersionPrefix+"_")) - }) - t.Run("ksk", func(t *testing.T) { - id, err := newSessionKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, SessionKeyPrefix+"_")) - }) - t.Run("kskv", func(t *testing.T) { - id, err := newSessionKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, SessionKeyVersionPrefix+"_")) - }) - t.Run("koidck", func(t *testing.T) { - id, err := newOidcKeyId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, OidcKeyPrefix+"_")) - }) - t.Run("koidckv", func(t *testing.T) { - id, err := newOidcKeyVersionId() - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, OidcKeyVersionPrefix+"_")) - }) - t.Run("kak", func(t *testing.T) { - id, err := newAuditKeyId(context.Background()) - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, AuditKeyPrefix+"_")) - }) - t.Run("kakv", func(t *testing.T) { - id, err := newAuditKeyVersionId(context.Background()) - require.NoError(t, err) - assert.True(t, strings.HasPrefix(id, AuditKeyVersionPrefix+"_")) - }) -} diff --git a/internal/kms/immutable_fields_test.go b/internal/kms/immutable_fields_test.go deleted file mode 100644 index cbba96bd5..000000000 --- a/internal/kms/immutable_fields_test.go +++ /dev/null @@ -1,1165 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/db/timestamp" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestOplogKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestOplogKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.OplogKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.OplogKey { - k := new.Clone().(*kms.OplogKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.OplogKey { - k := new.Clone().(*kms.OplogKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.OplogKey { - k := new.Clone().(*kms.OplogKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.OplogKey), after.(*kms.OplogKey))) - }) - } -} - -func TestOplogKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - new := kms.TestOplogKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oplog key")) - - tests := []struct { - name string - update *kms.OplogKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "oplog_key_id", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.OplogKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.OplogKeyVersion { - k := new.Clone().(*kms.OplogKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.OplogKeyVersion), after.(*kms.OplogKeyVersion))) - }) - } -} - -func TestTokenKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestTokenKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.TokenKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.TokenKey { - k := new.Clone().(*kms.TokenKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.TokenKey { - k := new.Clone().(*kms.TokenKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.TokenKey { - k := new.Clone().(*kms.TokenKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.TokenKey), after.(*kms.TokenKey))) - }) - } -} - -func TestTokenKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - new := kms.TestTokenKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("token key")) - - tests := []struct { - name string - update *kms.TokenKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "token_key_id", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.TokenKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.TokenKeyVersion { - k := new.Clone().(*kms.TokenKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.TokenKeyVersion), after.(*kms.TokenKeyVersion))) - }) - } -} - -func TestSessionKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestSessionKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.SessionKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.SessionKey { - k := new.Clone().(*kms.SessionKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.SessionKey { - k := new.Clone().(*kms.SessionKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.SessionKey { - k := new.Clone().(*kms.SessionKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.SessionKey), after.(*kms.SessionKey))) - }) - } -} - -func TestSessionKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestSessionKey(t, conn, rk.PrivateId) - new := kms.TestSessionKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("session key")) - - tests := []struct { - name string - update *kms.SessionKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "Session_key_id", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.SessionKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.SessionKeyVersion { - k := new.Clone().(*kms.SessionKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.SessionKeyVersion), after.(*kms.SessionKeyVersion))) - }) - } -} - -func TestRootKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKeyVersion(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - tests := []struct { - name string - update *kms.RootKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.RootKeyVersion { - k := new.Clone().(*kms.RootKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.RootKeyVersion { - k := new.Clone().(*kms.RootKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.RootKeyVersion { - k := new.Clone().(*kms.RootKeyVersion) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.RootKeyVersion { - k := new.Clone().(*kms.RootKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.RootKeyVersion { - k := new.Clone().(*kms.RootKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.RootKeyVersion), after.(*kms.RootKeyVersion))) - }) - } -} - -func TestRootKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - new := kms.TestRootKey(t, conn, org.PublicId) - - tests := []struct { - name string - update *kms.RootKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.RootKey { - k := new.Clone().(*kms.RootKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.RootKey { - k := new.Clone().(*kms.RootKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "scope_id", - update: func() *kms.RootKey { - k := new.Clone().(*kms.RootKey) - k.ScopeId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.RootKey), after.(*kms.RootKey))) - }) - } -} - -func TestDatabaseKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.DatabaseKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.DatabaseKey { - k := new.Clone().(*kms.DatabaseKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.DatabaseKey { - k := new.Clone().(*kms.DatabaseKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.DatabaseKey { - k := new.Clone().(*kms.DatabaseKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.DatabaseKey), after.(*kms.DatabaseKey))) - }) - } -} - -func TestDatabaseKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - new := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("database key")) - - tests := []struct { - name string - update *kms.DatabaseKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "database_key_id", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.DatabaseKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.DatabaseKeyVersion { - k := new.Clone().(*kms.DatabaseKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.DatabaseKeyVersion), after.(*kms.DatabaseKeyVersion))) - }) - } -} - -func TestOidcKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestOidcKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.OidcKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.OidcKey { - k := new.Clone().(*kms.OidcKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.OidcKey { - k := new.Clone().(*kms.OidcKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.OidcKey { - k := new.Clone().(*kms.OidcKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.OidcKey), after.(*kms.OidcKey))) - }) - } -} - -func TestOidcKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - new := kms.TestOidcKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oidc key")) - - tests := []struct { - name string - update *kms.OidcKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "oidc_key_id", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.OidcKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.OidcKeyVersion { - k := new.Clone().(*kms.OidcKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.OidcKeyVersion), after.(*kms.OidcKeyVersion))) - }) - } -} - -func TestAuditKey_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - new := kms.TestAuditKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - update *kms.AuditKey - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.AuditKey { - k := new.Clone().(*kms.AuditKey) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.AuditKey { - k := new.Clone().(*kms.AuditKey) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "root_key_id", - update: func() *kms.AuditKey { - k := new.Clone().(*kms.AuditKey) - k.RootKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"ScopeId"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.AuditKey), after.(*kms.AuditKey))) - }) - } -} - -func TestAuditKeyVersion_ImmutableFields(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - - ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} - - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - new := kms.TestAuditKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("audit key")) - - tests := []struct { - name string - update *kms.AuditKeyVersion - fieldMask []string - }{ - { - name: "private_id", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.PrivateId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"PrivateId"}, - }, - { - name: "create time", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.CreateTime = &ts - return k - }(), - fieldMask: []string{"CreateTime"}, - }, - { - name: "audit_key_id", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.AuditKeyId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "root_key_version_id", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.RootKeyVersionId = "o_thisIsNotAValidId" - return k - }(), - fieldMask: []string{"RootKeyId"}, - }, - { - name: "version", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.Version = uint32(22) - return k - }(), - fieldMask: []string{"Version"}, - }, - { - name: "key", - update: func() *kms.AuditKeyVersion { - k := new.Clone().(*kms.AuditKeyVersion) - k.Key = []byte("updated key") - return k - }(), - fieldMask: []string{"CtKey"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - orig := new.Clone() - err := rw.LookupById(context.Background(), orig) - require.NoError(err) - - err = tt.update.Encrypt(context.Background(), wrapper) - require.NoError(err) - rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) - require.Error(err) - assert.Equal(0, rowsUpdated) - - after := new.Clone() - err = rw.LookupById(context.Background(), after) - require.NoError(err) - - assert.True(proto.Equal(orig.(*kms.AuditKeyVersion), after.(*kms.AuditKeyVersion))) - }) - } -} diff --git a/internal/kms/kms.go b/internal/kms/kms.go index dafa28663..701329b75 100644 --- a/internal/kms/kms.go +++ b/internal/kms/kms.go @@ -6,285 +6,150 @@ import ( "io" "reflect" "sync" + "time" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/types/scope" + "github.com/hashicorp/go-dbw" + wrappingKms "github.com/hashicorp/go-kms-wrapping/extras/kms/v2" wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/hashicorp/go-kms-wrapping/v2/extras/multi" ) -// ExternalWrappers holds wrappers defined outside of Boundary, e.g. in its -// configuration file. -type ExternalWrappers struct { - m sync.RWMutex - root wrapping.Wrapper - workerAuth wrapping.Wrapper - recovery wrapping.Wrapper -} - -// Root returns the wrapper for root keys -func (e *ExternalWrappers) Root() wrapping.Wrapper { - e.m.RLock() - defer e.m.RUnlock() - return e.root -} - -// WorkerAuth returns the wrapper for worker authentication -func (e *ExternalWrappers) WorkerAuth() wrapping.Wrapper { - e.m.RLock() - defer e.m.RUnlock() - return e.workerAuth -} - -// Recovery returns the wrapper for recovery operations -func (e *ExternalWrappers) Recovery() wrapping.Wrapper { - e.m.RLock() - defer e.m.RUnlock() - return e.recovery -} - // Kms is a way to access wrappers for a given scope and purpose. Since keys can // never change, only be added or (eventually) removed, it opportunistically // caches, going to the database as needed. type Kms struct { - // scopePurposeCache holds a per-scope-purpose multiwrapper containing the - // current encrypting key and all previous key versions, for decryption - scopePurposeCache sync.Map - - externalScopeCache map[string]*ExternalWrappers - externalScopeCacheMutex sync.RWMutex - + underlying *wrappingKms.Kms + reader db.Reader derivedPurposeCache sync.Map - - repo *Repository } -// NewKms takes in a repo and returns a Kms. -func NewKms(repo *Repository, opt ...Option) (*Kms, error) { - const op = "kms.NewKms" - if repo == nil { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing underlying repo") +// New creates a Kms using the provided reader and writer. No options are +// currently supported. +func New(ctx context.Context, reader *db.Db, writer *db.Db, _ ...Option) (*Kms, error) { + const op = "kms.(Kms).New" + if isNil(reader) { + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing reader") } + if isNil(writer) { + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing writer") + } + purposes := stdNewKmsPurposes() + r := dbw.New(reader.UnderlyingDB()) + w := dbw.New(writer.UnderlyingDB()) + k, err := wrappingKms.New(r, w, purposes, wrappingKms.WithCache(true)) + if err != nil { + return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms")) + } return &Kms{ - externalScopeCache: make(map[string]*ExternalWrappers), - repo: repo, + underlying: k, + reader: reader, }, nil } -// GetScopePurposeCache is used in test functions for validation. Since the -// tests need to be in a different package to avoid circular dependencies, this -// is exported. -func (k *Kms) GetScopePurposeCache() *sync.Map { - return &k.scopePurposeCache +// NewUsingReaderWriter creates a Kms using the provided reader and writer. No +// options are currently supported. +func NewUsingReaderWriter(ctx context.Context, reader db.Reader, writer db.Writer, _ ...Option) (*Kms, error) { + const op = "kms.(Kms).New" + if isNil(reader) { + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing reader") + } + if isNil(writer) { + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing writer") + } + purposes := stdNewKmsPurposes() + + r, err := convertToRW(ctx, reader) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + w, err := convertToRW(ctx, writer) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + k, err := wrappingKms.New(r, w, purposes, wrappingKms.WithCache(true)) + if err != nil { + return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms")) + } + return &Kms{ + underlying: k, + reader: reader, + }, nil } -func (k *Kms) GetDerivedPurposeCache() *sync.Map { - return &k.derivedPurposeCache +func convertToRW(ctx context.Context, r interface{}) (*dbw.RW, error) { + const op = "kms.convertToDb" + d, ok := r.(*db.Db) + if !ok { + return nil, errors.New(ctx, errors.InvalidParameter, op, "unable to convert to db.DB") + } + return dbw.New(d.UnderlyingDB()), nil } // AddExternalWrappers allows setting the external keys. -// -// TODO: If we support more than one, e.g. for encrypting against many in case -// of a key loss, there will need to be some refactoring here to have the values -// being stored in the struct be a multiwrapper, but that's for a later project. func (k *Kms) AddExternalWrappers(ctx context.Context, opt ...Option) error { - const op = "kms.AddExternalWrappers" - k.externalScopeCacheMutex.Lock() - defer k.externalScopeCacheMutex.Unlock() - - ext := k.externalScopeCache[scope.Global.String()] - if ext == nil { - ext = &ExternalWrappers{} - } - ext.m.Lock() - defer ext.m.Unlock() + const op = "kms.(Kms).AddExternalWrappers" opts := getOpts(opt...) if opts.withRootWrapper != nil { - ext.root = opts.withRootWrapper - keyId, err := ext.root.KeyId(ctx) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg("error reading root wrapper key ID")) - } - if keyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "root wrapper has no key ID") + if err := k.underlying.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeRootKey.String()), opts.withRootWrapper); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add root wrapper")) } } if opts.withWorkerAuthWrapper != nil { - ext.workerAuth = opts.withWorkerAuthWrapper - keyId, err := ext.workerAuth.KeyId(ctx) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg("error reading worker auth wrapper key ID")) - } - if keyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "worker auth wrapper has no key ID") + if err := k.underlying.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), opts.withWorkerAuthWrapper); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add worker auth wrapper")) } } if opts.withRecoveryWrapper != nil { - ext.recovery = opts.withRecoveryWrapper - keyId, err := ext.root.KeyId(ctx) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg("error reading recovery wrapper key ID")) - } - if keyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "recovery wrapper has no key ID") + if err := k.underlying.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeRecovery.String()), opts.withRecoveryWrapper); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add recovery wrapper")) } } - - k.externalScopeCache[scope.Global.String()] = ext return nil } -func (k *Kms) GetExternalWrappers() *ExternalWrappers { - k.externalScopeCacheMutex.RLock() - defer k.externalScopeCacheMutex.RUnlock() - - ext := k.externalScopeCache[scope.Global.String()] - ext.m.RLock() - defer ext.m.RUnlock() - - ret := &ExternalWrappers{ - root: ext.root, - workerAuth: ext.workerAuth, - recovery: ext.recovery, - } - return ret -} - // GetWrapper returns a wrapper for the given scope and purpose. When a keyId is // passed, it will ensure that the returning wrapper has that key ID in the -// multiwrapper. This is not necesary for encryption but should be supplied for +// multiwrapper. This is not necessary for encryption but should be supplied for // decryption. func (k *Kms) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose, opt ...Option) (wrapping.Wrapper, error) { - const op = "kms.GetWrapper" + const op = "kms.(Kms).GetWrapper" if scopeId == "" { return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id") } - - switch purpose { - case KeyPurposeOplog, KeyPurposeDatabase, KeyPurposeTokens, KeyPurposeSessions, KeyPurposeOidc, KeyPurposeAudit: - case KeyPurposeUnknown: - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key purpose") - default: - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported purpose %q", purpose)) + if purpose == KeyPurposeUnknown { + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing purpose") } - opts := getOpts(opt...) - // Fast-path: we have a valid key at the scope/purpose. Verify the key with - // that ID is in the multiwrapper; if not, fall through to reload from the - // DB. - val, ok := k.scopePurposeCache.Load(scopeId + purpose.String()) - if ok { - wrapper := val.(*multi.PooledWrapper) - if opts.withKeyId == "" { - return wrapper, nil - } - if keyIdWrapper := wrapper.WrapperForKeyId(opts.withKeyId); keyIdWrapper != nil { - return keyIdWrapper, nil - } - // Fall through to refresh our multiwrapper for this scope/purpose from the DB - } - - // We don't have it cached, so we'll need to read from the database. Get the - // root for the scope as we'll need it to decrypt the value coming from the - // DB. We don't cache the roots as we expect that after a few calls the - // scope-purpose cache will catch everything in steady-state. - rootWrapper, rootKeyId, err := k.loadRoot(ctx, scopeId, opt...) + w, err := k.underlying.GetWrapper(ctx, scopeId, wrappingKms.KeyPurpose(purpose.String()), wrappingKms.WithKeyId(opts.withKeyId)) if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error loading root key for scope %s", scopeId))) + return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get wrapper")) } - if rootWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("got nil root wrapper for scope %s", scopeId)) - } - - wrapper, err := k.loadDek(ctx, scopeId, purpose, rootWrapper, rootKeyId, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error loading %s for scope %s", purpose.String(), scopeId))) - } - k.scopePurposeCache.Store(scopeId+purpose.String(), wrapper) - - if opts.withKeyId != "" { - if keyIdWrapper := wrapper.WrapperForKeyId(opts.withKeyId); keyIdWrapper != nil { - return keyIdWrapper, nil - } - return nil, errors.New(ctx, errors.KeyNotFound, op, "unable to find specified key ID") - } - - return wrapper, nil + return w, err } -func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*multi.PooledWrapper, string, error) { - const op = "kms.loadRoot" - opts := getOpts(opt...) - repo := opts.withRepository - if repo == nil { - repo = k.repo +// GetExternalWrappers returns the Kms' ExternalWrappers +func (k *Kms) GetExternalWrappers(ctx context.Context) *ExternalWrappers { + const op = "kms.(Kms).GetExternalWrappers" + ret := &ExternalWrappers{} + if root, err := k.underlying.GetExternalRootWrapper(); err == nil { + ret.root = root } - rootKeys, err := repo.ListRootKeys(ctx) - if err != nil { - return nil, "", errors.Wrap(ctx, err, op) + if workerAuth, err := k.underlying.GetExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String())); err == nil { + ret.workerAuth = workerAuth } - var rootKeyId string - for _, k := range rootKeys { - if k.GetScopeId() == scopeId { - rootKeyId = k.GetPrivateId() - break - } - } - if rootKeyId == "" { - return nil, "", errors.New(ctx, errors.KeyNotFound, op, fmt.Sprintf("missing root key for scope %s", scopeId)) + if recovery, err := k.underlying.GetExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeRecovery.String())); err == nil { + ret.recovery = recovery } + return ret +} - // Now: find the external KMS that can be used to decrypt the root values - // from the DB. - k.externalScopeCacheMutex.Lock() - externalWrappers := k.externalScopeCache[scope.Global.String()] - k.externalScopeCacheMutex.Unlock() - if externalWrappers == nil { - return nil, "", errors.New(ctx, errors.KeyNotFound, op, "could not find kms information at either the needed scope or global fallback") - } - - externalWrappers.m.RLock() - defer externalWrappers.m.RUnlock() - - if externalWrappers.root == nil { - return nil, "", errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key wrapper for scope %s is nil", scopeId)) - } - rootKeyVersions, err := repo.ListRootKeyVersions(ctx, externalWrappers.root, rootKeyId, WithOrderByVersion(db.DescendingOrderBy)) - if err != nil { - return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error looking up root key versions for scope %s", scopeId))) - } - if len(rootKeyVersions) == 0 { - return nil, "", errors.New(ctx, errors.KeyNotFound, op, fmt.Sprintf("no root key versions found for scope %s", scopeId)) - } - - var pooled *multi.PooledWrapper - for i, key := range rootKeyVersions { - var err error - wrapper := aead.NewWrapper() - if _, err = wrapper.SetConfig(ctx, wrapping.WithKeyId(key.GetPrivateId())); err != nil { - return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead root wrapper in scope %s", scopeId))) - } - if err = wrapper.SetAesGcmKeyBytes(key.GetKey()); err != nil { - return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead root wrapper in scope %s", scopeId))) - } - if i == 0 { - pooled, err = multi.NewPooledWrapper(ctx, wrapper) - if err != nil { - return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error getting root pooled wrapper for key version 0 in scope %s", scopeId))) - } - } else { - _, err = pooled.AddWrapper(ctx, wrapper) - if err != nil { - return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error adding pooled wrapper for key version %d in scope %s", i, scopeId))) - } - } - } - - return pooled, rootKeyId, nil +// GetDerivedPurposeCache returns the raw derived purpose cache +func (k *Kms) GetDerivedPurposeCache() *sync.Map { + return &k.derivedPurposeCache } // ReconcileKeys will reconcile the keys in the kms against known possible @@ -295,71 +160,108 @@ func (k *Kms) ReconcileKeys(ctx context.Context, randomReader io.Reader, opt ... if isNil(randomReader) { return errors.New(ctx, errors.InvalidParameter, op, "missing rand reader") } - // it's possible that the global audit key was created after this instance's // database was initialized... so check if the audit wrapper is available // for the global scope and if not, then add one to the global scope if _, err := k.GetWrapper(ctx, scope.Global.String(), KeyPurposeAudit); err != nil { - switch { - case errors.Match(errors.T(errors.KeyNotFound), err): - globalRootWrapper, _, err := k.loadRoot(ctx, scope.Global.String()) - if err != nil { - return errors.Wrap(ctx, err, op) - } - key, err := generateKey(ctx, randomReader) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for database key in scope %s", scope.Global.String()))) - } - if _, _, err := k.repo.CreateAuditKey(ctx, globalRootWrapper, key); err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error creating audit key in scope %s", scope.Global.String()))) - } - default: - errors.Wrap(ctx, err, op) + if err := k.underlying.ReconcileKeys( + ctx, + []string{scope.Global.String()}, + []wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeAudit.String())}, + wrappingKms.WithRandomReader(randomReader), + ); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error creating audit key in scope %s", scope.Global.String()))) } } opts := getOpts(opt...) - for _, id := range opts.withScopeIds { - var scopeRootWrapper *multi.PooledWrapper - - for _, purpose := range []KeyPurpose{ + if len(opts.withScopeIds) > 0 { + if err := k.underlying.ReconcileKeys( + ctx, + opts.withScopeIds, // just add additional purposes as needed going forward to reconcile // new keys as they are added. - // - // NOTE: don't add an audit key here since it can only be created in - // the global scope. - KeyPurposeOidc, - } { - if _, err := k.GetWrapper(ctx, id, purpose); err != nil { - switch { - case errors.Match(errors.T(errors.KeyNotFound), err): - if scopeRootWrapper == nil { - if scopeRootWrapper, _, err = k.loadRoot(ctx, id); err != nil { - return errors.Wrap(ctx, err, op) - } - } - key, err := generateKey(ctx, randomReader) - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for %q key in scope %q", purpose.String(), id))) - } - switch purpose { - case KeyPurposeOidc: - if _, _, err := k.repo.CreateOidcKey(ctx, scopeRootWrapper, key); err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error creating %q key in scope %s", purpose.String(), id))) - } - default: - return errors.New(ctx, errors.Internal, op, fmt.Sprintf("error creating %q key in scope %s since it's not a supported KeyPurpose", purpose.String(), id)) - } - default: - errors.Wrap(ctx, err, op) - } - } + []wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOidc.String())}, + wrappingKms.WithRandomReader(randomReader), + ); err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error creating keys in scopes %s", opts.withScopeIds))) } } - return nil } +// CreateKeys creates the root key and DEKs returns a map of the new keys. +// Supports the WithRandomReader(...) and WithReaderWriter(...) options. +// When WithReaderWriter(...) is used the caller is responsible for managing the +// transaction which allows this capability to be shared with the iam repo when +// it's creating Scopes. +func (k *Kms) CreateKeys(ctx context.Context, scopeId string, opt ...Option) error { + const op = "kms.(Kms).CreateKeysTx" + if scopeId == "" { + return errors.New(ctx, errors.InvalidParameter, op, "missing scope id") + } + opts := getOpts(opt...) + kmsOpts := []wrappingKms.Option{wrappingKms.WithRandomReader(opts.withRandomReader)} + switch { + case !isNil(opts.withReader) && isNil(opts.withWriter): + return errors.New(ctx, errors.InvalidParameter, op, "missing writer") + case isNil(opts.withReader) && !isNil(opts.withWriter): + return errors.New(ctx, errors.InvalidParameter, op, "missing reader") + case !isNil(opts.withReader) && !isNil(opts.withWriter): + r, err := convertToRW(ctx, opts.withReader) + if err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("unable to convert reader")) + } + w, err := convertToRW(ctx, opts.withWriter) + if err != nil { + return errors.Wrap(ctx, err, op, errors.WithMsg("unable to convert writer")) + } + kmsOpts = append(kmsOpts, wrappingKms.WithReaderWriter(r, w)) + } + purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes())) + for _, p := range ValidDekPurposes() { + purposes = append(purposes, wrappingKms.KeyPurpose(p.String())) + } + if err := k.underlying.CreateKeys(ctx, scopeId, purposes, kmsOpts...); err != nil { + return errors.Wrap(ctx, err, op) + } + return nil +} + +// ClearCache will clear the kms's cache which is useful after a scope has been +// deleted. +func (k *Kms) ClearCache(ctx context.Context) error { + const op = "kms.(Kms).ClearCache" + if err := k.underlying.ClearCache(ctx); err != nil { + return errors.Wrap(ctx, err, op) + } + return nil +} + +// VerifyGlobalRoot will verify that the global root wrapper is reasonable. +func (k *Kms) VerifyGlobalRoot(ctx context.Context) error { + const op = "kms.(Kms).VerifyGlobalRoot" + var keys []*rootKey + if err := k.reader.SearchWhere(ctx, &keys, "1=1", nil, db.WithLimit(1), db.WithOrder("create_time asc")); err != nil { + return errors.Wrap(ctx, err, op) + } + for _, rk := range keys { + if rk.ScopeId == scope.Global.String() { + return nil + } + } + return errors.New(ctx, errors.MigrationIntegrity, op, "can't find global scoped root key") +} + +func stdNewKmsPurposes() []wrappingKms.KeyPurpose { + purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes())) + for _, p := range ValidDekPurposes() { + purposes = append(purposes, wrappingKms.KeyPurpose(p.String())) + } + purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), wrappingKms.KeyPurpose(KeyPurposeRecovery.String())) + return purposes +} + func isNil(i interface{}) bool { if i == nil { return true @@ -371,111 +273,10 @@ func isNil(i interface{}) bool { return false } -// Dek is an interface wrapping dek types to allow a lot less switching in loadDek -type Dek interface { - GetRootKeyId() string - GetPrivateId() string +type rootKey struct { + PrivateId string `gorm:"primary_key"` + ScopeId string `gorm:"default:null"` + CreateTime time.Time `gorm:"default:current_timestamp"` } -// DekVersion is an interface wrapping versioned dek types to allow a lot less switching in loadDek -type DekVersion interface { - GetPrivateId() string - GetKey() []byte -} - -func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, rootWrapper wrapping.Wrapper, rootKeyId string, opt ...Option) (*multi.PooledWrapper, error) { - const op = "kms.loadDek" - if rootWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("nil root wrapper for scope %s", scopeId)) - } - if rootKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("missing root key ID for scope %s", scopeId)) - } - - opts := getOpts(opt...) - repo := opts.withRepository - if repo == nil { - repo = k.repo - } - - var keys []Dek - var err error - switch purpose { - case KeyPurposeDatabase: - keys, err = repo.ListDatabaseKeys(ctx) - case KeyPurposeOplog: - keys, err = repo.ListOplogKeys(ctx) - case KeyPurposeTokens: - keys, err = repo.ListTokenKeys(ctx) - case KeyPurposeSessions: - keys, err = repo.ListSessionKeys(ctx) - case KeyPurposeOidc: - keys, err = repo.ListOidcKeys(ctx) - case KeyPurposeAudit: - keys, err = repo.ListAuditKeys(ctx) - default: - return nil, errors.New(ctx, errors.InvalidParameter, op, "unknown or invalid DEK purpose specified") - } - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error listing root keys")) - } - var keyId string - for _, k := range keys { - if k.GetRootKeyId() == rootKeyId { - keyId = k.GetPrivateId() - break - } - } - if keyId == "" { - return nil, errors.New(ctx, errors.KeyNotFound, op, fmt.Sprintf("error finding %s key for scope %s", purpose.String(), scopeId)) - } - - var keyVersions []DekVersion - switch purpose { - case KeyPurposeDatabase: - keyVersions, err = repo.ListDatabaseKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - case KeyPurposeOplog: - keyVersions, err = repo.ListOplogKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - case KeyPurposeTokens: - keyVersions, err = repo.ListTokenKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - case KeyPurposeSessions: - keyVersions, err = repo.ListSessionKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - case KeyPurposeOidc: - keyVersions, err = repo.ListOidcKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - case KeyPurposeAudit: - keyVersions, err = repo.ListAuditKeyVersions(ctx, rootWrapper, keyId, WithOrderByVersion(db.DescendingOrderBy)) - default: - return nil, errors.New(ctx, errors.InvalidParameter, op, "unknown or invalid DEK purpose specified") - } - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error looking up %s key versions for scope %s", purpose.String(), scopeId))) - } - if len(keyVersions) == 0 { - return nil, errors.New(ctx, errors.KeyNotFound, op, fmt.Sprintf("no %s key versions found for scope %s", purpose.String(), scopeId)) - } - - var pooled *multi.PooledWrapper - for i, keyVersion := range keyVersions { - var err error - wrapper := aead.NewWrapper() - if _, err = wrapper.SetConfig(ctx, wrapping.WithKeyId(keyVersion.GetPrivateId())); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead %s wrapper in scope %s", purpose.String(), scopeId))) - } - if err = wrapper.SetAesGcmKeyBytes(keyVersion.GetKey()); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead %s wrapper in scope %s", purpose.String(), scopeId))) - } - if i == 0 { - pooled, err = multi.NewPooledWrapper(ctx, wrapper) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error getting %s pooled wrapper for key version 0 in scope %s", purpose.String(), scopeId))) - } - } else { - _, err = pooled.AddWrapper(ctx, wrapper) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error getting %s pooled wrapper for key version %d in scope %s", purpose.String(), i, scopeId))) - } - } - } - - return pooled, nil -} +func (*rootKey) TableName() string { return "kms_root_key" } diff --git a/internal/kms/kms_ext_test.go b/internal/kms/kms_ext_test.go index 7c8ece8be..8bf676411 100644 --- a/internal/kms/kms_ext_test.go +++ b/internal/kms/kms_ext_test.go @@ -26,55 +26,15 @@ func TestKms(t *testing.T) { t.Parallel() ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) extWrapper := db.TestWrapper(t) - badExtWrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) kmsCache := kms.TestKms(t, conn, extWrapper) org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, extWrapper)) - // Verify that the cache is empty, so we can show that by the end of the - // test sequence we did actually look up keys and store them in the cache - t.Run("verify cache empty", func(t *testing.T) { - var count int - kmsCache.GetScopePurposeCache().Range(func(key interface{}, value interface{}) bool { - count++ - return true - }) - assert.Equal(t, 0, count) - }) - // Verify that the root keys are all in the database and can be decrypted - // with the correct wrapper from the KMS object - t.Run("verify root keys", func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - rootKeys, err := repo.ListRootKeys(ctx) - require.NoError(err) - wrappers := kmsCache.GetExternalWrappers() - for _, key := range rootKeys { - kvs, err := repo.ListRootKeyVersions(ctx, wrappers.Root(), key.GetPrivateId()) - require.NoError(err) - assert.Len(kvs, 1) - assert.Len(kvs[0].GetKey(), 32) - } - }) - // Verify that the wrong wrapper causes decryption to fail - t.Run("bad external keys", func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - rootKeys, err := repo.ListRootKeys(ctx) - require.NoError(err) - for _, key := range rootKeys { - _, err := repo.ListRootKeyVersions(ctx, badExtWrapper, key.GetPrivateId()) - require.Error(err) - assert.True(strings.Contains(err.Error(), "message authentication failed"), err.Error()) - } - }) // This next sequence is run twice to ensure that calling for the keys twice // returns the same value each time and doesn't simply populate more keys // into the KMS object keyBytes := map[string]bool{} keyIds := map[string]bool{} - scopePurposeMap := map[string]interface{}{} for i := 1; i < 3; i++ { // This iterates through wrappers for all three scopes and four purposes, // ensuring that the key bytes and IDs are different for each of them, @@ -116,24 +76,6 @@ func TestKms(t *testing.T) { } } }) - // Verify that the cache has been populated with unique values. The - // second time we validate that the items we find when going through the - // cache a second time are the same as the first. If they were recreated - // the pointers would be different. - t.Run(fmt.Sprintf("verify cache populated x %d", i), func(t *testing.T) { - var count int - kmsCache.GetScopePurposeCache().Range(func(key interface{}, value interface{}) bool { - count++ - if i == 1 { - scopePurposeMap[key.(string)] = value - } else { - assert.Same(t, scopePurposeMap[key.(string)], value) - } - return true - }) - // four purposes x 3 scopes - assert.Equal(t, 12, count) - }) } } @@ -141,7 +83,6 @@ func TestKms_ReconcileKeys(t *testing.T) { t.Parallel() testCtx := context.Background() conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) wrapper := db.TestWrapper(t) org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) @@ -183,9 +124,10 @@ func TestKms_ReconcileKeys(t *testing.T) { kms: kms.TestKms(t, conn, wrapper), reader: rand.Reader, setup: func(k *kms.Kms) { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKey(); return &i }(), "1=1") + kms.TestKmsDeleteKeyPurpose(t, conn, kms.KeyPurposeAudit) // make sure the kms is in the proper state for the unit test // before proceeding. + k.ClearCache(testCtx) _, err := k.GetWrapper(testCtx, scope.Global.String(), kms.KeyPurposeAudit) require.Error(t, err) }, @@ -200,14 +142,15 @@ func TestKms_ReconcileKeys(t *testing.T) { setup: func(k *kms.Kms) { // create initial keys for the test scope ids... for _, id := range []string{org.PublicId, org2.PublicId} { - _, err := kms.CreateKeysTx(context.Background(), rw, rw, wrapper, rand.Reader, id) + err := k.CreateKeys(testCtx, id) require.NoError(t, err) } - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKey(); return &i }(), "1=1") + kms.TestKmsDeleteKeyPurpose(t, conn, kms.KeyPurposeOidc) + // make sure the kms is in the proper state for the unit test // before proceeding. for _, id := range []string{org.PublicId, org2.PublicId} { - _, err := k.GetWrapper(testCtx, id, kms.KeyPurposeAudit) + _, err := k.GetWrapper(testCtx, id, kms.KeyPurposeOidc) require.Error(t, err) } }, @@ -218,10 +161,10 @@ func TestKms_ReconcileKeys(t *testing.T) { t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) // start with no keys... - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") + kms.TestKmsDeleteAllKeys(t, conn) // create initial keys for the global scope... - _, err := kms.CreateKeysTx(context.Background(), rw, rw, wrapper, rand.Reader, scope.Global.String()) + err := tt.kms.CreateKeys(context.Background(), scope.Global.String()) require.NoError(err) if tt.setup != nil { @@ -252,3 +195,175 @@ func TestKms_ReconcileKeys(t *testing.T) { }) } } + +func TestKms_GetDerivedPurposeCache(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + conn, _ := db.TestSetup(t, "postgres") + rootWrapper := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, rootWrapper) + + derivedWrapper := db.TestWrapper(t) + kmsCache.GetDerivedPurposeCache().Store(1, derivedWrapper) + + v, ok := kmsCache.GetDerivedPurposeCache().Load(1) + assert.True(ok) + assert.Equal(derivedWrapper, v) +} + +func TestKms_VerifyGlobalRoot(t *testing.T) { + t.Parallel() + testCtx := context.Background() + assert, require := assert.New(t), require.New(t) + conn, _ := db.TestSetup(t, "postgres") + rootWrapper := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, rootWrapper) + + assert.Error(kmsCache.VerifyGlobalRoot(testCtx)) + + require.NoError(kmsCache.CreateKeys(testCtx, "global")) + assert.NoError(kmsCache.VerifyGlobalRoot(testCtx)) +} + +func TestKms_GetWrapper(t *testing.T) { + t.Parallel() + testCtx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rootWrapper := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, rootWrapper) + kmsCache.CreateKeys(testCtx, "global") + tests := []struct { + name string + kms *kms.Kms + purpose kms.KeyPurpose + scopeId string + opt []kms.Option + wantErr bool + wantErrMatch *errors.Template + wantErrContains string + }{ + { + name: "missing-purpose", + kms: kmsCache, + scopeId: "global", + wantErr: true, + wantErrMatch: errors.T(errors.InvalidParameter), + wantErrContains: "missing purpose", + }, + { + name: "missing-scope-id", + kms: kmsCache, + purpose: kms.KeyPurposeDatabase, + wantErr: true, + wantErrMatch: errors.T(errors.InvalidParameter), + wantErrContains: "missing scope id", + }, + { + name: "success", + kms: kmsCache, + purpose: kms.KeyPurposeDatabase, + scopeId: "global", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + got, err := tc.kms.GetWrapper(testCtx, tc.scopeId, tc.purpose, tc.opt...) + if tc.wantErr { + require.Error(err) + if tc.wantErrMatch != nil { + assert.Truef(errors.Match(tc.wantErrMatch, err), "expected %q and got err: %+v", tc.wantErrMatch.Code, err) + } + if tc.wantErrContains != "" { + assert.True(strings.Contains(err.Error(), tc.wantErrContains)) + } + return + } + require.NoError(err) + assert.NotNil(got) + }) + } +} + +func TestKms_CreateKeys(t *testing.T) { + t.Parallel() + testCtx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rootWrapper := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, rootWrapper) + kmsCache.CreateKeys(testCtx, "global") + rw := db.New(conn) + + tests := []struct { + name string + kms *kms.Kms + scopeId string + opt []kms.Option + wantErr bool + wantErrMatch *errors.Template + wantErrContains string + }{ + { + name: "missing-scope-id", + kms: kmsCache, + wantErr: true, + wantErrMatch: errors.T(errors.InvalidParameter), + wantErrContains: "missing scope id", + }, + { + name: "invalid-scope", + kms: kmsCache, + scopeId: "o_1234567890", + wantErr: true, + wantErrContains: "violates foreign key constraint", + }, + { + name: "missing-writer-opt", + kms: kmsCache, + scopeId: "global", + opt: []kms.Option{kms.WithReaderWriter(rw, nil)}, + wantErr: true, + wantErrMatch: errors.T(errors.InvalidParameter), + wantErrContains: "missing writer", + }, + { + name: "missing-reader-opt", + kms: kmsCache, + scopeId: "global", + opt: []kms.Option{kms.WithReaderWriter(nil, rw)}, + wantErr: true, + wantErrMatch: errors.T(errors.InvalidParameter), + wantErrContains: "missing reader", + }, + { + name: "success", + kms: kmsCache, + scopeId: "global", + }, + { + name: "success-with-reader-writer", + kms: kmsCache, + opt: []kms.Option{kms.WithReaderWriter(rw, rw)}, + scopeId: "global", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + kms.TestKmsDeleteAllKeys(t, conn) + err := tc.kms.CreateKeys(testCtx, tc.scopeId, tc.opt...) + if tc.wantErr { + require.Error(err) + if tc.wantErrMatch != nil { + assert.Truef(errors.Match(tc.wantErrMatch, err), "expected %q and got err: %+v", tc.wantErrMatch.Code, err) + } + if tc.wantErrContains != "" { + assert.True(strings.Contains(err.Error(), tc.wantErrContains)) + } + return + } + require.NoError(err) + }) + } +} diff --git a/internal/kms/kms_test.go b/internal/kms/kms_test.go index 171ce3ff2..83eb47522 100644 --- a/internal/kms/kms_test.go +++ b/internal/kms/kms_test.go @@ -2,73 +2,175 @@ package kms import ( "context" - "crypto/rand" "testing" "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/go-uuid" + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/go-dbw" + wrappingKms "github.com/hashicorp/go-kms-wrapping/extras/kms/v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestKms_KeyId(t *testing.T) { +func Test_New(t *testing.T) { t.Parallel() - require := require.New(t) - ctx := context.Background() + testCtx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) - extWrapper := db.TestWrapper(t) - repo, err := NewRepository(rw, rw) - require.NoError(err) - // Make the global scope base keys - _, err = CreateKeysTx(ctx, rw, rw, extWrapper, rand.Reader, scope.Global.String()) - require.NoError(err) + tests := []struct { + name string + r *db.Db + w *db.Db + want *Kms + wantErr bool + wantErrMatch *errors.Template + wantErrContains string + }{ + { + name: "nil-reader", + w: rw, + wantErr: true, + wantErrContains: "missing reader", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "nil-writer", + r: rw, + wantErr: true, + wantErrContains: "missing writer", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "success", + r: rw, + w: rw, + want: &Kms{ + reader: rw, + underlying: func() *wrappingKms.Kms { + purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes())) + for _, p := range ValidDekPurposes() { + purposes = append(purposes, wrappingKms.KeyPurpose(p.String())) + } + purposes = append(purposes, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), wrappingKms.KeyPurpose(KeyPurposeRecovery.String())) - // Get the global scope's root wrapper - kmsCache, err := NewKms(repo) - require.NoError(err) - require.NoError(kmsCache.AddExternalWrappers(ctx, WithRootWrapper(extWrapper))) - globalRootWrapper, _, err := kmsCache.loadRoot(ctx, scope.Global.String()) - require.NoError(err) + r := dbw.New(rw.UnderlyingDB()) + w := dbw.New(rw.UnderlyingDB()) + wrapped, err := wrappingKms.New(r, w, purposes, wrappingKms.WithCache(true)) + require.NoError(t, err) + return wrapped + }(), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) - dks, err := repo.ListDatabaseKeys(ctx) - require.NoError(err) - require.Len(dks, 1) - - // Create another key version - newKeyBytes, err := uuid.GenerateRandomBytes(32) - require.NoError(err) - _, err = repo.CreateDatabaseKeyVersion(ctx, globalRootWrapper, dks[0].GetPrivateId(), newKeyBytes) - require.NoError(err) - - dkvs, err := repo.ListDatabaseKeyVersions(ctx, globalRootWrapper, dks[0].GetPrivateId()) - require.NoError(err) - require.Len(dkvs, 2) - - keyId1 := dkvs[0].GetPrivateId() - keyId2 := dkvs[1].GetPrivateId() - - // First test: just getting the key should return the latest - wrapper, err := kmsCache.GetWrapper(ctx, scope.Global.String(), KeyPurposeDatabase) - require.NoError(err) - tKeyId, err := wrapper.KeyId(context.Background()) - require.NoError(err) - require.Equal(keyId2, tKeyId) - - // Second: ask for each in turn - wrapper, err = kmsCache.GetWrapper(ctx, scope.Global.String(), KeyPurposeDatabase, WithKeyId(keyId1)) - require.NoError(err) - tKeyId, err = wrapper.KeyId(context.Background()) - require.NoError(err) - require.Equal(keyId1, tKeyId) - wrapper, err = kmsCache.GetWrapper(ctx, scope.Global.String(), KeyPurposeDatabase, WithKeyId(keyId2)) - require.NoError(err) - tKeyId, err = wrapper.KeyId(context.Background()) - require.NoError(err) - require.Equal(keyId2, tKeyId) - - // Last: verify something bogus finds nothing - _, err = kmsCache.GetWrapper(ctx, scope.Global.String(), KeyPurposeDatabase, WithKeyId("foo")) - require.Error(err) + got, err := New(testCtx, tc.r, tc.w) + if tc.wantErr { + require.Error(err) + if tc.wantErrMatch != nil { + assert.Truef(errors.Match(tc.wantErrMatch, err), "expected %q and got err: %+v", tc.wantErrMatch.Code, err) + } + if tc.wantErrContains != "" { + assert.Contains(err.Error(), tc.wantErrContains) + } + return + } + require.NoError(err) + assert.Equal(tc.want, got) + }) + } +} + +func Test_NewUsingReaderWriter(t *testing.T) { + t.Parallel() + testCtx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + + tests := []struct { + name string + r db.Reader + w db.Writer + want *Kms + wantErr bool + wantErrMatch *errors.Template + wantErrContains string + }{ + { + name: "nil-reader", + w: rw, + wantErr: true, + wantErrContains: "missing reader", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "nil-writer", + r: rw, + wantErr: true, + wantErrContains: "missing writer", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "invalid-reader", + r: &invalidReader{}, + w: rw, + wantErr: true, + wantErrContains: "unable to convert to db.DB", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "invalid-writer", + r: rw, + w: &invalidWriter{}, + wantErr: true, + wantErrContains: "unable to convert to db.DB", + wantErrMatch: errors.T(errors.InvalidParameter), + }, + { + name: "success", + r: rw, + w: rw, + want: &Kms{ + reader: rw, + underlying: func() *wrappingKms.Kms { + purposes := stdNewKmsPurposes() + r := dbw.New(rw.UnderlyingDB()) + w := dbw.New(rw.UnderlyingDB()) + wrapped, err := wrappingKms.New(r, w, purposes, wrappingKms.WithCache(true)) + require.NoError(t, err) + return wrapped + }(), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + got, err := NewUsingReaderWriter(testCtx, tc.r, tc.w) + if tc.wantErr { + require.Error(err) + if tc.wantErrMatch != nil { + assert.Truef(errors.Match(tc.wantErrMatch, err), "expected %q and got err: %+v", tc.wantErrMatch.Code, err) + } + if tc.wantErrContains != "" { + assert.Contains(err.Error(), tc.wantErrContains) + } + return + } + require.NoError(err) + assert.Equal(tc.want, got) + }) + } +} + +type invalidReader struct { + db.Reader +} + +type invalidWriter struct { + db.Writer } diff --git a/internal/kms/oidc_key.go b/internal/kms/oidc_key.go deleted file mode 100644 index c3acff7ed..000000000 --- a/internal/kms/oidc_key.go +++ /dev/null @@ -1,83 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultOidcKeyTableName = "kms_oidc_key" -) - -type OidcKey struct { - *store.OidcKey - tableName string `gorm:"-"` -} - -// NewOidcKey creates a new in memory oidc key. This key is used to encrypt -// oidc state before it's included in the oidc auth url. No options are -// currently supported. -func NewOidcKey(rootKeyId string, _ ...Option) (*OidcKey, error) { - const op = "kms.NewOidcKey" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - c := &OidcKey{ - OidcKey: &store.OidcKey{ - RootKeyId: rootKeyId, - }, - } - return c, nil -} - -// AllocOidcKey will allocate a OidcKey -func AllocOidcKey() OidcKey { - return OidcKey{ - OidcKey: &store.OidcKey{}, - } -} - -// Clone creates a clone of the OidcKey -func (k *OidcKey) Clone() interface{} { - cp := proto.Clone(k.OidcKey) - return &OidcKey{ - OidcKey: cp.(*store.OidcKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *OidcKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(OidcKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *OidcKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultOidcKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *OidcKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/oidc_key_test.go b/internal/kms/oidc_key_test.go deleted file mode 100644 index 00430a9aa..000000000 --- a/internal/kms/oidc_key_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the OidcKey attributes are -// immutable and those tests are covered by TestOidcKey_ImmutableFields - -func TestOidcKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.OidcKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.OidcKey { - k := kms.AllocOidcKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKey(); return &i }(), "1=1") - got, err := kms.NewOidcKey(tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.OidcKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestOidcKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.OidcKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestOidcKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.OidcKey { - k := kms.AllocOidcKey() - id, err := db.NewPublicId(kms.OidcKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocOidcKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocOidcKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestOidcKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestOidcKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.OidcKey).OidcKey, k.OidcKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestOidcKey(t, conn, rk.PrivateId) - k2 := kms.TestOidcKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.OidcKey).OidcKey, k2.OidcKey)) - }) -} - -func TestOidcKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultOidcKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocOidcKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocOidcKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/oidc_key_version.go b/internal/kms/oidc_key_version.go deleted file mode 100644 index f26be0281..000000000 --- a/internal/kms/oidc_key_version.go +++ /dev/null @@ -1,122 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultOidcKeyVersionTableName = "kms_oidc_key_version" -) - -type OidcKeyVersion struct { - *store.OidcKeyVersion - tableName string `gorm:"-"` -} - -// NewOidcKeyVersion creates a new in memory oidc key version. This key is used -// to encrypt oidc state before it's included in the oidc auth url. No options -// are currently supported. -func NewOidcKeyVersion(oidcKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*OidcKeyVersion, error) { - const op = "kms.NewOidcKeyVersion" - if oidcKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing oidc key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key version id") - } - - k := &OidcKeyVersion{ - OidcKeyVersion: &store.OidcKeyVersion{ - OidcKeyId: oidcKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocOidcKeyVersion allocates a OidcKeyVersion -func AllocOidcKeyVersion() OidcKeyVersion { - return OidcKeyVersion{ - OidcKeyVersion: &store.OidcKeyVersion{}, - } -} - -// Clone creates a clone of the OidcKeyVersion -func (k *OidcKeyVersion) Clone() interface{} { - cp := proto.Clone(k.OidcKeyVersion) - return &OidcKeyVersion{ - OidcKeyVersion: cp.(*store.OidcKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the oidc key -// version before it's written. -func (k *OidcKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(OidcKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.OidcKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing oidc key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *OidcKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultOidcKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *OidcKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the oidc key version's key -func (k *OidcKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(OidcKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.OidcKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.OidcKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the oidc key version's key -func (k *OidcKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(OidcKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.OidcKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.OidcKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/oidc_key_version_test.go b/internal/kms/oidc_key_version_test.go deleted file mode 100644 index 5fc6fd0d1..000000000 --- a/internal/kms/oidc_key_version_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the OidcKeyVersion attributes are -// immutable and those tests are covered by TestOidcKey_ImmutableFields - -func TestOidcKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - type args struct { - OidcKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.OidcKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-oidc-id", - args: args{ - key: []byte("oidc key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - OidcKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - OidcKeyId: dk.PrivateId, - key: []byte("oidc key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - OidcKeyId: dk.PrivateId, - key: []byte("oidc key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.OidcKeyVersion { - k := kms.AllocOidcKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("oidc key") - k.OidcKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKeyVersion(); return &i }(), "1=1") - got, err := kms.NewOidcKeyVersion(tt.args.OidcKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.OidcKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestOidcKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.OidcKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestOidcKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oidc key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.OidcKeyVersion { - k := kms.AllocOidcKeyVersion() - id, err := db.NewPublicId(kms.OidcKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocOidcKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocOidcKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestOidcKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestOidcKey(t, conn, rk.PrivateId) - kv := kms.TestOidcKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.OidcKeyVersion).OidcKeyVersion, kv.OidcKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestOidcKey(t, conn, rk.PrivateId) - k2 := kms.TestOidcKey(t, conn, rk2.PrivateId) - kv := kms.TestOidcKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test db key")) - kv2 := kms.TestOidcKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test db key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.OidcKeyVersion).OidcKeyVersion, kv2.OidcKeyVersion)) - }) -} - -func TestOidcKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultOidcKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocOidcKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocOidcKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/oplog_key.go b/internal/kms/oplog_key.go deleted file mode 100644 index 6eb724aee..000000000 --- a/internal/kms/oplog_key.go +++ /dev/null @@ -1,79 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultOplogKeyTableName = "kms_oplog_key" -) - -type OplogKey struct { - *store.OplogKey - tableName string `gorm:"-"` -} - -// NewOplogKey creates a new in memory key. No options -// are currently supported. -func NewOplogKey(rootKeyId string, _ ...Option) (*OplogKey, error) { - const op = "kms.NewOplogKey" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - c := &OplogKey{ - OplogKey: &store.OplogKey{ - RootKeyId: rootKeyId, - }, - } - return c, nil -} - -// AllocOplogKey will allocate a key -func AllocOplogKey() OplogKey { - return OplogKey{ - OplogKey: &store.OplogKey{}, - } -} - -// Clone creates a clone of the key -func (k *OplogKey) Clone() interface{} { - cp := proto.Clone(k.OplogKey) - return &OplogKey{ - OplogKey: cp.(*store.OplogKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *OplogKey) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(OplogKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *OplogKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultOplogKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *OplogKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/oplog_key_test.go b/internal/kms/oplog_key_test.go deleted file mode 100644 index e1a1048e2..000000000 --- a/internal/kms/oplog_key_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the OplogKey attributes are -// immutable and those tests are covered by TestOplogKey_ImmutableFields - -func TestOplogKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.OplogKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.OplogKey { - k := kms.AllocOplogKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKey(); return &i }(), "1=1") - got, err := kms.NewOplogKey(tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.OplogKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestOplogKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.OplogKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestOplogKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.OplogKey { - k := kms.AllocOplogKey() - id, err := db.NewPublicId(kms.OplogKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocOplogKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocOplogKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestOplogKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestOplogKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.OplogKey).OplogKey, k.OplogKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestOplogKey(t, conn, rk.PrivateId) - k2 := kms.TestOplogKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.OplogKey).OplogKey, k2.OplogKey)) - }) -} - -func TestOplogKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultOplogKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocOplogKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocOplogKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/oplog_key_version.go b/internal/kms/oplog_key_version.go deleted file mode 100644 index 42f905bb3..000000000 --- a/internal/kms/oplog_key_version.go +++ /dev/null @@ -1,118 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultOplogKeyVersionTableName = "kms_oplog_key_version" -) - -type OplogKeyVersion struct { - *store.OplogKeyVersion - tableName string `gorm:"-"` -} - -// OplogKeyVersion creates a new in memory key version. No options are -// currently supported. -func NewOplogKeyVersion(oplogKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*OplogKeyVersion, error) { - const op = "kms.NewOplogKeyVersion" - if oplogKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing oplog key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key version id") - } - - k := &OplogKeyVersion{ - OplogKeyVersion: &store.OplogKeyVersion{ - OplogKeyId: oplogKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocOplogKeyVersion allocates a key version -func AllocOplogKeyVersion() OplogKeyVersion { - return OplogKeyVersion{ - OplogKeyVersion: &store.OplogKeyVersion{}, - } -} - -// Clone creates a clone of the key version -func (k *OplogKeyVersion) Clone() interface{} { - cp := proto.Clone(k.OplogKeyVersion) - return &OplogKeyVersion{ - OplogKeyVersion: cp.(*store.OplogKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// version before it's written. -func (k *OplogKeyVersion) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(OplogKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.OplogKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing oplog key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *OplogKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultOplogKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *OplogKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the key version's key -func (k *OplogKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(OplogKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.OplogKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.OplogKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the key version's key -func (k *OplogKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(OplogKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.OplogKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.OplogKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/oplog_key_version_test.go b/internal/kms/oplog_key_version_test.go deleted file mode 100644 index c4f413a3d..000000000 --- a/internal/kms/oplog_key_version_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the OplogKeyVersion attributes are -// immutable and those tests are covered by TestOplogKey_ImmutableFields - -func TestOplogKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - - type args struct { - oplogKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.OplogKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-id", - args: args{ - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - oplogKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - oplogKeyId: dk.PrivateId, - key: []byte("test key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - oplogKeyId: dk.PrivateId, - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.OplogKeyVersion { - k := kms.AllocOplogKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("test key") - k.OplogKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKeyVersion(); return &i }(), "1=1") - got, err := kms.NewOplogKeyVersion(tt.args.oplogKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.OplogKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestOplogKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - opk := kms.TestOplogKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.OplogKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestOplogKeyVersion(t, conn, rkvWrapper, opk.PrivateId, []byte("test key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.OplogKeyVersion { - k := kms.AllocOplogKeyVersion() - id, err := db.NewPublicId(kms.OplogKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocOplogKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocOplogKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestOplogKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestOplogKey(t, conn, rk.PrivateId) - kv := kms.TestOplogKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.OplogKeyVersion).OplogKeyVersion, kv.OplogKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestOplogKey(t, conn, rk.PrivateId) - k2 := kms.TestOplogKey(t, conn, rk2.PrivateId) - kv := kms.TestOplogKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - kv2 := kms.TestOplogKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.OplogKeyVersion).OplogKeyVersion, kv2.OplogKeyVersion)) - }) -} - -func TestOplogKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultOplogKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocOplogKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocOplogKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/option_test.go b/internal/kms/option_test.go index c5e8e880c..2ed5562a6 100644 --- a/internal/kms/option_test.go +++ b/internal/kms/option_test.go @@ -35,4 +35,11 @@ func Test_GetOpts(t *testing.T) { testOpts.withOrderByVersion = db.DescendingOrderBy assert.Equal(opts, testOpts) }) + t.Run("WithKeyId", func(t *testing.T) { + assert := assert.New(t) + opts := getOpts(WithKeyId("100")) + testOpts := getDefaultOptions() + testOpts.withKeyId = "100" + assert.Equal(opts, testOpts) + }) } diff --git a/internal/kms/options.go b/internal/kms/options.go index 4473d2b4b..ab52ccaa1 100644 --- a/internal/kms/options.go +++ b/internal/kms/options.go @@ -1,6 +1,8 @@ package kms import ( + "io" + "github.com/hashicorp/boundary/internal/db" wrapping "github.com/hashicorp/go-kms-wrapping/v2" ) @@ -23,10 +25,12 @@ type options struct { withRootWrapper wrapping.Wrapper withWorkerAuthWrapper wrapping.Wrapper withRecoveryWrapper wrapping.Wrapper - withRepository *Repository withOrderByVersion db.OrderBy withKeyId string withScopeIds []string + withRandomReader io.Reader + withReader db.Reader + withWriter db.Writer } func getDefaultOptions() options { @@ -64,14 +68,6 @@ func WithRecoveryWrapper(w wrapping.Wrapper) Option { } } -// WithRepository sets a repository for a given wrapper lookup, useful if in the -// middle of a transaction where the reader/writer need to be specified -func WithRepository(repo *Repository) Option { - return func(o *options) { - o.withRepository = repo - } -} - // WithOrderByVersion provides an option to specify ordering by the // CreateTime field. func WithOrderByVersion(orderBy db.OrderBy) Option { @@ -95,3 +91,23 @@ func WithScopeIds(scopeId ...string) Option { o.withScopeIds = scopeId } } + +// WithRandomReader(...) option allows an optional random reader to be +// provided. By default the reader from crypto/rand will be used. +func WithRandomReader(randomReader io.Reader) Option { + return func(o *options) { + o.withRandomReader = randomReader + } +} + +// WithReaderWriter allows the caller to pass an inflight transaction to be used +// for all database operations. If WithReaderWriter(...) is used, then the +// caller is responsible for managing the transaction. The purpose of the +// WithReaderWriter(...) option is to allow the caller to create the scope and +// all of its keys in the same transaction. +func WithReaderWriter(r db.Reader, w db.Writer) Option { + return func(o *options) { + o.withReader = r + o.withWriter = w + } +} diff --git a/internal/kms/repository.go b/internal/kms/repository.go deleted file mode 100644 index 10c7ed7c3..000000000 --- a/internal/kms/repository.go +++ /dev/null @@ -1,200 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "io" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/scope" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/hashicorp/go-uuid" -) - -// Repository is the iam database repository -type Repository struct { - reader db.Reader - writer db.Writer - // defaultLimit provides a default for limiting the number of results returned from the repo - defaultLimit int -} - -// NewRepository creates a new kms Repository. Supports the options: WithLimit -// which sets a default limit on results returned by repo operations. -func NewRepository(r db.Reader, w db.Writer, opt ...Option) (*Repository, error) { - const op = "kms.NewRepository" - if r == nil { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "nil reader") - } - if w == nil { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "nil writer") - } - opts := getOpts(opt...) - if opts.withLimit == 0 { - // zero signals the boundary defaults should be used. - opts.withLimit = db.DefaultLimit - } - return &Repository{ - reader: r, - writer: w, - defaultLimit: opts.withLimit, - }, nil -} - -// list will return a listing of resources and honor the WithLimit option or the -// repo defaultLimit -func (r *Repository) list(ctx context.Context, resources interface{}, where string, args []interface{}, opt ...Option) error { - opts := getOpts(opt...) - limit := r.defaultLimit - var dbOpts []db.Option - if opts.withLimit != 0 { - // non-zero signals an override of the default limit for the repo. - limit = opts.withLimit - } - dbOpts = append(dbOpts, db.WithLimit(limit)) - switch opts.withOrderByVersion { - case db.AscendingOrderBy: - dbOpts = append(dbOpts, db.WithOrder("version asc")) - case db.DescendingOrderBy: - dbOpts = append(dbOpts, db.WithOrder("version desc")) - } - - return r.reader.SearchWhere(ctx, resources, where, args, dbOpts...) -} - -// DefaultLimit returns the default limit for listing as set on the repo -func (r *Repository) DefaultLimit() int { - return r.defaultLimit -} - -// KeyIder defines a common interface for all keys returned from CreateKeysTx in -// a Keys map -type KeyIder interface { - GetPrivateId() string -} - -// Keys defines a return type for CreateKeysTx so the returned keys can be -// easily accessed via their KeyType -type Keys map[KeyType]KeyIder - -// CreateKeysTx creates the root key and DEKs returns a map of the new keys. -// This function encapsulates all the work required within a db.TxHandler and -// allows this capability to be shared with the iam repo. -func CreateKeysTx(ctx context.Context, dbReader db.Reader, dbWriter db.Writer, rootWrapper wrapping.Wrapper, randomReader io.Reader, scopeId string) (Keys, error) { - const op = "kms.CreateKeysTx" - if dbReader == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing db reader") - } - if dbWriter == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing db writer") - } - if rootWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root wrapper") - } - if randomReader == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing random reader") - } - if scopeId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id") - } - k, err := generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for root key in scope %s", scopeId))) - } - rootKey, rootKeyVersion, err := createRootKeyTx(ctx, dbWriter, rootWrapper, scopeId, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create root key in scope %s", scopeId))) - } - - rkvWrapper := aead.NewWrapper() - if _, err := rkvWrapper.SetConfig(ctx, wrapping.WithKeyId(rootKeyVersion.GetPrivateId())); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead root wrapper in scope %s", scopeId))) - } - if err := rkvWrapper.SetAesGcmKeyBytes(rootKeyVersion.GetKey()); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead root wrapper in scope %s", scopeId))) - } - - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for database key in scope %s", scopeId))) - } - dbKey, dbKeyVersion, err := createDatabaseKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create database key in scope %s", scopeId))) - } - - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oplog key in scope %s", scopeId))) - } - oplogKey, oplogKeyVersion, err := createOplogKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create oplog key in scope %s", scopeId))) - } - - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for session key in scope %s", scopeId))) - } - sessionKey, sessionKeyVersion, err := createSessionKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create session key in scope %s", scopeId))) - } - - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for token key in scope %s", scopeId))) - } - tokenKey, tokenKeyVersion, err := createTokenKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create token key in scope %s", scopeId))) - } - - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oidc key in scope %s", scopeId))) - } - oidcKey, oidcKeyVersion, err := createOidcKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create oidc key in scope %s", scopeId))) - } - keys := Keys{ - KeyTypeRootKey: rootKey, - KeyTypeRootKeyVersion: rootKeyVersion, - KeyTypeDatabaseKey: dbKey, - KeyTypeDatabaseKeyVersion: dbKeyVersion, - KeyTypeOplogKey: oplogKey, - KeyTypeOplogKeyVersion: oplogKeyVersion, - KeyTypeSessionKey: sessionKey, - KeyTypeSessionKeyVersion: sessionKeyVersion, - KeyTypeTokenKey: tokenKey, - KeyTypeTokenKeyVersion: tokenKeyVersion, - KeyTypeOidcKey: oidcKey, - KeyTypeOidcKeyVersion: oidcKeyVersion, - } - if scopeId == scope.Global.String() { - k, err = generateKey(ctx, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oidc key in scope %s", scopeId))) - } - auditKey, auditKeyVersion, err := createAuditKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to create audit key in scope %s", scopeId))) - } - keys[KeyTypeAuditKey] = auditKey - keys[KeyTypeAuditKeyVersion] = auditKeyVersion - } - - return keys, nil -} - -func generateKey(ctx context.Context, randomReader io.Reader) ([]byte, error) { - const op = "kms.generateKey" - k, err := uuid.GenerateRandomBytesWithReader(32, randomReader) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return k, nil -} diff --git a/internal/kms/repository_audit_key.go b/internal/kms/repository_audit_key.go deleted file mode 100644 index 96e25b143..000000000 --- a/internal/kms/repository_audit_key.go +++ /dev/null @@ -1,163 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateAuditKey inserts into the repository and returns the new audit key and -// audit key version. There are no valid options at this time. -func (r *Repository) CreateAuditKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*AuditKey, *AuditKeyVersion, error) { - const op = "kms.(Repository).CreateAuditKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createAuditKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*AuditKey), returnedDv.(*AuditKeyVersion), nil -} - -// createAuditKeyTx inserts into the db (via db.Writer) and returns the new audit key -// and audit key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createAuditKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*AuditKey, *AuditKeyVersion, error) { - const op = "kms.createAuditKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - err = r.LookupById(ctx, &rv) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - dk := AllocAuditKey() - dv := AllocAuditKeyVersion() - id, err := newAuditKeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dk.PrivateId = id - dk.RootKeyId = rv.RootKeyId - - id, err = newAuditKeyVersionId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dv.PrivateId = id - dv.AuditKeyId = dk.PrivateId - dv.RootKeyVersionId = rootKeyVersionId - dv.Key = key - if err := dv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no oplog entries for keys - if err := w.Create(ctx, &dk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("keys create")) - } - // no oplog entries for key versions - if err := w.Create(ctx, &dv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &dk, &dv, nil -} - -// LookupAuditKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupAuditKey(ctx context.Context, privateId string, _ ...Option) (*AuditKey, error) { - const op = "kms.(Repository).LookupAuditKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocAuditKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteAuditKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteAuditKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteAuditKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocAuditKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListAuditKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListAuditKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListAuditKeys" - var keys []*AuditKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_audit_key_test.go b/internal/kms/repository_audit_key_test.go deleted file mode 100644 index d9255505b..000000000 --- a/internal/kms/repository_audit_key_test.go +++ /dev/null @@ -1,298 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateAuditKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig( - context.Background(), - wrapping.WithKeyId(""), - ) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - dk, dv, err := repo.CreateAuditKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(dk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(dk.CreateTime) - foundKey, err := repo.LookupAuditKey(context.Background(), dk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, dk)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(dv.CreateTime) - foundKeyVersion, err := repo.LookupAuditKeyVersion(context.Background(), tt.args.keyWrapper, dv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, dv)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteAuditKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.AuditKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestAuditKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.AuditKey { - k := kms.AllocAuditKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.AuditKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocAuditKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteAuditKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupAuditKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListAuditKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestAuditKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListAuditKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_audit_key_version.go b/internal/kms/repository_audit_key_version.go deleted file mode 100644 index 1a474a930..000000000 --- a/internal/kms/repository_audit_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateAuditKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateAuditKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, auditKeyId string, key []byte, _ ...Option) (*AuditKeyVersion, error) { - const op = "kms.(Repository).CreateAuditKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key version ID")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if auditKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing audit key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocAuditKeyVersion() - id, err := newAuditKeyVersionId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.AuditKeyId = auditKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no oplog entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s audit key id", kv.AuditKeyId))) - } - return returnedKey.(*AuditKeyVersion), nil -} - -// LookupAuditKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupAuditKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*AuditKeyVersion, error) { - const op = "kms.(Repository).LookupAuditKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocAuditKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteAuditKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteAuditKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteAuditKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocAuditKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestAuditKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestAuditKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, AuditKeyId string, _ ...Option) (*AuditKeyVersion, error) { - const op = "kms.(Repository).LatestAuditKeyVersion" - if AuditKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing audit key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*AuditKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "audit_key_id = ?", []interface{}{AuditKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", AuditKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListAuditKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListAuditKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, AuditKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListAuditKeyVersions" - if AuditKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing audit key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*AuditKeyVersion - err := r.list(ctx, &versions, "audit_key_id = ?", []interface{}{AuditKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_audit_key_version_test.go b/internal/kms/repository_audit_key_version_test.go deleted file mode 100644 index e87fa43b3..000000000 --- a/internal/kms/repository_audit_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateAuditKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - AuditKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - AuditKeyId: dk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - AuditKeyId: dk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - AuditKeyId: dk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateAuditKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.AuditKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupAuditKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteAuditKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.AuditKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestAuditKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("audit key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.AuditKeyVersion { - k := kms.AllocAuditKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.AuditKeyVersion { - id, err := db.NewPublicId(kms.AuditKeyPrefix) - require.NoError(t, err) - k := kms.AllocAuditKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteAuditKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupAuditKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestAuditKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.AuditKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestAuditKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("test audit key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestAuditKeyVersion(context.Background(), tt.keyWrapper, dk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListAuditKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestAuditKey(t, conn, rk.PrivateId) - - type args struct { - AuditKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - AuditKeyId: dk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - AuditKeyId: dk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - AuditKeyId: dk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - AuditKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - AuditKeyId: dk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocAuditKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.AuditKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestAuditKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("audit key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListAuditKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.AuditKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_database_key.go b/internal/kms/repository_database_key.go deleted file mode 100644 index 2bc58aaa6..000000000 --- a/internal/kms/repository_database_key.go +++ /dev/null @@ -1,163 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateDatabaseKey inserts into the repository and returns the new database key and -// database key version. There are no valid options at this time. -func (r *Repository) CreateDatabaseKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*DatabaseKey, *DatabaseKeyVersion, error) { - const op = "kms.(Repository).CreateDatabaseKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createDatabaseKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*DatabaseKey), returnedDv.(*DatabaseKeyVersion), nil -} - -// createDatabaseKeyTx inserts into the db (via db.Writer) and returns the new database key -// and database key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createDatabaseKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*DatabaseKey, *DatabaseKeyVersion, error) { - const op = "kms.createDatabaseKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - err = r.LookupById(ctx, &rv) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - dk := AllocDatabaseKey() - dv := AllocDatabaseKeyVersion() - id, err := newDatabaseKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dk.PrivateId = id - dk.RootKeyId = rv.RootKeyId - - id, err = newDatabaseKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dv.PrivateId = id - dv.DatabaseKeyId = dk.PrivateId - dv.RootKeyVersionId = rootKeyVersionId - dv.Key = key - if err := dv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no oplog entries for keys - if err := w.Create(ctx, &dk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("keys create")) - } - // no oplog entries for key versions - if err := w.Create(ctx, &dv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &dk, &dv, nil -} - -// LookupDatabaseKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupDatabaseKey(ctx context.Context, privateId string, _ ...Option) (*DatabaseKey, error) { - const op = "kms.(Repository).LookupDatabaseKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocDatabaseKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteDatabaseKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteDatabaseKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteDatabaseKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocDatabaseKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListDatabaseKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListDatabaseKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListDatabaseKeys" - var keys []*DatabaseKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_database_key_test.go b/internal/kms/repository_database_key_test.go deleted file mode 100644 index 8b51c69fd..000000000 --- a/internal/kms/repository_database_key_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateDatabaseKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig(context.Background()) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - dk, dv, err := repo.CreateDatabaseKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(dk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(dk.CreateTime) - foundKey, err := repo.LookupDatabaseKey(context.Background(), dk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, dk)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(dv.CreateTime) - foundKeyVersion, err := repo.LookupDatabaseKeyVersion(context.Background(), tt.args.keyWrapper, dv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, dv)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteDatabaseKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.DatabaseKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestDatabaseKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.DatabaseKey { - k := kms.AllocDatabaseKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.DatabaseKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocDatabaseKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteDatabaseKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupDatabaseKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListDatabaseKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestDatabaseKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListDatabaseKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_database_key_version.go b/internal/kms/repository_database_key_version.go deleted file mode 100644 index 89bf0d90a..000000000 --- a/internal/kms/repository_database_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateDatabaseKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, key []byte, _ ...Option) (*DatabaseKeyVersion, error) { - const op = "kms.(Repository).CreateDatabaseKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if databaseKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing database key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocDatabaseKeyVersion() - id, err := newDatabaseKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.DatabaseKeyId = databaseKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no oplog entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s database key id", kv.DatabaseKeyId))) - } - return returnedKey.(*DatabaseKeyVersion), nil -} - -// LookupDatabaseKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupDatabaseKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*DatabaseKeyVersion, error) { - const op = "kms.(Repository).LookupDatabaseKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocDatabaseKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteDatabaseKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteDatabaseKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteDatabaseKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocDatabaseKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestDatabaseKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, _ ...Option) (*DatabaseKeyVersion, error) { - const op = "kms.(Repository).LatestDatabaseKeyVersion" - if databaseKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing database key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*DatabaseKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "database_key_id = ?", []interface{}{databaseKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", databaseKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListDatabaseKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListDatabaseKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListDatabaseKeyVersions" - if databaseKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing database key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*DatabaseKeyVersion - err := r.list(ctx, &versions, "database_key_id = ?", []interface{}{databaseKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_database_key_version_test.go b/internal/kms/repository_database_key_version_test.go deleted file mode 100644 index 50066fb37..000000000 --- a/internal/kms/repository_database_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateDatabaseKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - databaseKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - databaseKeyId: dk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - databaseKeyId: dk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - databaseKeyId: dk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateDatabaseKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.databaseKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupDatabaseKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteDatabaseKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.DatabaseKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("database key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.DatabaseKeyVersion { - k := kms.AllocDatabaseKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.DatabaseKeyVersion { - id, err := db.NewPublicId(kms.DatabaseKeyPrefix) - require.NoError(t, err) - k := kms.AllocDatabaseKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteDatabaseKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupDatabaseKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestDatabaseKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.DatabaseKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("test database key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestDatabaseKeyVersion(context.Background(), tt.keyWrapper, dk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListDatabaseKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - - type args struct { - databaseKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - databaseKeyId: dk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - databaseKeyId: dk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - databaseKeyId: dk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - databaseKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - databaseKeyId: dk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocDatabaseKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.DatabaseKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestDatabaseKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("database key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListDatabaseKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.databaseKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_oidc_key.go b/internal/kms/repository_oidc_key.go deleted file mode 100644 index d3fe2d03e..000000000 --- a/internal/kms/repository_oidc_key.go +++ /dev/null @@ -1,162 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateOidcKey inserts into the repository and returns the new oidc key and -// oidc key version. There are no valid options at this time. -func (r *Repository) CreateOidcKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*OidcKey, *OidcKeyVersion, error) { - const op = "kms.(Repository).CreateOidcKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createOidcKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*OidcKey), returnedDv.(*OidcKeyVersion), nil -} - -// createOidcKeyTx inserts into the db (via db.Writer) and returns the new oidc key -// and oidc key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createOidcKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*OidcKey, *OidcKeyVersion, error) { - const op = "kms.createOidcKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - if err := r.LookupById(ctx, &rv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - dk := AllocOidcKey() - dv := AllocOidcKeyVersion() - id, err := newOidcKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dk.PrivateId = id - dk.RootKeyId = rv.RootKeyId - - id, err = newOidcKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - dv.PrivateId = id - dv.OidcKeyId = dk.PrivateId - dv.RootKeyVersionId = rootKeyVersionId - dv.Key = key - if err := dv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no oplog entries for keys - if err := w.Create(ctx, &dk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("keys create")) - } - // no oplog entries for key versions - if err := w.Create(ctx, &dv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &dk, &dv, nil -} - -// LookupOidcKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupOidcKey(ctx context.Context, privateId string, _ ...Option) (*OidcKey, error) { - const op = "kms.(Repository).LookupOidcKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOidcKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteOidcKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteOidcKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteOidcKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOidcKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListOidcKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListOidcKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListOidcKeys" - var keys []*OidcKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_oidc_key_test.go b/internal/kms/repository_oidc_key_test.go deleted file mode 100644 index 56c402fdb..000000000 --- a/internal/kms/repository_oidc_key_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateOidcKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig(context.Background()) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - dk, dv, err := repo.CreateOidcKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(dk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(dk.CreateTime) - foundKey, err := repo.LookupOidcKey(context.Background(), dk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, dk)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(dv.CreateTime) - foundKeyVersion, err := repo.LookupOidcKeyVersion(context.Background(), tt.args.keyWrapper, dv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, dv)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, dv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteOidcKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.OidcKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestOidcKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.OidcKey { - k := kms.AllocOidcKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.OidcKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocOidcKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteOidcKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupOidcKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListOidcKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestOidcKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListOidcKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_oidc_key_version.go b/internal/kms/repository_oidc_key_version.go deleted file mode 100644 index 6237952d0..000000000 --- a/internal/kms/repository_oidc_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateOidcKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateOidcKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oidcKeyId string, key []byte, _ ...Option) (*OidcKeyVersion, error) { - const op = "kms.(Repository).CreateOidcKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to fetch key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if oidcKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oidc key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocOidcKeyVersion() - id, err := newOidcKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.OidcKeyId = oidcKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no oplog entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s oidc key id", kv.OidcKeyId))) - } - return returnedKey.(*OidcKeyVersion), nil -} - -// LookupOidcKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupOidcKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*OidcKeyVersion, error) { - const op = "kms.(Repository).LookupOidcKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocOidcKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteOidcKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteOidcKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteOidcKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOidcKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestOidcKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestOidcKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, OidcKeyId string, _ ...Option) (*OidcKeyVersion, error) { - const op = "kms.(Repository).LatestOidcKeyVersion" - if OidcKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oidc key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*OidcKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "oidc_key_id = ?", []interface{}{OidcKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", OidcKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListOidcKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListOidcKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, OidcKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListOidcKeyVersions" - if OidcKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oidc key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*OidcKeyVersion - err := r.list(ctx, &versions, "oidc_key_id = ?", []interface{}{OidcKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_oidc_key_version_test.go b/internal/kms/repository_oidc_key_version_test.go deleted file mode 100644 index 47a51ccfc..000000000 --- a/internal/kms/repository_oidc_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateOidcKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - OidcKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - OidcKeyId: dk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - OidcKeyId: dk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - OidcKeyId: dk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateOidcKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.OidcKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupOidcKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteOidcKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.OidcKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestOidcKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oidc key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.OidcKeyVersion { - k := kms.AllocOidcKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.OidcKeyVersion { - id, err := db.NewPublicId(kms.OidcKeyPrefix) - require.NoError(t, err) - k := kms.AllocOidcKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteOidcKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupOidcKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestOidcKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.OidcKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestOidcKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("test oidc key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestOidcKeyVersion(context.Background(), tt.keyWrapper, dk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListOidcKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOidcKey(t, conn, rk.PrivateId) - - type args struct { - OidcKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - OidcKeyId: dk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - OidcKeyId: dk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - OidcKeyId: dk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - OidcKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - OidcKeyId: dk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOidcKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.OidcKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestOidcKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oidc key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListOidcKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.OidcKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_oplog_key.go b/internal/kms/repository_oplog_key.go deleted file mode 100644 index 0b0fc63a5..000000000 --- a/internal/kms/repository_oplog_key.go +++ /dev/null @@ -1,162 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateOplogKey inserts into the repository and returns the new key and the -// key version. There are no valid options at this time. -func (r *Repository) CreateOplogKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*OplogKey, *OplogKeyVersion, error) { - const op = "kms.(Repository).CreateOplogKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createOplogKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*OplogKey), returnedDv.(*OplogKeyVersion), nil -} - -// createOplogKeyTx inserts into the db (via db.Writer) and returns the new key -// and the key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createOplogKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*OplogKey, *OplogKeyVersion, error) { - const op = "kms.createOplogKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - if err := r.LookupById(ctx, &rv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - opk := AllocOplogKey() - opv := AllocOplogKeyVersion() - id, err := newOplogKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - opk.PrivateId = id - opk.RootKeyId = rv.RootKeyId - - id, err = newOplogKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - opv.PrivateId = id - opv.OplogKeyId = opk.PrivateId - opv.RootKeyVersionId = rootKeyVersionId - opv.Key = key - if err := opv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no oplog entries for keys - if err := w.Create(ctx, &opk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key create")) - } - // no oplog entries for key versions - if err := w.Create(ctx, &opv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &opk, &opv, nil -} - -// LookupOplogKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupOplogKey(ctx context.Context, privateId string, _ ...Option) (*OplogKey, error) { - const op = "kms.(Repository).LookupOplogKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOplogKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteOplogKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteOplogKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteOplogKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOplogKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListOplogKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListOplogKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListOplogKeys" - var keys []*OplogKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_oplog_key_test.go b/internal/kms/repository_oplog_key_test.go deleted file mode 100644 index f897f1f4a..000000000 --- a/internal/kms/repository_oplog_key_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateOplogKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig(context.Background()) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - opk, opv, err := repo.CreateOplogKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(opk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(opk.CreateTime) - foundKey, err := repo.LookupOplogKey(context.Background(), opk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, opk)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, opk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(opv.CreateTime) - foundKeyVersion, err := repo.LookupOplogKeyVersion(context.Background(), tt.args.keyWrapper, opv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, opv)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, opv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteOplogKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.OplogKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestOplogKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.OplogKey { - k := kms.AllocOplogKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.OplogKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocOplogKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteOplogKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupOplogKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListOplogKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestOplogKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListOplogKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_oplog_key_version.go b/internal/kms/repository_oplog_key_version.go deleted file mode 100644 index d7db3e33b..000000000 --- a/internal/kms/repository_oplog_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateOplogKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, key []byte, _ ...Option) (*OplogKeyVersion, error) { - const op = "kms.(Repository).CreateOplogKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to fetch key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if oplogKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oplog key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocOplogKeyVersion() - id, err := newOplogKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.OplogKeyId = oplogKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no oplog entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s oplog key id", kv.OplogKeyId))) - } - return returnedKey.(*OplogKeyVersion), nil -} - -// LookupOplogKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupOplogKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*OplogKeyVersion, error) { - const op = "kms.(Repository).LookupOplogKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocOplogKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteOplogKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteOplogKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteOplogKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocOplogKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestOplogKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, _ ...Option) (*OplogKeyVersion, error) { - const op = "kms.(Repository).LatestOplogKeyVersion" - if oplogKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oplog key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*OplogKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "oplog_key_id = ?", []interface{}{oplogKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", oplogKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListOplogKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListOplogKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListOplogKeyVersions" - if oplogKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing oplog key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*OplogKeyVersion - err := r.list(ctx, &versions, "oplog_key_id = ?", []interface{}{oplogKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_oplog_key_version_test.go b/internal/kms/repository_oplog_key_version_test.go deleted file mode 100644 index 01f1002fb..000000000 --- a/internal/kms/repository_oplog_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateOplogKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - oplogKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - oplogKeyId: dk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - oplogKeyId: dk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - oplogKeyId: dk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateOplogKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.oplogKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupOplogKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteOplogKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.OplogKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestOplogKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oplog key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.OplogKeyVersion { - k := kms.AllocOplogKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.OplogKeyVersion { - id, err := db.NewPublicId(kms.OplogKeyPrefix) - require.NoError(t, err) - k := kms.AllocOplogKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteOplogKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupOplogKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestOplogKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKeyVersion(); ; return &i }(), "1=1") - testKeys := []*kms.OplogKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestOplogKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("test oplog key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestOplogKeyVersion(context.Background(), tt.keyWrapper, dk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListOplogKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestOplogKey(t, conn, rk.PrivateId) - - type args struct { - oplogKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - oplogKeyId: dk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - oplogKeyId: dk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - oplogKeyId: dk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - oplogKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - oplogKeyId: dk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocOplogKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.OplogKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestOplogKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oplog key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListOplogKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.oplogKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_root_key.go b/internal/kms/repository_root_key.go deleted file mode 100644 index cf8844930..000000000 --- a/internal/kms/repository_root_key.go +++ /dev/null @@ -1,146 +0,0 @@ -package kms - -import ( - "context" - "fmt" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateRootKey inserts into the repository and returns the new root key and -// root key version. There are no valid options at this time. -func (r *Repository) CreateRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, scopeId string, key []byte, _ ...Option) (*RootKey, *RootKeyVersion, error) { - const op = "kms.(Repository).CreateRootKey" - var returnedRk, returnedKv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - var err error - if returnedRk, returnedKv, err = createRootKeyTx(ctx, w, keyWrapper, scopeId, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", scopeId))) - } - return returnedRk.(*RootKey), returnedKv.(*RootKeyVersion), nil -} - -// createRootKeyTx inserts into the db (via db.Writer) and returns the new root key -// and root key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createRootKeyTx(ctx context.Context, w db.Writer, keyWrapper wrapping.Wrapper, scopeId string, key []byte) (*RootKey, *RootKeyVersion, error) { - const op = "kms.createRootKeyTx" - if scopeId == "" { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id") - } - if keyWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rk := AllocRootKey() - kv := AllocRootKeyVersion() - id, err := newRootKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - rk.PrivateId = id - rk.ScopeId = scopeId - - id, err = newRootKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyId = rk.PrivateId - kv.Key = key - if err := kv.Encrypt(ctx, keyWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no oplog entries for root keys - if err := w.Create(ctx, &rk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("root keys")) - } - // no oplog entries for root key versions - if err := w.Create(ctx, &kv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions")) - } - - return &rk, &kv, nil -} - -// LookupRootKey will look up a root key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*RootKey, error) { - const op = "kms.(Repository).LookupRootKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocRootKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteRootKey deletes the root key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteRootKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteRootKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocRootKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListRootKeys will list the root keys. Supports the WithLimit option. -func (r *Repository) ListRootKeys(ctx context.Context, opt ...Option) ([]*RootKey, error) { - const op = "kms.(Repository).ListRootKeys" - var keys []*RootKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return keys, nil -} diff --git a/internal/kms/repository_root_key_test.go b/internal/kms/repository_root_key_test.go deleted file mode 100644 index 81571c703..000000000 --- a/internal/kms/repository_root_key_test.go +++ /dev/null @@ -1,270 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateRootKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: false, - }, - { - name: "valid-global", - args: args{ - scopeId: "global", - key: []byte("valid-global"), - keyWrapper: wrapper, - }, - wantErr: false, - }, - { - name: "invalid-scope", - args: args{ - scopeId: "o_notAValidScopeId", - key: []byte("invalid-scope"), - keyWrapper: wrapper, - }, - wantErr: true, - }, - { - name: "empty-scope", - args: args{ - key: []byte("empty-scope"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - rk, kv, err := repo.CreateRootKey(context.Background(), tt.args.keyWrapper, tt.args.scopeId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(rk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(rk.CreateTime) - foundKey, err := repo.LookupRootKey(context.Background(), tt.args.keyWrapper, rk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, rk)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, rk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(kv.CreateTime) - foundKeyVersion, err := repo.LookupRootKeyVersion(context.Background(), tt.args.keyWrapper, kv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, kv)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, kv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteRootKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - type args struct { - key *kms.RootKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestRootKey(t, conn, org.PublicId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.RootKey { - k := kms.AllocRootKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.RootKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocRootKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteRootKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupRootKey(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListRootKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: (repo.DefaultLimit()+1)*2 + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - _, _ = iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - } - got, err := repo.ListRootKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_root_key_version.go b/internal/kms/repository_root_key_version.go deleted file mode 100644 index 502ae1541..000000000 --- a/internal/kms/repository_root_key_version.go +++ /dev/null @@ -1,160 +0,0 @@ -package kms - -import ( - "context" - "fmt" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateRootKeyVersion inserts into the repository and returns the new root key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, key []byte, _ ...Option) (*RootKeyVersion, error) { - const op = "kms.(Repository).CreateRootKeyVersion" - if rootKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocRootKeyVersion() - id, err := newRootKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyId = rootKeyId - kv.Key = key - if err := kv.Encrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no oplog entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s root key id", kv.RootKeyId))) - } - return returnedKey.(*RootKeyVersion), nil -} - -// LookupRootKeyVersion will look up a root key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*RootKeyVersion, error) { - const op = "kms.(Repository).LookupRootKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocRootKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteRootKeyVersion deletes the root key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteRootKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteRootKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocRootKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no oplog entries for root key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestRootKeyVersion searches for the root key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, _ ...Option) (*RootKeyVersion, error) { - const op = "kms.(Repository).LatestRootKeyVersion" - if rootKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - var foundKeys []RootKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "root_key_id = ?", []interface{}{rootKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", rootKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &foundKeys[0], nil -} - -// ListRootKeyVersions in versions of a root key. Supports the WithLimit option. -func (r *Repository) ListRootKeyVersions(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, opt ...Option) ([]*RootKeyVersion, error) { - const op = "kms.(Repository).ListRootKeyVersions" - if rootKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - var versions []*RootKeyVersion - err := r.list(ctx, &versions, "root_key_id = ?", []interface{}{rootKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - return versions, nil -} diff --git a/internal/kms/repository_root_key_version_test.go b/internal/kms/repository_root_key_version_test.go deleted file mode 100644 index 0b47a4ac4..000000000 --- a/internal/kms/repository_root_key_version_test.go +++ /dev/null @@ -1,363 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateRootKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - rootKeyId: rk.PrivateId, - keyWrapper: wrapper, - }, - wantErr: false, - }, - { - name: "invalid-root-key", - args: args{ - key: []byte("test key"), - rootKeyId: "krk_thisIsNotValid", - keyWrapper: wrapper, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - rootKeyId: rk.PrivateId, - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - rootKeyId: rk.PrivateId, - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateRootKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.rootKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupRootKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteRootKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.RootKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: func() *kms.RootKeyVersion { - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - return k - }(), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.RootKeyVersion { - k := kms.AllocRootKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.RootKeyVersion { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocRootKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteRootKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupRootKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestRootKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: wrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: wrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: wrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.RootKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestRootKeyVersion(context.Background(), tt.keyWrapper, rk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListRootKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - rootKeyId: rk.PrivateId, - keyWrapper: wrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: wrapper, - rootKeyId: rk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: wrapper, - rootKeyId: rk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: wrapper, - rootKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - rootKeyId: rk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKeyVersion(); return &i }(), "1=1") - testRootKeyVersions := []*kms.RootKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - testRootKeyVersions = append(testRootKeyVersions, k) - } - assert.Equal(tt.createCnt, len(testRootKeyVersions)) - got, err := repo.ListRootKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_session_key.go b/internal/kms/repository_session_key.go deleted file mode 100644 index 24e0d548e..000000000 --- a/internal/kms/repository_session_key.go +++ /dev/null @@ -1,162 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateSessionKey inserts into the repository and returns the new key and the -// key version. There are no valid options at this time. -func (r *Repository) CreateSessionKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*SessionKey, *SessionKeyVersion, error) { - const op = "kms.(Repository).CreateSessionKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createSessionKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*SessionKey), returnedDv.(*SessionKeyVersion), nil -} - -// createSessionKeyTx inserts into the db (via db.Writer) and returns the new key -// and the key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createSessionKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*SessionKey, *SessionKeyVersion, error) { - const op = "kms.createSessionKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - if err := r.LookupById(ctx, &rv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - tk := AllocSessionKey() - tv := AllocSessionKeyVersion() - id, err := newSessionKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - tk.PrivateId = id - tk.RootKeyId = rv.RootKeyId - - id, err = newSessionKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - tv.PrivateId = id - tv.SessionKeyId = tk.PrivateId - tv.RootKeyVersionId = rootKeyVersionId - tv.Key = key - if err := tv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no session entries for keys - if err := w.Create(ctx, &tk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("keys create")) - } - // no session entries for key versions - if err := w.Create(ctx, &tv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &tk, &tv, nil -} - -// LookupSessionKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupSessionKey(ctx context.Context, privateId string, _ ...Option) (*SessionKey, error) { - const op = "kms.(Repository).LookupSessionKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocSessionKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteSessionKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteSessionKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteSessionKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocSessionKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no session entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListSessionKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListSessionKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListSessionKeys" - var keys []*SessionKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_session_key_test.go b/internal/kms/repository_session_key_test.go deleted file mode 100644 index 538ea883f..000000000 --- a/internal/kms/repository_session_key_test.go +++ /dev/null @@ -1,296 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateSessionKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig(context.Background()) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - tk, tv, err := repo.CreateSessionKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(tk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(tk.CreateTime) - foundKey, err := repo.LookupSessionKey(context.Background(), tk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, tk)) - - // make sure there was no session written - err = db.TestVerifyOplog(t, rw, tk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(tv.CreateTime) - foundKeyVersion, err := repo.LookupSessionKeyVersion(context.Background(), tt.args.keyWrapper, tv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, tv)) - - // make sure there was no session written - err = db.TestVerifyOplog(t, rw, tv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteSessionKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.SessionKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestSessionKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.SessionKey { - k := kms.AllocSessionKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.SessionKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocSessionKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteSessionKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - - // make sure there was no session written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupSessionKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no session written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListSessionKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestSessionKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListSessionKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_session_key_version.go b/internal/kms/repository_session_key_version.go deleted file mode 100644 index 89874e4d6..000000000 --- a/internal/kms/repository_session_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateSessionKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, key []byte, _ ...Option) (*SessionKeyVersion, error) { - const op = "kms.(Repository).CreateSessionKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to fetch key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if sessionKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing session key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocSessionKeyVersion() - id, err := newSessionKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.SessionKeyId = sessionKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no session entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s session key id", kv.SessionKeyId))) - } - return returnedKey.(*SessionKeyVersion), nil -} - -// LookupSessionKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupSessionKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*SessionKeyVersion, error) { - const op = "kms.(Repository).LookupSessionKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocSessionKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteSessionKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteSessionKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteSessionKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocSessionKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no session entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestSessionKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, _ ...Option) (*SessionKeyVersion, error) { - const op = "kms.(Repository).LatestSessionKeyVersion" - if sessionKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing session key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*SessionKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "session_key_id = ?", []interface{}{sessionKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", sessionKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListSessionKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListSessionKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListSessionKeyVersions" - if sessionKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing session key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*SessionKeyVersion - err := r.list(ctx, &versions, "session_key_id = ?", []interface{}{sessionKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_session_key_version_test.go b/internal/kms/repository_session_key_version_test.go deleted file mode 100644 index b64d466f9..000000000 --- a/internal/kms/repository_session_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateSessionKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - sk := kms.TestSessionKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - sessionKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - sessionKeyId: sk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - sessionKeyId: sk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - sessionKeyId: sk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateSessionKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.sessionKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupSessionKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteSessionKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - sk := kms.TestSessionKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.SessionKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestSessionKeyVersion(t, conn, rkvWrapper, sk.PrivateId, []byte("session key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.SessionKeyVersion { - k := kms.AllocSessionKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.SessionKeyVersion { - id, err := db.NewPublicId(kms.SessionKeyPrefix) - require.NoError(t, err) - k := kms.AllocSessionKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteSessionKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupSessionKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestSessionKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - sk := kms.TestSessionKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.SessionKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestSessionKeyVersion(t, conn, rkvWrapper, sk.PrivateId, []byte("test key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestSessionKeyVersion(context.Background(), tt.keyWrapper, sk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListSessionKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - sk := kms.TestSessionKey(t, conn, rk.PrivateId) - - type args struct { - sessionKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - sessionKeyId: sk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - sessionKeyId: sk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - sessionKeyId: sk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - sessionKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - sessionKeyId: sk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.SessionKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestSessionKeyVersion(t, conn, rkvWrapper, sk.PrivateId, []byte("session key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListSessionKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.sessionKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_test.go b/internal/kms/repository_test.go deleted file mode 100644 index 2a77e986b..000000000 --- a/internal/kms/repository_test.go +++ /dev/null @@ -1,288 +0,0 @@ -package kms_test - -import ( - "context" - "crypto/rand" - "io" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/types/scope" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNewRepository(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - type args struct { - r db.Reader - w db.Writer - } - tests := []struct { - name string - args args - want *kms.Repository - wantErr bool - wantErrString string - }{ - { - name: "valid", - args: args{ - r: rw, - w: rw, - }, - want: func() *kms.Repository { - ret, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - return ret - }(), - wantErr: false, - }, - { - name: "nil-writer", - args: args{ - r: rw, - w: nil, - }, - want: nil, - wantErr: true, - wantErrString: "kms.NewRepository: nil writer: parameter violation: error #100", - }, - { - name: "nil-reader", - args: args{ - r: nil, - w: rw, - }, - want: nil, - wantErr: true, - wantErrString: "kms.NewRepository: nil reader: parameter violation: error #100", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - got, err := kms.NewRepository(tt.args.r, tt.args.w) - if tt.wantErr { - require.Error(err) - assert.Equal(tt.wantErrString, err.Error()) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - }) - } -} - -func TestCreateKeysTx(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - type args struct { - ctx context.Context - dbReader db.Reader - dbWriter db.Writer - rootWrapper wrapping.Wrapper - randomReader io.Reader - scopeId string - } - tests := []struct { - name string - args args - wantErr bool - wantErrIs errors.Code - }{ - { - name: "valid", - args: args{ - dbReader: rw, - dbWriter: rw, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: org.PublicId, - }, - }, - { - name: "valid-at-global", - args: args{ - dbReader: rw, - dbWriter: rw, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: scope.Global.String(), - }, - }, - { - name: "nil-reader", - args: args{ - dbReader: nil, - dbWriter: rw, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: org.PublicId, - }, - wantErr: true, - wantErrIs: errors.InvalidParameter, - }, - { - name: "nil-writer", - args: args{ - dbReader: rw, - dbWriter: nil, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: org.PublicId, - }, - wantErr: true, - wantErrIs: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - dbReader: rw, - dbWriter: rw, - rootWrapper: nil, - randomReader: rand.Reader, - scopeId: org.PublicId, - }, - wantErr: true, - wantErrIs: errors.InvalidParameter, - }, - { - name: "empty-scope", - args: args{ - dbReader: rw, - dbWriter: rw, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: "", - }, - wantErr: true, - wantErrIs: errors.InvalidParameter, - }, - { - name: "bad-scope", - args: args{ - dbReader: rw, - dbWriter: rw, - rootWrapper: wrapper, - randomReader: rand.Reader, - scopeId: "o_thisIsAnInvalidScopeId", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - keys, err := kms.CreateKeysTx(tt.args.ctx, tt.args.dbReader, tt.args.dbWriter, tt.args.rootWrapper, tt.args.randomReader, tt.args.scopeId) - if tt.wantErr { - require.Error(err) - assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error()) - return - } - require.NoError(err) - rk := kms.AllocRootKey() - rk.PrivateId = keys[kms.KeyTypeRootKey].GetPrivateId() - err = rw.LookupById(context.Background(), &rk) - require.NoError(err) - assert.Equal(rk.ScopeId, tt.args.scopeId) - - rkv := kms.AllocRootKeyVersion() - rkv.PrivateId = keys[kms.KeyTypeRootKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &rkv) - require.NoError(err) - assert.Equal(rkv.RootKeyId, rk.PrivateId) - - dk := kms.AllocDatabaseKey() - dk.PrivateId = keys[kms.KeyTypeDatabaseKey].GetPrivateId() - err = rw.LookupById(context.Background(), &dk) - require.NoError(err) - assert.Equal(rk.PrivateId, dk.RootKeyId) - - dkv := kms.AllocDatabaseKeyVersion() - dkv.PrivateId = keys[kms.KeyTypeDatabaseKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &dkv) - require.NoError(err) - assert.Equal(dk.PrivateId, dkv.DatabaseKeyId) - assert.Equal(rkv.PrivateId, dkv.RootKeyVersionId) - - opk := kms.AllocOplogKey() - opk.PrivateId = keys[kms.KeyTypeOplogKey].GetPrivateId() - err = rw.LookupById(context.Background(), &opk) - require.NoError(err) - assert.Equal(rk.PrivateId, opk.RootKeyId) - - opkv := kms.AllocOplogKeyVersion() - opkv.PrivateId = keys[kms.KeyTypeOplogKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &opkv) - require.NoError(err) - assert.Equal(opk.PrivateId, opkv.OplogKeyId) - assert.Equal(rkv.PrivateId, opkv.RootKeyVersionId) - - sk := kms.AllocSessionKey() - sk.PrivateId = keys[kms.KeyTypeSessionKey].GetPrivateId() - err = rw.LookupById(context.Background(), &sk) - require.NoError(err) - assert.Equal(rk.PrivateId, sk.RootKeyId) - - skv := kms.AllocSessionKeyVersion() - skv.PrivateId = keys[kms.KeyTypeSessionKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &skv) - require.NoError(err) - assert.Equal(sk.PrivateId, skv.SessionKeyId) - assert.Equal(rkv.PrivateId, skv.RootKeyVersionId) - - tk := kms.AllocTokenKey() - tk.PrivateId = keys[kms.KeyTypeTokenKey].GetPrivateId() - err = rw.LookupById(context.Background(), &tk) - require.NoError(err) - assert.Equal(rk.PrivateId, tk.RootKeyId) - - tkv := kms.AllocTokenKeyVersion() - tkv.PrivateId = keys[kms.KeyTypeTokenKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &tkv) - require.NoError(err) - assert.Equal(tk.PrivateId, tkv.TokenKeyId) - assert.Equal(rkv.PrivateId, tkv.RootKeyVersionId) - - oidcK := kms.AllocOidcKey() - oidcK.PrivateId = keys[kms.KeyTypeOidcKey].GetPrivateId() - err = rw.LookupById(context.Background(), &oidcK) - require.NoError(err) - assert.Equal(rk.PrivateId, oidcK.RootKeyId) - - oidcKv := kms.AllocOidcKeyVersion() - oidcKv.PrivateId = keys[kms.KeyTypeOidcKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &oidcKv) - require.NoError(err) - assert.Equal(oidcK.PrivateId, oidcKv.OidcKeyId) - assert.Equal(rkv.PrivateId, oidcKv.RootKeyVersionId) - - if tt.args.scopeId == scope.Global.String() { - auditK := kms.AllocAuditKey() - auditK.PrivateId = keys[kms.KeyTypeAuditKey].GetPrivateId() - err = rw.LookupById(context.Background(), &auditK) - require.NoError(err) - assert.Equal(rk.PrivateId, auditK.RootKeyId) - - auditKv := kms.AllocAuditKeyVersion() - auditKv.PrivateId = keys[kms.KeyTypeAuditKeyVersion].GetPrivateId() - err = rw.LookupById(context.Background(), &auditKv) - require.NoError(err) - assert.Equal(auditK.PrivateId, auditKv.AuditKeyId) - assert.Equal(rkv.PrivateId, auditKv.RootKeyVersionId) - } - }) - } -} diff --git a/internal/kms/repository_token_key.go b/internal/kms/repository_token_key.go deleted file mode 100644 index 7d043ab4b..000000000 --- a/internal/kms/repository_token_key.go +++ /dev/null @@ -1,162 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateTokenKey inserts into the repository and returns the new key and the -// key version. There are no valid options at this time. -func (r *Repository) CreateTokenKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*TokenKey, *TokenKeyVersion, error) { - const op = "kms.(Repository).CreateTokenKey" - var returnedDk, returnedDv interface{} - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(reader db.Reader, w db.Writer) error { - var err error - if returnedDk, returnedDv, err = createTokenKeyTx(ctx, reader, w, rkvWrapper, key); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - return returnedDk.(*TokenKey), returnedDv.(*TokenKeyVersion), nil -} - -// createTokenKeyTx inserts into the db (via db.Writer) and returns the new key -// and the key version. This function encapsulates all the work required within -// a db.TxHandler and allows this capability to be shared with the iam repo. -func createTokenKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*TokenKey, *TokenKeyVersion, error) { - const op = "kms.createTokenKeyTx" - if rkvWrapper == nil { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - if len(key) == 0 { - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to lookup root key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - rv := AllocRootKeyVersion() - rv.PrivateId = rootKeyVersionId - if err := r.LookupById(ctx, &rv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId))) - } - - tk := AllocTokenKey() - tv := AllocTokenKeyVersion() - id, err := newTokenKeyId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - tk.PrivateId = id - tk.RootKeyId = rv.RootKeyId - - id, err = newTokenKeyVersionId() - if err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - tv.PrivateId = id - tv.TokenKeyId = tk.PrivateId - tv.RootKeyVersionId = rootKeyVersionId - tv.Key = key - if err := tv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, nil, errors.Wrap(ctx, err, op) - } - - // no token entries for keys - if err := w.Create(ctx, &tk); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("keys create")) - } - // no token entries for key versions - if err := w.Create(ctx, &tv); err != nil { - return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("key versions create")) - } - - return &tk, &tv, nil -} - -// LookupTokenKey will look up a key in the repository. If the key is not -// found, it will return nil, nil. -func (r *Repository) LookupTokenKey(ctx context.Context, privateId string, _ ...Option) (*TokenKey, error) { - const op = "kms.(Repository).LookupTokenKey" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocTokenKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return &k, nil -} - -// DeleteTokenKey deletes the key for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteTokenKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteTokenKey" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocTokenKey() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no token entries for root keys - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// ListTokenKeys will list the keys. Supports the WithLimit option. -func (r *Repository) ListTokenKeys(ctx context.Context, opt ...Option) ([]Dek, error) { - const op = "kms.(Repository).ListTokenKeys" - var keys []*TokenKey - err := r.list(ctx, &keys, "1=1", nil, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - deks := make([]Dek, 0, len(keys)) - for _, key := range keys { - deks = append(deks, key) - } - return deks, nil -} diff --git a/internal/kms/repository_token_key_test.go b/internal/kms/repository_token_key_test.go deleted file mode 100644 index 308fb4e4e..000000000 --- a/internal/kms/repository_token_key_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateTokenKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - type args struct { - scopeId string - key []byte - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid-org", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: rkvWrapper, - }, - wantErr: false, - }, - { - name: "nil-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - scopeId: org.PublicId, - keyWrapper: rkvWrapper, - key: []byte(""), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-rkv-wrapper", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: wrapper, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "wrapper-missing-id", - args: args{ - scopeId: org.PublicId, - key: []byte("test key"), - keyWrapper: func() wrapping.Wrapper { - w := db.TestWrapper(t) - _, err = w.(*aead.Wrapper).SetConfig(context.Background()) - require.NoError(t, err) - return w - }(), - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - tk, tv, err := repo.CreateTokenKey(context.Background(), tt.args.keyWrapper, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(tk) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(tk.CreateTime) - foundKey, err := repo.LookupTokenKey(context.Background(), tk.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, tk)) - - // make sure there was no token written - err = db.TestVerifyOplog(t, rw, tk.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - - assert.NotNil(tv.CreateTime) - foundKeyVersion, err := repo.LookupTokenKeyVersion(context.Background(), tt.args.keyWrapper, tv.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKeyVersion, tv)) - - // make sure there was no token written - err = db.TestVerifyOplog(t, rw, tv.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteTokenKey(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - key *kms.TokenKey - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestTokenKey(t, conn, rk.PrivateId), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.TokenKey { - k := kms.AllocTokenKey() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.TokenKey { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k := kms.AllocTokenKey() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteTokenKey(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - // make sure there was no token written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupTokenKey(context.Background(), tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no token written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_ListTokenKeys(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - wrapper := db.TestWrapper(t) - - type args struct { - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, // org and project both have keys, plus global scope - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{}, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - } - for _, tt := range tests { - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - for i := 0; i < tt.createCnt; i++ { - org, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "scope_id in(?)", "global", org.PublicId, proj.PublicId) - rk := kms.TestRootKey(t, conn, proj.PublicId) - kms.TestTokenKey(t, conn, rk.PrivateId) - require.NoError(err) - } - got, err := repo.ListTokenKeys(context.Background(), tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/repository_token_key_version.go b/internal/kms/repository_token_key_version.go deleted file mode 100644 index 4c612bd5d..000000000 --- a/internal/kms/repository_token_key_version.go +++ /dev/null @@ -1,176 +0,0 @@ -package kms - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" -) - -// CreateTokenKeyVersion inserts into the repository and returns the new key -// version with its PrivateId. There are no valid options at this time. -func (r *Repository) CreateTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, key []byte, _ ...Option) (*TokenKeyVersion, error) { - const op = "kms.(Repository).CreateTokenKeyVersion" - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - rootKeyVersionId, err := rkvWrapper.KeyId(ctx) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to fetch key id")) - } - switch { - case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix): - return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix)) - case rootKeyVersionId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - if tokenKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token key id") - } - if len(key) == 0 { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - kv := AllocTokenKeyVersion() - id, err := newTokenKeyVersionId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - kv.PrivateId = id - kv.RootKeyVersionId = rootKeyVersionId - kv.Key = key - kv.TokenKeyId = tokenKeyId - if err := kv.Encrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - var returnedKey interface{} - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedKey = kv.Clone() - // no token entries for root key version - if err := w.Create(ctx, returnedKey); err != nil { - return errors.Wrap(ctx, err, op) - } - return nil - }, - ) - if err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s token key id", kv.TokenKeyId))) - } - return returnedKey.(*TokenKeyVersion), nil -} - -// LookupTokenKeyVersion will look up a key version in the repository. If -// the key version is not found, it will return nil, nil. -func (r *Repository) LookupTokenKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*TokenKeyVersion, error) { - const op = "kms.(Repository).LookupTokenKeyVersion" - if privateId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if keyWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing key wrapper") - } - k := AllocTokenKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - if err := k.Decrypt(ctx, keyWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return &k, nil -} - -// DeleteTokenKeyVersion deletes the key version for the provided id from the -// repository returning a count of the number of records deleted. All options -// are ignored. -func (r *Repository) DeleteTokenKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).DeleteTokenKeyVersion" - if privateId == "" { - return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - k := AllocTokenKeyVersion() - k.PrivateId = privateId - if err := r.reader.LookupById(ctx, &k); err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - - var rowsDeleted int - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) (err error) { - dk := k.Clone() - // no token entries for the key version - rowsDeleted, err = w.Delete(ctx, dk) - if err != nil { - return errors.Wrap(ctx, err, op) - } - if rowsDeleted > 1 { - return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") - } - return nil - }, - ) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId))) - } - return rowsDeleted, nil -} - -// LatestTokenKeyVersion searches for the key version with the highest -// version number. When no results are found, it returns nil with an -// errors.RecordNotFound error. -func (r *Repository) LatestTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, _ ...Option) (*TokenKeyVersion, error) { - const op = "kms.(Repository).LatestTokenKeyVersion" - if tokenKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var foundKeys []*TokenKeyVersion - if err := r.reader.SearchWhere(ctx, &foundKeys, "token_key_id = ?", []interface{}{tokenKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", tokenKeyId))) - } - if len(foundKeys) == 0 { - return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op)) - } - if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op) - } - return foundKeys[0], nil -} - -// ListTokenKeyVersions will lists versions of a key. Supports the WithLimit option. -func (r *Repository) ListTokenKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, opt ...Option) ([]DekVersion, error) { - const op = "kms.(Repository).ListTokenKeyVersions" - if tokenKeyId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token key id") - } - if rkvWrapper == nil { - return nil, errors.New(ctx, errors.InvalidParameter, op, "missing root key version wrapper") - } - var versions []*TokenKeyVersion - err := r.list(ctx, &versions, "token_key_id = ?", []interface{}{tokenKeyId}, opt...) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - for i, k := range versions { - if err := k.Decrypt(ctx, rkvWrapper); err != nil { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i))) - } - } - dekVersions := make([]DekVersion, 0, len(versions)) - for _, version := range versions { - dekVersions = append(dekVersions, version) - } - return dekVersions, nil -} diff --git a/internal/kms/repository_token_key_version_test.go b/internal/kms/repository_token_key_version_test.go deleted file mode 100644 index 204e65279..000000000 --- a/internal/kms/repository_token_key_version_test.go +++ /dev/null @@ -1,367 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - "time" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/oplog" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestRepository_CreateTokenKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - - type args struct { - key []byte - tokenKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - args args - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: []byte("test key"), - keyWrapper: rkvWrapper, - tokenKeyId: dk.PrivateId, - }, - wantErr: false, - }, - { - name: "invalid-rkv-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: wrapper, - tokenKeyId: dk.PrivateId, - }, - wantErr: true, - }, - { - name: "empty-key", - args: args{ - key: nil, - keyWrapper: wrapper, - tokenKeyId: dk.PrivateId, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "nil-wrapper", - args: args{ - key: []byte("test key"), - keyWrapper: nil, - }, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - k, err := repo.CreateTokenKeyVersion(context.Background(), tt.args.keyWrapper, tt.args.tokenKeyId, tt.args.key, tt.args.opt...) - if tt.wantErr { - assert.Error(err) - assert.Nil(k) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - assert.NotNil(k.CreateTime) - foundKey, err := repo.LookupTokenKeyVersion(context.Background(), tt.args.keyWrapper, k.PrivateId) - assert.NoError(err) - assert.True(proto.Equal(foundKey, k)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, k.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_DeleteTokenKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - - type args struct { - key *kms.TokenKeyVersion - opt []kms.Option - } - tests := []struct { - name string - args args - wantRowsDeleted int - wantErr bool - wantIsError errors.Code - }{ - { - name: "valid", - args: args{ - key: kms.TestTokenKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("token key")), - }, - wantRowsDeleted: 1, - wantErr: false, - }, - { - name: "no-private-id", - args: args{ - key: func() *kms.TokenKeyVersion { - k := kms.AllocTokenKeyVersion() - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - { - name: "not-found", - args: args{ - key: func() *kms.TokenKeyVersion { - id, err := db.NewPublicId(kms.TokenKeyPrefix) - require.NoError(t, err) - k := kms.AllocTokenKeyVersion() - k.PrivateId = id - require.NoError(t, err) - return &k - }(), - }, - wantRowsDeleted: 0, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deletedRows, err := repo.DeleteTokenKeyVersion(context.Background(), tt.args.key.PrivateId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.Equal(0, deletedRows) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - return - } - require.NoError(err) - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey, err := repo.LookupTokenKeyVersion(context.Background(), wrapper, tt.args.key.PrivateId) - assert.Error(err) - assert.Nil(foundKey) - assert.True(errors.IsNotFoundError(err)) - - // make sure there was no oplog written - err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) - assert.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRepository_LatestTokenKeyVersion(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - - tests := []struct { - name string - createCnt int - keyWrapper wrapping.Wrapper - wantVersion uint32 - wantErr bool - wantIsError errors.Code - }{ - { - name: "5", - createCnt: 5, - keyWrapper: rkvWrapper, - wantVersion: 5, - wantErr: false, - }, - { - name: "1", - createCnt: 1, - keyWrapper: rkvWrapper, - wantVersion: 1, - wantErr: false, - }, - { - name: "0", - createCnt: 0, - keyWrapper: rkvWrapper, - wantErr: true, - wantIsError: errors.RecordNotFound, - }, - { - name: "nil-wrapper", - createCnt: 5, - keyWrapper: nil, - wantErr: true, - wantIsError: errors.InvalidParameter, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKeyVersion(); return &i }(), "1=1") - testKeys := []*kms.TokenKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestTokenKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("test key")) - testKeys = append(testKeys, k) - } - assert.Equal(tt.createCnt, len(testKeys)) - got, err := repo.LatestTokenKeyVersion(context.Background(), tt.keyWrapper, dk.PrivateId) - if tt.wantErr { - require.Error(err) - assert.Nil(got) - assert.True(errors.Match(errors.T(tt.wantIsError), err)) - return - } - require.NoError(err) - require.NotNil(got) - assert.Equal(tt.wantVersion, got.Version) - }) - } -} - -func TestRepository_ListTokenKeyVersions(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - const testLimit = 10 - rw := db.New(conn) - wrapper := db.TestWrapper(t) - repo, err := kms.NewRepository(rw, rw, kms.WithLimit(testLimit)) - require.NoError(t, err) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - - type args struct { - tokenKeyId string - keyWrapper wrapping.Wrapper - opt []kms.Option - } - tests := []struct { - name string - createCnt int - args args - wantCnt int - wantErr bool - }{ - { - name: "no-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - tokenKeyId: dk.PrivateId, - keyWrapper: rkvWrapper, - opt: []kms.Option{kms.WithLimit(-1)}, - }, - wantCnt: repo.DefaultLimit() + 1, - wantErr: false, - }, - { - name: "default-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - tokenKeyId: dk.PrivateId, - }, - wantCnt: repo.DefaultLimit(), - wantErr: false, - }, - { - name: "custom-limit", - createCnt: repo.DefaultLimit() + 1, - args: args{ - keyWrapper: rkvWrapper, - tokenKeyId: dk.PrivateId, - opt: []kms.Option{kms.WithLimit(3)}, - }, - wantCnt: 3, - wantErr: false, - }, - { - name: "bad-org", - createCnt: 1, - args: args{ - keyWrapper: rkvWrapper, - tokenKeyId: "bad-id", - }, - wantCnt: 0, - wantErr: false, - }, - { - name: "nil-wrapper", - createCnt: 1, - args: args{ - keyWrapper: nil, - tokenKeyId: dk.PrivateId, - }, - wantCnt: 0, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKeyVersion(); return &i }(), "1=1") - keyVersions := []*kms.TokenKeyVersion{} - for i := 0; i < tt.createCnt; i++ { - k := kms.TestTokenKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("token key")) - keyVersions = append(keyVersions, k) - } - assert.Equal(tt.createCnt, len(keyVersions)) - got, err := repo.ListTokenKeyVersions(context.Background(), tt.args.keyWrapper, tt.args.tokenKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - assert.Equal(tt.wantCnt, len(got)) - }) - } -} diff --git a/internal/kms/root_key.go b/internal/kms/root_key.go deleted file mode 100644 index f98049487..000000000 --- a/internal/kms/root_key.go +++ /dev/null @@ -1,84 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultRootKeyTableName = "kms_root_key" -) - -type RootKey struct { - *store.RootKey - tableName string `gorm:"-"` -} - -// NewRootKey creates a new in memory root key. ScopeId must be -// for a global or org scope, but the scope type validation will be deferred -// until the in memory root key is written to the database. No options -// are currently supported. -func NewRootKey(scopeId string, _ ...Option) (*RootKey, error) { - const op = "kms.NewRootKey" - if scopeId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing scope id") - } - c := &RootKey{ - RootKey: &store.RootKey{ - ScopeId: scopeId, - }, - } - return c, nil -} - -// AllocRootKey will allocate a root key -func AllocRootKey() RootKey { - return RootKey{ - RootKey: &store.RootKey{}, - } -} - -// Clone creates a clone of the RootKey -func (k *RootKey) Clone() interface{} { - cp := proto.Clone(k.RootKey) - return &RootKey{ - RootKey: cp.(*store.RootKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *RootKey) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(RootKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.ScopeId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing scope id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *RootKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultRootKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (c *RootKey) SetTableName(n string) { - c.tableName = n -} diff --git a/internal/kms/root_key_test.go b/internal/kms/root_key_test.go deleted file mode 100644 index d364cd627..000000000 --- a/internal/kms/root_key_test.go +++ /dev/null @@ -1,210 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the RootKey attributes are -// immutable and those tests are covered by TestRootKey_ImmutableFields - -func TestRootKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - type args struct { - scopeId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.RootKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-scopeId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid-org-config", - args: args{ - scopeId: org.PublicId, - }, - want: func() *kms.RootKey { - k := kms.AllocRootKey() - k.ScopeId = org.PublicId - return &k - }(), - create: true, - }, - { - name: "valid-global-config", - args: args{ - scopeId: "global", - }, - want: func() *kms.RootKey { - k := kms.AllocRootKey() - k.ScopeId = "global" - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - got, err := kms.NewRootKey(tt.args.scopeId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestRootKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.RootKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestRootKey(t, conn, org.PublicId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.RootKey { - k := kms.AllocRootKey() - id, err := db.NewPublicId(kms.RootKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.ScopeId = org.PublicId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocRootKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocRootKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRootKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.RootKey).RootKey, k.RootKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - k2 := kms.TestRootKey(t, conn, org2.PublicId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.RootKey).RootKey, k2.RootKey)) - }) -} - -func TestRootKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultRootKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocRootKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocRootKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/root_key_version.go b/internal/kms/root_key_version.go deleted file mode 100644 index a6cba9469..000000000 --- a/internal/kms/root_key_version.go +++ /dev/null @@ -1,114 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultRootKeyVersionTableName = "kms_root_key_version" -) - -type RootKeyVersion struct { - *store.RootKeyVersion - tableName string `gorm:"-"` -} - -// NewRootKeyVersion creates a new in memory root key version. No options are -// currently supported. -func NewRootKeyVersion(rootKeyId string, key []byte, _ ...Option) (*RootKeyVersion, error) { - const op = "kms.NewRootKeyVersion" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - - k := &RootKeyVersion{ - RootKeyVersion: &store.RootKeyVersion{ - RootKeyId: rootKeyId, - Key: key, - }, - } - return k, nil -} - -// AllocRootKeyVersion allocates a RootKeyVersion -func AllocRootKeyVersion() RootKeyVersion { - return RootKeyVersion{ - RootKeyVersion: &store.RootKeyVersion{}, - } -} - -// Clone creates a clone of the RootKeyVersion -func (k *RootKeyVersion) Clone() interface{} { - cp := proto.Clone(k.RootKeyVersion) - return &RootKeyVersion{ - RootKeyVersion: cp.(*store.RootKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the root key -// version before it's written. -func (k *RootKeyVersion) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(RootKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - switch opType { - case db.CreateOp: - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - case db.UpdateOp: - return errors.New(ctx, errors.InvalidParameter, op, "key is immutable") - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *RootKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultRootKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *RootKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the root key version's key -func (k *RootKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(RootKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.RootKey directly - if err := structwrapping.WrapStruct(ctx, cipher, k.RootKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the root key version's key -func (k *RootKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(RootKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.RootKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.RootKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/root_key_version_test.go b/internal/kms/root_key_version_test.go deleted file mode 100644 index 36a2a6c1e..000000000 --- a/internal/kms/root_key_version_test.go +++ /dev/null @@ -1,219 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/hashicorp/boundary/internal/kms/store" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the RootKeyVersion attributes are -// immutable and those tests are covered by TestRootKeyVersion_ImmutableFields - -func TestRootKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rootKey := kms.TestRootKey(t, conn, org.PublicId) - type args struct { - rootId string - key []byte - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.RootKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-root-id", - args: args{ - key: []byte("test key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - rootId: rootKey.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootId: rootKey.PrivateId, - key: []byte("test key"), - }, - want: func() *kms.RootKeyVersion { - k := kms.AllocRootKeyVersion() - k.RootKeyId = rootKey.PrivateId - k.Key = []byte("test key") - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKeyVersion(); return &i }(), "1=1") - got, err := kms.NewRootKeyVersion(tt.args.rootId, tt.args.key, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.RootKeyVersionPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), wrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - assert.Equal(uint32(1), got.Version) - } - }) - } -} - -func TestRootKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - rw := db.New(conn) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - tests := []struct { - name string - key *kms.RootKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: func() *kms.RootKeyVersion { k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId); return k }(), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.RootKeyVersion { - k := kms.AllocRootKeyVersion() - id, err := db.NewPublicId(kms.RootKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocRootKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocRootKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestRootKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.RootKeyVersion).RootKeyVersion, k.RootKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - k2, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.RootKeyVersion).RootKeyVersion, k2.RootKeyVersion)) - }) -} - -func TestRootKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultRootKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocRootKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := &kms.RootKeyVersion{ - RootKeyVersion: &store.RootKeyVersion{}, - } - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/session_key.go b/internal/kms/session_key.go deleted file mode 100644 index 21105afe2..000000000 --- a/internal/kms/session_key.go +++ /dev/null @@ -1,79 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultSessionKeyTableName = "kms_session_key" -) - -type SessionKey struct { - *store.SessionKey - tableName string `gorm:"-"` -} - -// NewSessionKey creates a new in memory key. No options -// are currently supported. -func NewSessionKey(rootKeyId string, _ ...Option) (*SessionKey, error) { - const op = "kms.NewSessionKey" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - c := &SessionKey{ - SessionKey: &store.SessionKey{ - RootKeyId: rootKeyId, - }, - } - return c, nil -} - -// AllocSessionKey will allocate a key -func AllocSessionKey() SessionKey { - return SessionKey{ - SessionKey: &store.SessionKey{}, - } -} - -// Clone creates a clone of the key -func (k *SessionKey) Clone() interface{} { - cp := proto.Clone(k.SessionKey) - return &SessionKey{ - SessionKey: cp.(*store.SessionKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *SessionKey) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(SessionKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *SessionKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultSessionKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *SessionKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/session_key_test.go b/internal/kms/session_key_test.go deleted file mode 100644 index b5c5b8e95..000000000 --- a/internal/kms/session_key_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the SessionKey attributes are -// immutable and those tests are covered by TestSessionKey_ImmutableFields - -func TestSessionKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.SessionKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.SessionKey { - k := kms.AllocSessionKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKey(); return &i }(), "1=1") - got, err := kms.NewSessionKey(tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.SessionKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestSessionKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.SessionKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestSessionKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.SessionKey { - k := kms.AllocSessionKey() - id, err := db.NewPublicId(kms.SessionKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocSessionKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocSessionKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestSessionKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestSessionKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.SessionKey).SessionKey, k.SessionKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestSessionKey(t, conn, rk.PrivateId) - k2 := kms.TestSessionKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.SessionKey).SessionKey, k2.SessionKey)) - }) -} - -func TestSessionKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultSessionKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocSessionKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocSessionKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/session_key_version.go b/internal/kms/session_key_version.go deleted file mode 100644 index 0ffd9c8d8..000000000 --- a/internal/kms/session_key_version.go +++ /dev/null @@ -1,118 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultSessionKeyVersionTableName = "kms_session_key_version" -) - -type SessionKeyVersion struct { - *store.SessionKeyVersion - tableName string `gorm:"-"` -} - -// SessionKeyVersion creates a new in memory key version. No options are -// currently supported. -func NewSessionKeyVersion(sessionKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*SessionKeyVersion, error) { - const op = "kms.NewSessionKeyVersion" - if sessionKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing session key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key version id") - } - - k := &SessionKeyVersion{ - SessionKeyVersion: &store.SessionKeyVersion{ - SessionKeyId: sessionKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocSessionKeyVersion allocates a key version -func AllocSessionKeyVersion() SessionKeyVersion { - return SessionKeyVersion{ - SessionKeyVersion: &store.SessionKeyVersion{}, - } -} - -// Clone creates a clone of the key version -func (k *SessionKeyVersion) Clone() interface{} { - cp := proto.Clone(k.SessionKeyVersion) - return &SessionKeyVersion{ - SessionKeyVersion: cp.(*store.SessionKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// version before it's written. -func (k *SessionKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error { - const op = "kms.(SessionKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.SessionKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing session key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *SessionKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultSessionKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *SessionKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the key version's key -func (k *SessionKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(SessionKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.SessionKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.SessionKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the key version's key -func (k *SessionKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(SessionKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.SessionKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.SessionKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/session_key_version_test.go b/internal/kms/session_key_version_test.go deleted file mode 100644 index df75baceb..000000000 --- a/internal/kms/session_key_version_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the essionKeyVersion attributes are -// immutable and those tests are covered by TestSessionKey_ImmutableFields - -func TestSessionKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestSessionKey(t, conn, rk.PrivateId) - - type args struct { - sessionKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.SessionKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-id", - args: args{ - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - sessionKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - sessionKeyId: dk.PrivateId, - key: []byte("test key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - sessionKeyId: dk.PrivateId, - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.SessionKeyVersion { - k := kms.AllocSessionKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("test key") - k.SessionKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKeyVersion(); return &i }(), "1=1") - got, err := kms.NewSessionKeyVersion(tt.args.sessionKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.SessionKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestSessionKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - tk := kms.TestSessionKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocSessionKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.SessionKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestSessionKeyVersion(t, conn, rkvWrapper, tk.PrivateId, []byte("test key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.SessionKeyVersion { - k := kms.AllocSessionKeyVersion() - id, err := db.NewPublicId(kms.SessionKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocSessionKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocSessionKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestSessionKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestSessionKey(t, conn, rk.PrivateId) - kv := kms.TestSessionKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.SessionKeyVersion).SessionKeyVersion, kv.SessionKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestSessionKey(t, conn, rk.PrivateId) - k2 := kms.TestSessionKey(t, conn, rk2.PrivateId) - kv := kms.TestSessionKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - kv2 := kms.TestSessionKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.SessionKeyVersion).SessionKeyVersion, kv2.SessionKeyVersion)) - }) -} - -func TestSessionKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultSessionKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocSessionKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocSessionKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/testing.go b/internal/kms/testing.go index aaf2e4ea2..1cab48eba 100644 --- a/internal/kms/testing.go +++ b/internal/kms/testing.go @@ -2,276 +2,38 @@ package kms import ( "context" + "fmt" "testing" "github.com/hashicorp/boundary/internal/db" wrapping "github.com/hashicorp/go-kms-wrapping/v2" - aead "github.com/hashicorp/go-kms-wrapping/v2/aead" "github.com/stretchr/testify/require" ) -func TestRootKey(t testing.TB, conn *db.DB, scopeId string) *RootKey { - t.Helper() - require := require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocRootKey(); return &i }(), "scope_id = ?", scopeId) - rw := db.New(conn) - k, err := NewRootKey(scopeId) - require.NoError(err) - id, err := newRootKeyId() - require.NoError(err) - k.PrivateId = id - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestRootKeyVersion(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, rootId string) (kv *RootKeyVersion, kvWrapper wrapping.Wrapper) { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyVersionWrapper := db.TestWrapper(t) - key, err := rootKeyVersionWrapper.(*aead.Wrapper).KeyBytes(context.Background()) - require.NoError(err) - k, err := NewRootKeyVersion(rootId, key) - require.NoError(err) - id, err := newRootKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), wrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - _, err = rootKeyVersionWrapper.(*aead.Wrapper).SetConfig(context.Background(), wrapping.WithKeyId(k.GetPrivateId())) - require.NoError(err) - return k, rootKeyVersionWrapper -} - +// TestKms creates a kms for testing. func TestKms(t testing.TB, conn *db.DB, rootWrapper wrapping.Wrapper) *Kms { t.Helper() require := require.New(t) rw := db.New(conn) - kmsRepo, err := NewRepository(rw, rw) - require.NoError(err) - kms, err := NewKms(kmsRepo) + kms, err := New(context.Background(), rw, rw) require.NoError(err) err = kms.AddExternalWrappers(context.Background(), WithRootWrapper(rootWrapper)) require.NoError(err) + _, err = kms.underlying.GetExternalRootWrapper() + require.NoError(err) return kms } -func TestDatabaseKey(t testing.TB, conn *db.DB, rootKeyId string) *DatabaseKey { - t.Helper() - require := require.New(t) - rw := db.New(conn) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocDatabaseKey(); return &i }(), "root_key_id = ?", rootKeyId) - k, err := NewDatabaseKey(rootKeyId) - require.NoError(err) - id, err := newDatabaseKeyId() - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k +// TestKmsDeleteKeyPurpose allows you to delete a KeyPurpose for testing. +func TestKmsDeleteKeyPurpose(t testing.TB, conn *db.DB, purpose KeyPurpose) { + db.TestDeleteWhere(t, conn, func() interface{} { i := dataKey{}; return &i }(), fmt.Sprintf("purpose='%s'", purpose.String())) } -func TestDatabaseKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, databaseKeyId string, key []byte) *DatabaseKeyVersion { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyId, err := rootKeyVersionWrapper.KeyId(context.Background()) - require.NoError(err) - rootKeyVersionId := rootKeyId - require.NotEmpty(rootKeyVersionId) - k, err := NewDatabaseKeyVersion(databaseKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newDatabaseKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k +// TestKmsDeleteAllKeys allows you to delete all the keys for testing. +func TestKmsDeleteAllKeys(t testing.TB, conn *db.DB) { + db.TestDeleteWhere(t, conn, func() interface{} { i := rootKey{}; return &i }(), "1=1") } -func TestOplogKey(t testing.TB, conn *db.DB, rootKeyId string) *OplogKey { - t.Helper() - require := require.New(t) - rw := db.New(conn) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocOplogKey(); return &i }(), "root_key_id = ?", rootKeyId) - k, err := NewOplogKey(rootKeyId) - require.NoError(err) - id, err := newOplogKeyId() - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} +type dataKey struct{} -func TestOplogKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, oplogKeyId string, key []byte) *OplogKeyVersion { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyId, err := rootKeyVersionWrapper.KeyId(context.Background()) - require.NoError(err) - rootKeyVersionId := rootKeyId - require.NotEmpty(rootKeyVersionId) - k, err := NewOplogKeyVersion(oplogKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newOplogKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestTokenKey(t testing.TB, conn *db.DB, rootKeyId string) *TokenKey { - t.Helper() - require := require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocTokenKey(); return &i }(), "root_key_id = ?", rootKeyId) - rw := db.New(conn) - k, err := NewTokenKey(rootKeyId) - require.NoError(err) - id, err := newTokenKeyId() - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestTokenKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, tokenKeyId string, key []byte) *TokenKeyVersion { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyId, err := rootKeyVersionWrapper.KeyId(context.Background()) - require.NoError(err) - rootKeyVersionId := rootKeyId - require.NotEmpty(rootKeyVersionId) - k, err := NewTokenKeyVersion(tokenKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newTokenKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestSessionKey(t testing.TB, conn *db.DB, rootKeyId string) *SessionKey { - t.Helper() - require := require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocSessionKey(); return &i }(), "root_key_id = ?", rootKeyId) - rw := db.New(conn) - k, err := NewSessionKey(rootKeyId) - require.NoError(err) - id, err := newSessionKeyId() - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestSessionKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, sessionKeyId string, key []byte) *SessionKeyVersion { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyId, err := rootKeyVersionWrapper.KeyId(context.Background()) - require.NoError(err) - rootKeyVersionId := rootKeyId - require.NotEmpty(rootKeyVersionId) - k, err := NewSessionKeyVersion(sessionKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newSessionKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestOidcKey(t testing.TB, conn *db.DB, rootKeyId string) *OidcKey { - t.Helper() - require := require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocOidcKey(); return &i }(), "root_key_id = ?", rootKeyId) - rw := db.New(conn) - k, err := NewOidcKey(rootKeyId) - require.NoError(err) - id, err := newOidcKeyId() - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestOidcKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, oidcKeyId string, key []byte) *OidcKeyVersion { - t.Helper() - require := require.New(t) - rw := db.New(conn) - rootKeyId, err := rootKeyVersionWrapper.KeyId(context.Background()) - require.NoError(err) - rootKeyVersionId := rootKeyId - require.NotEmpty(rootKeyVersionId) - k, err := NewOidcKeyVersion(oidcKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newOidcKeyVersionId() - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestAuditKey(t testing.TB, conn *db.DB, rootKeyId string) *AuditKey { - t.Helper() - ctx := context.Background() - require := require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := AllocAuditKey(); return &i }(), "root_key_id = ?", rootKeyId) - rw := db.New(conn) - k, err := NewAuditKey(ctx, rootKeyId) - require.NoError(err) - id, err := newAuditKeyId(ctx) - require.NoError(err) - k.PrivateId = id - k.RootKeyId = rootKeyId - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} - -func TestAuditKeyVersion(t testing.TB, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, auditKeyId string, key []byte) *AuditKeyVersion { - t.Helper() - ctx := context.Background() - require := require.New(t) - rw := db.New(conn) - rootKeyVersionId, err := rootKeyVersionWrapper.KeyId(ctx) - require.NoError(err) - require.NotEmpty(rootKeyVersionId) - k, err := NewAuditKeyVersion(ctx, auditKeyId, key, rootKeyVersionId) - require.NoError(err) - id, err := newAuditKeyVersionId(ctx) - require.NoError(err) - k.PrivateId = id - err = k.Encrypt(context.Background(), rootKeyVersionWrapper) - require.NoError(err) - err = rw.Create(context.Background(), k) - require.NoError(err) - return k -} +func (*dataKey) TableName() string { return "kms_data_key" } diff --git a/internal/kms/testing_test.go b/internal/kms/testing_test.go deleted file mode 100644 index 30ef305a2..000000000 --- a/internal/kms/testing_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package kms_test - -import ( - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_TestRootKey(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) -} - -func Test_TestRootKeyVersion(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k, _ := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) -} - -func Test_TestDatabaseKey(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) - - dk := kms.TestDatabaseKey(t, conn, k.PrivateId) - require.NotNil(dk) - assert.NotEmpty(dk.PrivateId) -} - -func Test_TestDatabaseKeyVersion(t *testing.T) { - require := require.New(t) - conn, _ := db.TestSetup(t, "postgres") - kmsWrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, kmsWrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rootKeyVersionWrapper := kms.TestRootKeyVersion(t, conn, kmsWrapper, rk.PrivateId) - dk := kms.TestDatabaseKey(t, conn, rk.PrivateId) - dv := kms.TestDatabaseKeyVersion(t, conn, rootKeyVersionWrapper, dk.PrivateId, []byte("test dek key")) - require.NotNil(dv) - require.NotEmpty(dv.PrivateId) -} - -func Test_TestOplogKey(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) - - opk := kms.TestOplogKey(t, conn, k.PrivateId) - require.NotNil(opk) - assert.NotEmpty(opk.PrivateId) -} - -func Test_TestOplogKeyVersion(t *testing.T) { - require := require.New(t) - conn, _ := db.TestSetup(t, "postgres") - kmsWrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, kmsWrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rootKeyVersionWrapper := kms.TestRootKeyVersion(t, conn, kmsWrapper, rk.PrivateId) - opk := kms.TestOplogKey(t, conn, rk.PrivateId) - opv := kms.TestOplogKeyVersion(t, conn, rootKeyVersionWrapper, opk.PrivateId, []byte("test dek key")) - require.NotNil(opv) - require.NotEmpty(opv.PrivateId) -} - -func Test_TestTokenKey(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) - - tk := kms.TestTokenKey(t, conn, k.PrivateId) - require.NotNil(tk) - assert.NotEmpty(tk.PrivateId) -} - -func Test_TestTokenKeyVersion(t *testing.T) { - require := require.New(t) - conn, _ := db.TestSetup(t, "postgres") - kmsWrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, kmsWrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rootKeyVersionWrapper := kms.TestRootKeyVersion(t, conn, kmsWrapper, rk.PrivateId) - tk := kms.TestTokenKey(t, conn, rk.PrivateId) - tv := kms.TestTokenKeyVersion(t, conn, rootKeyVersionWrapper, tk.PrivateId, []byte("test dek key")) - require.NotNil(tv) - require.NotEmpty(tv.PrivateId) -} - -func Test_TestSessionKey(t *testing.T) { - assert, require := assert.New(t), require.New(t) - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - k := kms.TestRootKey(t, conn, org.PublicId) - require.NotNil(k) - assert.NotEmpty(k.PrivateId) - - sk := kms.TestSessionKey(t, conn, k.PrivateId) - require.NotNil(sk) - assert.NotEmpty(sk.PrivateId) -} - -func Test_TestSessionKeyVersion(t *testing.T) { - require := require.New(t) - conn, _ := db.TestSetup(t, "postgres") - kmsWrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, kmsWrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rootKeyVersionWrapper := kms.TestRootKeyVersion(t, conn, kmsWrapper, rk.PrivateId) - sk := kms.TestSessionKey(t, conn, rk.PrivateId) - sv := kms.TestSessionKeyVersion(t, conn, rootKeyVersionWrapper, sk.PrivateId, []byte("test dek key")) - require.NotNil(sv) - require.NotEmpty(sv.PrivateId) -} diff --git a/internal/kms/token_key.go b/internal/kms/token_key.go deleted file mode 100644 index 63e61d63a..000000000 --- a/internal/kms/token_key.go +++ /dev/null @@ -1,79 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultTokenKeyTableName = "kms_token_key" -) - -type TokenKey struct { - *store.TokenKey - tableName string `gorm:"-"` -} - -// NewTokenKey creates a new in memory key. No options -// are currently supported. -func NewTokenKey(rootKeyId string, _ ...Option) (*TokenKey, error) { - const op = "kms.NewTokenKey" - if rootKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key id") - } - c := &TokenKey{ - TokenKey: &store.TokenKey{ - RootKeyId: rootKeyId, - }, - } - return c, nil -} - -// AllocTokenKey will allocate a key -func AllocTokenKey() TokenKey { - return TokenKey{ - TokenKey: &store.TokenKey{}, - } -} - -// Clone creates a clone of the key -func (k *TokenKey) Clone() interface{} { - cp := proto.Clone(k.TokenKey) - return &TokenKey{ - TokenKey: cp.(*store.TokenKey), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// before it's written. -func (k *TokenKey) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(TokenKey).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.RootKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *TokenKey) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultTokenKeyTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *TokenKey) SetTableName(n string) { - k.tableName = n -} diff --git a/internal/kms/token_key_test.go b/internal/kms/token_key_test.go deleted file mode 100644 index 9f1b8a4fa..000000000 --- a/internal/kms/token_key_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the TokenKey attributes are -// immutable and those tests are covered by TestTokenKey_ImmutableFields - -func TestTokenKey_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - - type args struct { - rootKeyId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.TokenKey - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-rootKeyId", - args: args{}, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - rootKeyId: rk.PrivateId, - }, - want: func() *kms.TokenKey { - k := kms.AllocTokenKey() - k.RootKeyId = rk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKey(); return &i }(), "1=1") - got, err := kms.NewTokenKey(tt.args.rootKeyId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.TokenKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestTokenKey_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKey(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.TokenKey - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestTokenKey(t, conn, rk.PrivateId), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.TokenKey { - k := kms.AllocTokenKey() - id, err := db.NewPublicId(kms.TokenKeyPrefix) - require.NoError(t, err) - k.PrivateId = id - k.RootKeyId = rk.PrivateId - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocTokenKey() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocTokenKey() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestTokenKey_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - k := kms.TestTokenKey(t, conn, rk.PrivateId) - cp := k.Clone() - assert.True(proto.Equal(cp.(*kms.TokenKey).TokenKey, k.TokenKey)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - k := kms.TestTokenKey(t, conn, rk.PrivateId) - k2 := kms.TestTokenKey(t, conn, rk2.PrivateId) - - cp := k.Clone() - assert.True(!proto.Equal(cp.(*kms.TokenKey).TokenKey, k2.TokenKey)) - }) -} - -func TestTokenKey_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultTokenKeyTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocTokenKey() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocTokenKey() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/kms/token_key_version.go b/internal/kms/token_key_version.go deleted file mode 100644 index efb406e57..000000000 --- a/internal/kms/token_key_version.go +++ /dev/null @@ -1,118 +0,0 @@ -package kms - -import ( - "context" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms/store" - wrapping "github.com/hashicorp/go-kms-wrapping/v2" - "github.com/hashicorp/go-kms-wrapping/v2/extras/structwrapping" - "google.golang.org/protobuf/proto" -) - -const ( - DefaultTokenKeyVersionTableName = "kms_token_key_version" -) - -type TokenKeyVersion struct { - *store.TokenKeyVersion - tableName string `gorm:"-"` -} - -// TokenKeyVersion creates a new in memory key version. No options are -// currently supported. -func NewTokenKeyVersion(tokenKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*TokenKeyVersion, error) { - const op = "kms.NewTokenKeyVersion" - if tokenKeyId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing token key id") - } - if len(key) == 0 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing key") - } - if rootKeyVersionId == "" { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing root key version id") - } - - k := &TokenKeyVersion{ - TokenKeyVersion: &store.TokenKeyVersion{ - TokenKeyId: tokenKeyId, - RootKeyVersionId: rootKeyVersionId, - Key: key, - }, - } - return k, nil -} - -// AllocTokenKeyVersion allocates a key version -func AllocTokenKeyVersion() TokenKeyVersion { - return TokenKeyVersion{ - TokenKeyVersion: &store.TokenKeyVersion{}, - } -} - -// Clone creates a clone of the key version -func (k *TokenKeyVersion) Clone() interface{} { - cp := proto.Clone(k.TokenKeyVersion) - return &TokenKeyVersion{ - TokenKeyVersion: cp.(*store.TokenKeyVersion), - } -} - -// VetForWrite implements db.VetForWrite() interface and validates the key -// version before it's written. -func (k *TokenKeyVersion) VetForWrite(ctx context.Context, _r db.Reader, opType db.OpType, _ ...db.Option) error { - const op = "kms.(TokenKeyVersion).VetForWrite" - if k.PrivateId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing private id") - } - if opType == db.CreateOp { - if k.CtKey == nil { - return errors.New(ctx, errors.InvalidParameter, op, "missing key") - } - if k.TokenKeyId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing token key id") - } - if k.RootKeyVersionId == "" { - return errors.New(ctx, errors.InvalidParameter, op, "missing root key version id") - } - } - return nil -} - -// TableName returns the tablename to override the default gorm table name -func (k *TokenKeyVersion) TableName() string { - if k.tableName != "" { - return k.tableName - } - return DefaultTokenKeyVersionTableName -} - -// SetTableName sets the tablename and satisfies the ReplayableMessage -// interface. If the caller attempts to set the name to "" the name will be -// reset to the default name. -func (k *TokenKeyVersion) SetTableName(n string) { - k.tableName = n -} - -// Encrypt will encrypt the key version's key -func (k *TokenKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(TokenKeyVersion).Encrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.TokenKeyVersion directly - if err := structwrapping.WrapStruct(ctx, cipher, k.TokenKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt)) - } - return nil -} - -// Decrypt will decrypt the key version's key -func (k *TokenKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error { - const op = "kms.(TokenKeyVersion).Decrypt" - // structwrapping doesn't support embedding, so we'll pass in the - // store.TokenKeyVersion directly - if err := structwrapping.UnwrapStruct(ctx, cipher, k.TokenKeyVersion, nil); err != nil { - return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt)) - } - return nil -} diff --git a/internal/kms/token_key_version_test.go b/internal/kms/token_key_version_test.go deleted file mode 100644 index 6e02ed71d..000000000 --- a/internal/kms/token_key_version_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package kms_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/iam" - "github.com/hashicorp/boundary/internal/kms" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -// NOTE: there are no update tests since all the TokenKeyVersion attributes are -// immutable and those tests are covered by TestTokenKey_ImmutableFields - -func TestTokenKeyVersion_Create(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rkv, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - dk := kms.TestTokenKey(t, conn, rk.PrivateId) - - type args struct { - tokenKeyId string - key []byte - rootKeyVersionId string - opt []kms.Option - } - tests := []struct { - name string - args args - want *kms.TokenKeyVersion - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool - }{ - { - name: "empty-id", - args: args{ - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-key", - args: args{ - tokenKeyId: dk.PrivateId, - rootKeyVersionId: rkv.PrivateId, - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "empty-root-key-version-id", - args: args{ - tokenKeyId: dk.PrivateId, - key: []byte("test key"), - }, - wantErr: true, - wantIsErr: errors.InvalidParameter, - }, - { - name: "valid", - args: args{ - tokenKeyId: dk.PrivateId, - key: []byte("test key"), - rootKeyVersionId: rkv.PrivateId, - }, - want: func() *kms.TokenKeyVersion { - k := kms.AllocTokenKeyVersion() - k.RootKeyVersionId = rkv.PrivateId - k.Key = []byte("test key") - k.TokenKeyId = dk.PrivateId - return &k - }(), - create: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKeyVersion(); return &i }(), "1=1") - got, err := kms.NewTokenKeyVersion(tt.args.tokenKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...) - if tt.wantErr { - require.Error(err) - assert.True(errors.Match(errors.T(tt.wantIsErr), err)) - return - } - require.NoError(err) - assert.Equal(tt.want, got) - if tt.create { - id, err := db.NewPublicId(kms.TokenKeyPrefix) - require.NoError(err) - got.PrivateId = id - err = got.Encrypt(context.Background(), rkvWrapper) - require.NoError(err) - err = db.New(conn).Create(context.Background(), got) - if tt.wantCreateErr { - assert.Error(err) - return - } else { - assert.NoError(err) - } - } - }) - } -} - -func TestTokenKeyVersion_Delete(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - tk := kms.TestTokenKey(t, conn, rk.PrivateId) - - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocTokenKeyVersion(); return &i }(), "1=1") - - tests := []struct { - name string - key *kms.TokenKeyVersion - wantRowsDeleted int - wantErr bool - wantErrMsg string - }{ - { - name: "valid", - key: kms.TestTokenKeyVersion(t, conn, rkvWrapper, tk.PrivateId, []byte("test key")), - wantErr: false, - wantRowsDeleted: 1, - }, - { - name: "bad-id", - key: func() *kms.TokenKeyVersion { - k := kms.AllocTokenKeyVersion() - id, err := db.NewPublicId(kms.TokenKeyVersionPrefix) - require.NoError(t, err) - k.PrivateId = id - return &k - }(), - wantErr: false, - wantRowsDeleted: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - deleteKey := kms.AllocTokenKeyVersion() - deleteKey.PrivateId = tt.key.PrivateId - deletedRows, err := rw.Delete(context.Background(), &deleteKey) - if tt.wantErr { - require.Error(err) - return - } - require.NoError(err) - if tt.wantRowsDeleted == 0 { - assert.Equal(tt.wantRowsDeleted, deletedRows) - return - } - assert.Equal(tt.wantRowsDeleted, deletedRows) - foundKey := kms.AllocTokenKeyVersion() - foundKey.PrivateId = tt.key.PrivateId - err = rw.LookupById(context.Background(), &foundKey) - require.Error(err) - assert.True(errors.IsNotFoundError(err)) - }) - } -} - -func TestTokenKeyVersion_Clone(t *testing.T) { - t.Parallel() - conn, _ := db.TestSetup(t, "postgres") - wrapper := db.TestWrapper(t) - t.Run("valid", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - - rk := kms.TestRootKey(t, conn, org.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - - k := kms.TestTokenKey(t, conn, rk.PrivateId) - kv := kms.TestTokenKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - cp := kv.Clone() - assert.True(proto.Equal(cp.(*kms.TokenKeyVersion).TokenKeyVersion, kv.TokenKeyVersion)) - }) - t.Run("not-equal", func(t *testing.T) { - assert := assert.New(t) - org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - org2, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) - db.TestDeleteWhere(t, conn, func() interface{} { i := kms.AllocRootKey(); return &i }(), "1=1") - rk := kms.TestRootKey(t, conn, org.PublicId) - rk2 := kms.TestRootKey(t, conn, org2.PublicId) - _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) - _, rkvWrapper2 := kms.TestRootKeyVersion(t, conn, wrapper, rk2.PrivateId) - - k := kms.TestTokenKey(t, conn, rk.PrivateId) - k2 := kms.TestTokenKey(t, conn, rk2.PrivateId) - kv := kms.TestTokenKeyVersion(t, conn, rkvWrapper, k.PrivateId, []byte("test key")) - kv2 := kms.TestTokenKeyVersion(t, conn, rkvWrapper2, k2.PrivateId, []byte("test key 2")) - - cp := kv.Clone() - assert.True(!proto.Equal(cp.(*kms.TokenKeyVersion).TokenKeyVersion, kv2.TokenKeyVersion)) - }) -} - -func TestTokenKeyVersion_SetTableName(t *testing.T) { - t.Parallel() - defaultTableName := kms.DefaultTokenKeyVersionTableName - tests := []struct { - name string - setNameTo string - want string - }{ - { - name: "new-name", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := kms.AllocTokenKeyVersion() - require.Equal(defaultTableName, def.TableName()) - s := kms.AllocTokenKeyVersion() - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/servers/repository_test.go b/internal/servers/repository_test.go index 6e82aba46..e348f484b 100644 --- a/internal/servers/repository_test.go +++ b/internal/servers/repository_test.go @@ -31,6 +31,10 @@ func TestRecoveryNonces(t *testing.T) { }) defer tc.Shutdown() + externalWrappers := tc.Kms().GetExternalWrappers(context.Background()) + externalRecovery := externalWrappers.Recovery() + require.Equal(externalRecovery, wrapper) + client := tc.Client() repo := tc.ServersRepo() diff --git a/internal/session/repository_test.go b/internal/session/repository_test.go index 5326a1b3a..4a2ed7878 100644 --- a/internal/session/repository_test.go +++ b/internal/session/repository_test.go @@ -13,14 +13,18 @@ func TestNewRepository(t *testing.T) { t.Parallel() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) + wrapper := db.TestWrapper(t) + testKms := kms.TestKms(t, conn, wrapper) + type args struct { r db.Reader w db.Writer + k *kms.Kms } tests := []struct { name string args args - want *kms.Repository + want *Repository wantErr bool wantErrString string }{ @@ -29,9 +33,10 @@ func TestNewRepository(t *testing.T) { args: args{ r: rw, w: rw, + k: testKms, }, - want: func() *kms.Repository { - ret, err := kms.NewRepository(rw, rw) + want: func() *Repository { + ret, err := NewRepository(rw, rw, testKms) require.NoError(t, err) return ret }(), @@ -45,7 +50,7 @@ func TestNewRepository(t *testing.T) { }, want: nil, wantErr: true, - wantErrString: "kms.NewRepository: nil writer: parameter violation: error #100", + wantErrString: "session.NewRepository: nil writer: parameter violation: error #100", }, { name: "nil-reader", @@ -55,13 +60,13 @@ func TestNewRepository(t *testing.T) { }, want: nil, wantErr: true, - wantErrString: "kms.NewRepository: nil reader: parameter violation: error #100", + wantErrString: "session.NewRepository: nil reader: parameter violation: error #100", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - got, err := kms.NewRepository(tt.args.r, tt.args.w) + got, err := NewRepository(tt.args.r, tt.args.w, tt.args.k) if tt.wantErr { require.Error(err) assert.Equal(tt.wantErrString, err.Error())