diff --git a/.sonarcloud.properties b/.sonarcloud.properties index 9f0c853a4..9e034312c 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -1,2 +1,2 @@ sonar.exclusions=**/*.gen.go, **/*.sql.go -sonar.cpd.exclusions=**/*_test.go +sonar.cpd.exclusions=**/*_test.go, **/sqlite/*.go, **/postgres/*.go diff --git a/Makefile b/Makefile index 9ba288e90..86d52fc93 100644 --- a/Makefile +++ b/Makefile @@ -74,11 +74,11 @@ go_path := PATH="$(go_bin_dir):$(PATH)" oapi_codegen_version = 1.12.4 oapi_codegen_dir = $(build_dir)/protoc/$(protoc_version):q -server_sqlc_config_file = $(DIR)/pkg/server/datastore/sqlc.yaml +server_sqlc_config_file = $(DIR)/pkg/server/db/sqlc.yaml sqlc_dir = $(build_dir)/sqlc/$(sqlc_version) sqlc_bin = $(sqlc_dir)/sqlc -sqlc_version = 1.17.0 +sqlc_version = 1.18.0 ifeq ($(os1),windows) sqlc_url = https://github.com/kyleconroy/sqlc/releases/download/v${sqlc_version}/sqlc_${sqlc_version}_windows_amd64.zip else ifeq ($(os1),darwin) @@ -206,9 +206,9 @@ help: .PHONY: generate-sqlc-server generete-spec # Run sqlc to generate sql code -generate-sqlc-server: install-sqlc run-sqlc-server +generate-sqlc-code: install-sqlc run-generate-sqlc -run-sqlc-server: +run-generate-sqlc: $(sqlc_bin) generate --file $(server_sqlc_config_file) # Run oapi-codegen to generate api code diff --git a/cmd/harvester/cli/run_test.go b/cmd/harvester/cli/run_test.go index cce4161c5..49cac0f06 100644 --- a/cmd/harvester/cli/run_test.go +++ b/cmd/harvester/cli/run_test.go @@ -1,10 +1,11 @@ package cli import ( - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" ) func TestLoadConfig(t *testing.T) { diff --git a/cmd/server/cli/config.go b/cmd/server/cli/config.go index 8416e5a8a..be74eab59 100644 --- a/cmd/server/cli/config.go +++ b/cmd/server/cli/config.go @@ -34,7 +34,6 @@ type serverConfig struct { ListenPort int `hcl:"listen_port,optional"` SocketPath string `hcl:"socket_path,optional"` LogLevel string `hcl:"log_level,optional"` - DBConnString string `hcl:"db_conn_string"` } // providersBlock holds the Providers HCL block body. @@ -76,8 +75,6 @@ func NewServerConfig(c *Config) (*server.Config, error) { sc.LocalAddress = socketAddr - sc.DBConnString = c.Server.DBConnString - logLevel, err := logrus.ParseLevel(c.Server.LogLevel) if err != nil { return nil, fmt.Errorf("failed to parse log level: %v", err) @@ -86,12 +83,9 @@ func NewServerConfig(c *Config) (*server.Config, error) { logger.SetLevel(logLevel) sc.Logger = logger.WithField(telemetry.SubsystemName, telemetry.Server) - // TODO: eventually providers section will be required - if c.Providers != nil { - sc.ProvidersConfig, err = catalog.ProvidersConfigsFromHCLBody(c.Providers.Body) - if err != nil { - return nil, fmt.Errorf("failed to parse providers configuration: %w", err) - } + sc.ProvidersConfig, err = catalog.ProvidersConfigsFromHCLBody(c.Providers.Body) + if err != nil { + return nil, fmt.Errorf("failed to parse providers configuration: %w", err) } return sc, nil diff --git a/cmd/server/cli/config_test.go b/cmd/server/cli/config_test.go index d2f8f191e..53962af7c 100644 --- a/cmd/server/cli/config_test.go +++ b/cmd/server/cli/config_test.go @@ -4,13 +4,11 @@ import ( "bytes" "errors" "io" - "strings" "testing" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -19,15 +17,20 @@ var hclConfigWithProviders = `server { listen_address = "127.0.0.1" listen_port = "2222" socket_path = "/tmp/api.sock" - db_conn_string = "test_conn_string" log_level = "DEBUG" } providers { - x509ca "disk" { + Datastore "sqlite3" { + connection_string = "./datastore.sqlite3" + } + + X509CA "disk" { key_file_path = "./root_ca.key" cert_file_path = "./root_ca.crt" } + + KeyManager "memory" {} } ` @@ -37,26 +40,6 @@ func (fakeReader) Read(p []byte) (n int, err error) { return 0, errors.New("error from fake reader") } -func TestNewServerConfig(t *testing.T) { - config := Config{Server: &serverConfig{ - ListenAddress: "localhost", - ListenPort: 8000, - SocketPath: "/example", - LogLevel: "INFO", - DBConnString: "postgresql://postgres:postgres@localhost:5432/galadriel", - }} - - sc, err := NewServerConfig(&config) - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "127.0.0.1", sc.TCPAddress.IP.String()) - assert.Equal(t, config.Server.ListenPort, sc.TCPAddress.Port) - assert.Equal(t, config.Server.SocketPath, sc.LocalAddress.String()) - assert.Equal(t, strings.ToLower(config.Server.LogLevel), logrus.GetLevel().String()) -} - func TestNew(t *testing.T) { tests := []struct { name string @@ -73,22 +56,18 @@ func TestNew(t *testing.T) { ListenPort: 2222, SocketPath: "/tmp/api.sock", LogLevel: "DEBUG", - DBConnString: "test_conn_string", }, }, }, { - name: "defaults", - config: bytes.NewBuffer([]byte(`server { -db_conn_string = "test_conn_string" -}`)), + name: "defaults", + config: bytes.NewBuffer([]byte(`server {}`)), expected: &Config{ Server: &serverConfig{ ListenAddress: defaultAddress, ListenPort: defaultPort, SocketPath: defaultSocketPath, LogLevel: defaultLogLevel, - DBConnString: "test_conn_string", }, }, }, diff --git a/cmd/server/util/client.go b/cmd/server/util/client.go index 3586df62f..c904fce3f 100644 --- a/cmd/server/util/client.go +++ b/cmd/server/util/client.go @@ -23,7 +23,7 @@ const ( ) var ( - createTrustDomainURL = fmt.Sprintf(localURL, "createTrustDomain") + createTrustDomainURL = fmt.Sprintf(localURL, "trust-domain") listTrustDomainsURL = fmt.Sprintf(localURL, "listTrustDomains") createRelationshipURL = fmt.Sprintf(localURL, "createRelationship") listRelationshipsURL = fmt.Sprintf(localURL, "listRelationships") @@ -63,7 +63,12 @@ func (c serverClient) CreateTrustDomain(m *entity.TrustDomain) error { return err } - r, err := c.client.Post(createTrustDomainURL, contentType, bytes.NewReader(trustDomainBytes)) + req, err := http.NewRequest(http.MethodPut, createTrustDomainURL, bytes.NewReader(trustDomainBytes)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + r, err := c.client.Do(req) if err != nil { return err } diff --git a/conf/server/server.conf b/conf/server/server.conf index e6e3b213c..e4e939d88 100644 --- a/conf/server/server.conf +++ b/conf/server/server.conf @@ -12,12 +12,20 @@ server { # log_level: Sets the logging level . Default: INFO. log_level = "DEBUG" - - # db_conn_string: postgres database connection string. - db_conn_string = "postgresql://postgres:postgres@localhost:5432/galadriel" } providers { + # datastore: + Datastore "sqlite3" { + # connection_string: database connection string. + connection_string = "./datastore.sqlite3" + } + + #Datastore "postgres" { + # # connection_string: database connection string. + # connection_string = "postgresql://postgres:postgres@localhost:5432/galadriel" + #} + # X509CA "disk": Uses a ROOT CA loaded from disk to issue X509 certificates. X509CA "disk" { # Path to the root CA private key file. PEM format. diff --git a/go.mod b/go.mod index eab4c6f34..e17e18771 100644 --- a/go.mod +++ b/go.mod @@ -8,13 +8,12 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-migrate/migrate/v4 v4.15.2 github.com/google/uuid v1.3.0 - github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl/v2 v2.16.2 - github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgtype v1.14.0 github.com/jackc/pgx/v5 v5.3.1 github.com/jmhodges/clock v1.2.0 github.com/labstack/echo/v4 v4.10.2 + github.com/mattn/go-sqlite3 v1.14.16 github.com/ory/dockertest/v3 v3.10.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 @@ -62,6 +61,7 @@ require ( github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/lib/pq v1.10.2 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -76,6 +76,7 @@ require ( github.com/opencontainers/runc v1.1.5 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect @@ -95,4 +96,13 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // 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 ) diff --git a/go.sum b/go.sum index 0a338e346..f0013de7b 100644 --- a/go.sum +++ b/go.sum @@ -393,6 +393,7 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNE 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 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -673,7 +674,6 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1a0= github.com/hashicorp/hcl/v2 v2.16.2/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng= @@ -715,8 +715,6 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8 github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530 h1:dUJ578zuPEsXjtzOfEF0q9zDAfljJ9oFnTHcQaNkccw= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= -github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= -github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/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= @@ -801,6 +799,7 @@ github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3t 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= @@ -882,6 +881,8 @@ github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL github.com/mattn/go-sqlite3 v1.9.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.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= @@ -1053,6 +1054,7 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 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.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1956,29 +1958,41 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/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 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= 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 h1:sYNjGr4zK6cDH74USl8wVJRrvDX6UOLpG0j4lFvR0W0= 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 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc= 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= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pkg/common/http/http.go b/pkg/common/http/http.go index 7c4e35f06..50169d3ad 100644 --- a/pkg/common/http/http.go +++ b/pkg/common/http/http.go @@ -3,27 +3,26 @@ package http import ( "errors" "fmt" - "net/http" "github.com/labstack/echo/v4" ) // WriteResponse parses a struct into a json and writes in the response -func WriteResponse(ctx echo.Context, body interface{}) error { +func WriteResponse(ctx echo.Context, code int, body interface{}) error { if body == nil { return errors.New("body is required") } - if err := ctx.JSON(http.StatusOK, body); err != nil { + if err := ctx.JSON(code, body); err != nil { return fmt.Errorf("failed to write response body: %v", err) } return nil } -// BodylessResponse wraps error echo body-less responses. -func BodylessResponse(ctx echo.Context) error { - if err := ctx.NoContent(http.StatusOK); err != nil { +// BodilessResponse wraps error echo body-less responses. +func BodilessResponse(ctx echo.Context, code int) error { + if err := ctx.NoContent(code); err != nil { return fmt.Errorf("failed to respond without body: %v", err) } diff --git a/pkg/common/http/http_test.go b/pkg/common/http/http_test.go index 75fc59d73..cd7ef396f 100644 --- a/pkg/common/http/http_test.go +++ b/pkg/common/http/http_test.go @@ -34,21 +34,22 @@ func Setup() *HTTPSetup { func TestWriteResponse(t *testing.T) { t.Run("Error when nil body is passed", func(t *testing.T) { setup := Setup() - err := WriteResponse(setup.EchoContext, nil) + err := WriteResponse(setup.EchoContext, http.StatusOK, nil) assert.EqualError(t, err, "body is required") assert.Empty(t, setup.Recorder.Body) }) t.Run("No error when an empty body is passed", func(t *testing.T) { setup := Setup() - err := WriteResponse(setup.EchoContext, TestBody{}) + err := WriteResponse(setup.EchoContext, http.StatusOK, TestBody{}) assert.NoError(t, err) + assert.Equal(t, http.StatusOK, setup.Recorder.Code) }) t.Run("Ensuring that the body is being full filled with the entity", func(t *testing.T) { expectedResponseBody := TestBody{Name: "teste"} setup := Setup() - err := WriteResponse(setup.EchoContext, expectedResponseBody) + err := WriteResponse(setup.EchoContext, http.StatusOK, expectedResponseBody) assert.NoError(t, err) responseBody := TestBody{} @@ -60,10 +61,10 @@ func TestWriteResponse(t *testing.T) { }) } -func TestBodylessResponse(t *testing.T) { +func TestBodilessResponse(t *testing.T) { t.Run("Ensuring that the body is empty", func(t *testing.T) { setup := Setup() - err := BodylessResponse(setup.EchoContext) + err := BodilessResponse(setup.EchoContext, http.StatusOK) assert.NoError(t, err) assert.NoError(t, err) @@ -75,7 +76,7 @@ func TestBodylessResponse(t *testing.T) { func TestFromBody(t *testing.T) { t.Run("Ensuring that the body is empty", func(t *testing.T) { setup := Setup() - err := BodylessResponse(setup.EchoContext) + err := BodilessResponse(setup.EchoContext, http.StatusOK) assert.NoError(t, err) assert.NoError(t, err) diff --git a/pkg/server/api/admin/admin.gen.go b/pkg/server/api/admin/admin.gen.go index c748c6d57..36e960eab 100644 --- a/pkg/server/api/admin/admin.gen.go +++ b/pkg/server/api/admin/admin.gen.go @@ -22,13 +22,6 @@ import ( "github.com/labstack/echo/v4" ) -// Defines values for GetRelationshipsParamsStatus. -const ( - Approved GetRelationshipsParamsStatus = "approved" - Denied GetRelationshipsParamsStatus = "denied" - Pending GetRelationshipsParamsStatus = "pending" -) - // JoinTokenResult defines model for JoinTokenResult. type JoinTokenResult struct { Token externalRef0.JoinToken `json:"token"` @@ -52,23 +45,20 @@ type Default = externalRef0.ApiError // GetRelationshipsParams defines parameters for GetRelationships. type GetRelationshipsParams struct { // Status relationship status from a Trust Domain perspective, - Status *GetRelationshipsParamsStatus `form:"status,omitempty" json:"status,omitempty"` + Status *externalRef0.ConsentStatus `form:"status,omitempty" json:"status,omitempty"` // TrustDomainName TrustDomain TrustDomainName *externalRef0.TrustDomainName `form:"trustDomainName,omitempty" json:"trustDomainName,omitempty"` } -// GetRelationshipsParamsStatus defines parameters for GetRelationships. -type GetRelationshipsParamsStatus string - -// PutRelationshipsJSONRequestBody defines body for PutRelationships for application/json ContentType. -type PutRelationshipsJSONRequestBody = RelationshipRequest +// PutRelationshipJSONRequestBody defines body for PutRelationship for application/json ContentType. +type PutRelationshipJSONRequestBody = RelationshipRequest // PutTrustDomainJSONRequestBody defines body for PutTrustDomain for application/json ContentType. type PutTrustDomainJSONRequestBody = TrustDomainPut -// PutTrustDomainTrustDomainNameJSONRequestBody defines body for PutTrustDomainTrustDomainName for application/json ContentType. -type PutTrustDomainTrustDomainNameJSONRequestBody = externalRef0.TrustDomain +// PutTrustDomainByNameJSONRequestBody defines body for PutTrustDomainByName for application/json ContentType. +type PutTrustDomainByNameJSONRequestBody = externalRef0.TrustDomain // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -146,26 +136,26 @@ type ClientInterface interface { // GetRelationships request GetRelationships(ctx context.Context, params *GetRelationshipsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - // PutRelationships request with any body - PutRelationshipsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + // PutRelationship request with any body + PutRelationshipWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - PutRelationships(ctx context.Context, body PutRelationshipsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + PutRelationship(ctx context.Context, body PutRelationshipJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // GetRelationshipsRelationshipID request - GetRelationshipsRelationshipID(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetRelationshipByID request + GetRelationshipByID(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) // PutTrustDomain request with any body PutTrustDomainWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) PutTrustDomain(ctx context.Context, body PutTrustDomainJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // GetTrustDomainTrustDomainName request - GetTrustDomainTrustDomainName(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetTrustDomainByName request + GetTrustDomainByName(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*http.Response, error) - // PutTrustDomainTrustDomainName request with any body - PutTrustDomainTrustDomainNameWithBody(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + // PutTrustDomainByName request with any body + PutTrustDomainByNameWithBody(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - PutTrustDomainTrustDomainName(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainTrustDomainNameJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + PutTrustDomainByName(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainByNameJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) // GetJoinToken request GetJoinToken(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -183,8 +173,8 @@ func (c *Client) GetRelationships(ctx context.Context, params *GetRelationshipsP return c.Client.Do(req) } -func (c *Client) PutRelationshipsWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPutRelationshipsRequestWithBody(c.Server, contentType, body) +func (c *Client) PutRelationshipWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPutRelationshipRequestWithBody(c.Server, contentType, body) if err != nil { return nil, err } @@ -195,8 +185,8 @@ func (c *Client) PutRelationshipsWithBody(ctx context.Context, contentType strin return c.Client.Do(req) } -func (c *Client) PutRelationships(ctx context.Context, body PutRelationshipsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPutRelationshipsRequest(c.Server, body) +func (c *Client) PutRelationship(ctx context.Context, body PutRelationshipJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPutRelationshipRequest(c.Server, body) if err != nil { return nil, err } @@ -207,8 +197,8 @@ func (c *Client) PutRelationships(ctx context.Context, body PutRelationshipsJSON return c.Client.Do(req) } -func (c *Client) GetRelationshipsRelationshipID(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetRelationshipsRelationshipIDRequest(c.Server, relationshipID) +func (c *Client) GetRelationshipByID(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetRelationshipByIDRequest(c.Server, relationshipID) if err != nil { return nil, err } @@ -243,8 +233,8 @@ func (c *Client) PutTrustDomain(ctx context.Context, body PutTrustDomainJSONRequ return c.Client.Do(req) } -func (c *Client) GetTrustDomainTrustDomainName(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetTrustDomainTrustDomainNameRequest(c.Server, trustDomainName) +func (c *Client) GetTrustDomainByName(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetTrustDomainByNameRequest(c.Server, trustDomainName) if err != nil { return nil, err } @@ -255,8 +245,8 @@ func (c *Client) GetTrustDomainTrustDomainName(ctx context.Context, trustDomainN return c.Client.Do(req) } -func (c *Client) PutTrustDomainTrustDomainNameWithBody(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPutTrustDomainTrustDomainNameRequestWithBody(c.Server, trustDomainName, contentType, body) +func (c *Client) PutTrustDomainByNameWithBody(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPutTrustDomainByNameRequestWithBody(c.Server, trustDomainName, contentType, body) if err != nil { return nil, err } @@ -267,8 +257,8 @@ func (c *Client) PutTrustDomainTrustDomainNameWithBody(ctx context.Context, trus return c.Client.Do(req) } -func (c *Client) PutTrustDomainTrustDomainName(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainTrustDomainNameJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewPutTrustDomainTrustDomainNameRequest(c.Server, trustDomainName, body) +func (c *Client) PutTrustDomainByName(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainByNameJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPutTrustDomainByNameRequest(c.Server, trustDomainName, body) if err != nil { return nil, err } @@ -354,19 +344,19 @@ func NewGetRelationshipsRequest(server string, params *GetRelationshipsParams) ( return req, nil } -// NewPutRelationshipsRequest calls the generic PutRelationships builder with application/json body -func NewPutRelationshipsRequest(server string, body PutRelationshipsJSONRequestBody) (*http.Request, error) { +// NewPutRelationshipRequest calls the generic PutRelationship builder with application/json body +func NewPutRelationshipRequest(server string, body PutRelationshipJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader buf, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(buf) - return NewPutRelationshipsRequestWithBody(server, "application/json", bodyReader) + return NewPutRelationshipRequestWithBody(server, "application/json", bodyReader) } -// NewPutRelationshipsRequestWithBody generates requests for PutRelationships with any type of body -func NewPutRelationshipsRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { +// NewPutRelationshipRequestWithBody generates requests for PutRelationship with any type of body +func NewPutRelationshipRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { var err error serverURL, err := url.Parse(server) @@ -394,8 +384,8 @@ func NewPutRelationshipsRequestWithBody(server string, contentType string, body return req, nil } -// NewGetRelationshipsRelationshipIDRequest generates requests for GetRelationshipsRelationshipID -func NewGetRelationshipsRelationshipIDRequest(server string, relationshipID externalRef0.UUID) (*http.Request, error) { +// NewGetRelationshipByIDRequest generates requests for GetRelationshipByID +func NewGetRelationshipByIDRequest(server string, relationshipID externalRef0.UUID) (*http.Request, error) { var err error var pathParam0 string @@ -468,8 +458,8 @@ func NewPutTrustDomainRequestWithBody(server string, contentType string, body io return req, nil } -// NewGetTrustDomainTrustDomainNameRequest generates requests for GetTrustDomainTrustDomainName -func NewGetTrustDomainTrustDomainNameRequest(server string, trustDomainName externalRef0.TrustDomainName) (*http.Request, error) { +// NewGetTrustDomainByNameRequest generates requests for GetTrustDomainByName +func NewGetTrustDomainByNameRequest(server string, trustDomainName externalRef0.TrustDomainName) (*http.Request, error) { var err error var pathParam0 string @@ -502,19 +492,19 @@ func NewGetTrustDomainTrustDomainNameRequest(server string, trustDomainName exte return req, nil } -// NewPutTrustDomainTrustDomainNameRequest calls the generic PutTrustDomainTrustDomainName builder with application/json body -func NewPutTrustDomainTrustDomainNameRequest(server string, trustDomainName externalRef0.UUID, body PutTrustDomainTrustDomainNameJSONRequestBody) (*http.Request, error) { +// NewPutTrustDomainByNameRequest calls the generic PutTrustDomainByName builder with application/json body +func NewPutTrustDomainByNameRequest(server string, trustDomainName externalRef0.UUID, body PutTrustDomainByNameJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader buf, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(buf) - return NewPutTrustDomainTrustDomainNameRequestWithBody(server, trustDomainName, "application/json", bodyReader) + return NewPutTrustDomainByNameRequestWithBody(server, trustDomainName, "application/json", bodyReader) } -// NewPutTrustDomainTrustDomainNameRequestWithBody generates requests for PutTrustDomainTrustDomainName with any type of body -func NewPutTrustDomainTrustDomainNameRequestWithBody(server string, trustDomainName externalRef0.UUID, contentType string, body io.Reader) (*http.Request, error) { +// NewPutTrustDomainByNameRequestWithBody generates requests for PutTrustDomainByName with any type of body +func NewPutTrustDomainByNameRequestWithBody(server string, trustDomainName externalRef0.UUID, contentType string, body io.Reader) (*http.Request, error) { var err error var pathParam0 string @@ -629,26 +619,26 @@ type ClientWithResponsesInterface interface { // GetRelationships request GetRelationshipsWithResponse(ctx context.Context, params *GetRelationshipsParams, reqEditors ...RequestEditorFn) (*GetRelationshipsResponse, error) - // PutRelationships request with any body - PutRelationshipsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutRelationshipsResponse, error) + // PutRelationship request with any body + PutRelationshipWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutRelationshipResponse, error) - PutRelationshipsWithResponse(ctx context.Context, body PutRelationshipsJSONRequestBody, reqEditors ...RequestEditorFn) (*PutRelationshipsResponse, error) + PutRelationshipWithResponse(ctx context.Context, body PutRelationshipJSONRequestBody, reqEditors ...RequestEditorFn) (*PutRelationshipResponse, error) - // GetRelationshipsRelationshipID request - GetRelationshipsRelationshipIDWithResponse(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*GetRelationshipsRelationshipIDResponse, error) + // GetRelationshipByID request + GetRelationshipByIDWithResponse(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*GetRelationshipByIDResponse, error) // PutTrustDomain request with any body PutTrustDomainWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutTrustDomainResponse, error) PutTrustDomainWithResponse(ctx context.Context, body PutTrustDomainJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTrustDomainResponse, error) - // GetTrustDomainTrustDomainName request - GetTrustDomainTrustDomainNameWithResponse(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*GetTrustDomainTrustDomainNameResponse, error) + // GetTrustDomainByName request + GetTrustDomainByNameWithResponse(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*GetTrustDomainByNameResponse, error) - // PutTrustDomainTrustDomainName request with any body - PutTrustDomainTrustDomainNameWithBodyWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutTrustDomainTrustDomainNameResponse, error) + // PutTrustDomainByName request with any body + PutTrustDomainByNameWithBodyWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutTrustDomainByNameResponse, error) - PutTrustDomainTrustDomainNameWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainTrustDomainNameJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTrustDomainTrustDomainNameResponse, error) + PutTrustDomainByNameWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainByNameJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTrustDomainByNameResponse, error) // GetJoinToken request GetJoinTokenWithResponse(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*GetJoinTokenResponse, error) @@ -677,7 +667,7 @@ func (r GetRelationshipsResponse) StatusCode() int { return 0 } -type PutRelationshipsResponse struct { +type PutRelationshipResponse struct { Body []byte HTTPResponse *http.Response JSON200 *externalRef0.Relationship @@ -685,7 +675,7 @@ type PutRelationshipsResponse struct { } // Status returns HTTPResponse.Status -func (r PutRelationshipsResponse) Status() string { +func (r PutRelationshipResponse) Status() string { if r.HTTPResponse != nil { return r.HTTPResponse.Status } @@ -693,14 +683,14 @@ func (r PutRelationshipsResponse) Status() string { } // StatusCode returns HTTPResponse.StatusCode -func (r PutRelationshipsResponse) StatusCode() int { +func (r PutRelationshipResponse) StatusCode() int { if r.HTTPResponse != nil { return r.HTTPResponse.StatusCode } return 0 } -type GetRelationshipsRelationshipIDResponse struct { +type GetRelationshipByIDResponse struct { Body []byte HTTPResponse *http.Response JSON200 *externalRef0.Relationship @@ -708,7 +698,7 @@ type GetRelationshipsRelationshipIDResponse struct { } // Status returns HTTPResponse.Status -func (r GetRelationshipsRelationshipIDResponse) Status() string { +func (r GetRelationshipByIDResponse) Status() string { if r.HTTPResponse != nil { return r.HTTPResponse.Status } @@ -716,7 +706,7 @@ func (r GetRelationshipsRelationshipIDResponse) Status() string { } // StatusCode returns HTTPResponse.StatusCode -func (r GetRelationshipsRelationshipIDResponse) StatusCode() int { +func (r GetRelationshipByIDResponse) StatusCode() int { if r.HTTPResponse != nil { return r.HTTPResponse.StatusCode } @@ -746,7 +736,7 @@ func (r PutTrustDomainResponse) StatusCode() int { return 0 } -type GetTrustDomainTrustDomainNameResponse struct { +type GetTrustDomainByNameResponse struct { Body []byte HTTPResponse *http.Response JSON200 *externalRef0.TrustDomain @@ -754,7 +744,7 @@ type GetTrustDomainTrustDomainNameResponse struct { } // Status returns HTTPResponse.Status -func (r GetTrustDomainTrustDomainNameResponse) Status() string { +func (r GetTrustDomainByNameResponse) Status() string { if r.HTTPResponse != nil { return r.HTTPResponse.Status } @@ -762,14 +752,14 @@ func (r GetTrustDomainTrustDomainNameResponse) Status() string { } // StatusCode returns HTTPResponse.StatusCode -func (r GetTrustDomainTrustDomainNameResponse) StatusCode() int { +func (r GetTrustDomainByNameResponse) StatusCode() int { if r.HTTPResponse != nil { return r.HTTPResponse.StatusCode } return 0 } -type PutTrustDomainTrustDomainNameResponse struct { +type PutTrustDomainByNameResponse struct { Body []byte HTTPResponse *http.Response JSON200 *externalRef0.TrustDomain @@ -777,7 +767,7 @@ type PutTrustDomainTrustDomainNameResponse struct { } // Status returns HTTPResponse.Status -func (r PutTrustDomainTrustDomainNameResponse) Status() string { +func (r PutTrustDomainByNameResponse) Status() string { if r.HTTPResponse != nil { return r.HTTPResponse.Status } @@ -785,7 +775,7 @@ func (r PutTrustDomainTrustDomainNameResponse) Status() string { } // StatusCode returns HTTPResponse.StatusCode -func (r PutTrustDomainTrustDomainNameResponse) StatusCode() int { +func (r PutTrustDomainByNameResponse) StatusCode() int { if r.HTTPResponse != nil { return r.HTTPResponse.StatusCode } @@ -824,30 +814,30 @@ func (c *ClientWithResponses) GetRelationshipsWithResponse(ctx context.Context, return ParseGetRelationshipsResponse(rsp) } -// PutRelationshipsWithBodyWithResponse request with arbitrary body returning *PutRelationshipsResponse -func (c *ClientWithResponses) PutRelationshipsWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutRelationshipsResponse, error) { - rsp, err := c.PutRelationshipsWithBody(ctx, contentType, body, reqEditors...) +// PutRelationshipWithBodyWithResponse request with arbitrary body returning *PutRelationshipResponse +func (c *ClientWithResponses) PutRelationshipWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutRelationshipResponse, error) { + rsp, err := c.PutRelationshipWithBody(ctx, contentType, body, reqEditors...) if err != nil { return nil, err } - return ParsePutRelationshipsResponse(rsp) + return ParsePutRelationshipResponse(rsp) } -func (c *ClientWithResponses) PutRelationshipsWithResponse(ctx context.Context, body PutRelationshipsJSONRequestBody, reqEditors ...RequestEditorFn) (*PutRelationshipsResponse, error) { - rsp, err := c.PutRelationships(ctx, body, reqEditors...) +func (c *ClientWithResponses) PutRelationshipWithResponse(ctx context.Context, body PutRelationshipJSONRequestBody, reqEditors ...RequestEditorFn) (*PutRelationshipResponse, error) { + rsp, err := c.PutRelationship(ctx, body, reqEditors...) if err != nil { return nil, err } - return ParsePutRelationshipsResponse(rsp) + return ParsePutRelationshipResponse(rsp) } -// GetRelationshipsRelationshipIDWithResponse request returning *GetRelationshipsRelationshipIDResponse -func (c *ClientWithResponses) GetRelationshipsRelationshipIDWithResponse(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*GetRelationshipsRelationshipIDResponse, error) { - rsp, err := c.GetRelationshipsRelationshipID(ctx, relationshipID, reqEditors...) +// GetRelationshipByIDWithResponse request returning *GetRelationshipByIDResponse +func (c *ClientWithResponses) GetRelationshipByIDWithResponse(ctx context.Context, relationshipID externalRef0.UUID, reqEditors ...RequestEditorFn) (*GetRelationshipByIDResponse, error) { + rsp, err := c.GetRelationshipByID(ctx, relationshipID, reqEditors...) if err != nil { return nil, err } - return ParseGetRelationshipsRelationshipIDResponse(rsp) + return ParseGetRelationshipByIDResponse(rsp) } // PutTrustDomainWithBodyWithResponse request with arbitrary body returning *PutTrustDomainResponse @@ -867,30 +857,30 @@ func (c *ClientWithResponses) PutTrustDomainWithResponse(ctx context.Context, bo return ParsePutTrustDomainResponse(rsp) } -// GetTrustDomainTrustDomainNameWithResponse request returning *GetTrustDomainTrustDomainNameResponse -func (c *ClientWithResponses) GetTrustDomainTrustDomainNameWithResponse(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*GetTrustDomainTrustDomainNameResponse, error) { - rsp, err := c.GetTrustDomainTrustDomainName(ctx, trustDomainName, reqEditors...) +// GetTrustDomainByNameWithResponse request returning *GetTrustDomainByNameResponse +func (c *ClientWithResponses) GetTrustDomainByNameWithResponse(ctx context.Context, trustDomainName externalRef0.TrustDomainName, reqEditors ...RequestEditorFn) (*GetTrustDomainByNameResponse, error) { + rsp, err := c.GetTrustDomainByName(ctx, trustDomainName, reqEditors...) if err != nil { return nil, err } - return ParseGetTrustDomainTrustDomainNameResponse(rsp) + return ParseGetTrustDomainByNameResponse(rsp) } -// PutTrustDomainTrustDomainNameWithBodyWithResponse request with arbitrary body returning *PutTrustDomainTrustDomainNameResponse -func (c *ClientWithResponses) PutTrustDomainTrustDomainNameWithBodyWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutTrustDomainTrustDomainNameResponse, error) { - rsp, err := c.PutTrustDomainTrustDomainNameWithBody(ctx, trustDomainName, contentType, body, reqEditors...) +// PutTrustDomainByNameWithBodyWithResponse request with arbitrary body returning *PutTrustDomainByNameResponse +func (c *ClientWithResponses) PutTrustDomainByNameWithBodyWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutTrustDomainByNameResponse, error) { + rsp, err := c.PutTrustDomainByNameWithBody(ctx, trustDomainName, contentType, body, reqEditors...) if err != nil { return nil, err } - return ParsePutTrustDomainTrustDomainNameResponse(rsp) + return ParsePutTrustDomainByNameResponse(rsp) } -func (c *ClientWithResponses) PutTrustDomainTrustDomainNameWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainTrustDomainNameJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTrustDomainTrustDomainNameResponse, error) { - rsp, err := c.PutTrustDomainTrustDomainName(ctx, trustDomainName, body, reqEditors...) +func (c *ClientWithResponses) PutTrustDomainByNameWithResponse(ctx context.Context, trustDomainName externalRef0.UUID, body PutTrustDomainByNameJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTrustDomainByNameResponse, error) { + rsp, err := c.PutTrustDomainByName(ctx, trustDomainName, body, reqEditors...) if err != nil { return nil, err } - return ParsePutTrustDomainTrustDomainNameResponse(rsp) + return ParsePutTrustDomainByNameResponse(rsp) } // GetJoinTokenWithResponse request returning *GetJoinTokenResponse @@ -935,15 +925,15 @@ func ParseGetRelationshipsResponse(rsp *http.Response) (*GetRelationshipsRespons return response, nil } -// ParsePutRelationshipsResponse parses an HTTP response from a PutRelationshipsWithResponse call -func ParsePutRelationshipsResponse(rsp *http.Response) (*PutRelationshipsResponse, error) { +// ParsePutRelationshipResponse parses an HTTP response from a PutRelationshipWithResponse call +func ParsePutRelationshipResponse(rsp *http.Response) (*PutRelationshipResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &PutRelationshipsResponse{ + response := &PutRelationshipResponse{ Body: bodyBytes, HTTPResponse: rsp, } @@ -968,15 +958,15 @@ func ParsePutRelationshipsResponse(rsp *http.Response) (*PutRelationshipsRespons return response, nil } -// ParseGetRelationshipsRelationshipIDResponse parses an HTTP response from a GetRelationshipsRelationshipIDWithResponse call -func ParseGetRelationshipsRelationshipIDResponse(rsp *http.Response) (*GetRelationshipsRelationshipIDResponse, error) { +// ParseGetRelationshipByIDResponse parses an HTTP response from a GetRelationshipByIDWithResponse call +func ParseGetRelationshipByIDResponse(rsp *http.Response) (*GetRelationshipByIDResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &GetRelationshipsRelationshipIDResponse{ + response := &GetRelationshipByIDResponse{ Body: bodyBytes, HTTPResponse: rsp, } @@ -1034,15 +1024,15 @@ func ParsePutTrustDomainResponse(rsp *http.Response) (*PutTrustDomainResponse, e return response, nil } -// ParseGetTrustDomainTrustDomainNameResponse parses an HTTP response from a GetTrustDomainTrustDomainNameWithResponse call -func ParseGetTrustDomainTrustDomainNameResponse(rsp *http.Response) (*GetTrustDomainTrustDomainNameResponse, error) { +// ParseGetTrustDomainByNameResponse parses an HTTP response from a GetTrustDomainByNameWithResponse call +func ParseGetTrustDomainByNameResponse(rsp *http.Response) (*GetTrustDomainByNameResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &GetTrustDomainTrustDomainNameResponse{ + response := &GetTrustDomainByNameResponse{ Body: bodyBytes, HTTPResponse: rsp, } @@ -1067,15 +1057,15 @@ func ParseGetTrustDomainTrustDomainNameResponse(rsp *http.Response) (*GetTrustDo return response, nil } -// ParsePutTrustDomainTrustDomainNameResponse parses an HTTP response from a PutTrustDomainTrustDomainNameWithResponse call -func ParsePutTrustDomainTrustDomainNameResponse(rsp *http.Response) (*PutTrustDomainTrustDomainNameResponse, error) { +// ParsePutTrustDomainByNameResponse parses an HTTP response from a PutTrustDomainByNameWithResponse call +func ParsePutTrustDomainByNameResponse(rsp *http.Response) (*PutTrustDomainByNameResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) defer func() { _ = rsp.Body.Close() }() if err != nil { return nil, err } - response := &PutTrustDomainTrustDomainNameResponse{ + response := &PutTrustDomainByNameResponse{ Body: bodyBytes, HTTPResponse: rsp, } @@ -1140,19 +1130,19 @@ type ServerInterface interface { GetRelationships(ctx echo.Context, params GetRelationshipsParams) error // Create a relationship request between two Trust Domains // (PUT /relationships) - PutRelationships(ctx echo.Context) error + PutRelationship(ctx echo.Context) error // Get a specific relationship // (GET /relationships/{relationshipID}) - GetRelationshipsRelationshipID(ctx echo.Context, relationshipID externalRef0.UUID) error + GetRelationshipByID(ctx echo.Context, relationshipID externalRef0.UUID) error // Add a specific trust domain // (PUT /trust-domain) PutTrustDomain(ctx echo.Context) error // Get a specific trust domain // (GET /trust-domain/{trustDomainName}) - GetTrustDomainTrustDomainName(ctx echo.Context, trustDomainName externalRef0.TrustDomainName) error + GetTrustDomainByName(ctx echo.Context, trustDomainName externalRef0.TrustDomainName) error // Update a specific trust domain // (PUT /trust-domain/{trustDomainName}) - PutTrustDomainTrustDomainName(ctx echo.Context, trustDomainName externalRef0.UUID) error + PutTrustDomainByName(ctx echo.Context, trustDomainName externalRef0.UUID) error // Get a join token for a specific Trust Domain // (GET /trust-domain/{trustDomainName}/join-token) GetJoinToken(ctx echo.Context, trustDomainName externalRef0.TrustDomainName) error @@ -1188,17 +1178,17 @@ func (w *ServerInterfaceWrapper) GetRelationships(ctx echo.Context) error { return err } -// PutRelationships converts echo context to params. -func (w *ServerInterfaceWrapper) PutRelationships(ctx echo.Context) error { +// PutRelationship converts echo context to params. +func (w *ServerInterfaceWrapper) PutRelationship(ctx echo.Context) error { var err error // Invoke the callback with all the unmarshalled arguments - err = w.Handler.PutRelationships(ctx) + err = w.Handler.PutRelationship(ctx) return err } -// GetRelationshipsRelationshipID converts echo context to params. -func (w *ServerInterfaceWrapper) GetRelationshipsRelationshipID(ctx echo.Context) error { +// GetRelationshipByID converts echo context to params. +func (w *ServerInterfaceWrapper) GetRelationshipByID(ctx echo.Context) error { var err error // ------------- Path parameter "relationshipID" ------------- var relationshipID externalRef0.UUID @@ -1209,7 +1199,7 @@ func (w *ServerInterfaceWrapper) GetRelationshipsRelationshipID(ctx echo.Context } // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetRelationshipsRelationshipID(ctx, relationshipID) + err = w.Handler.GetRelationshipByID(ctx, relationshipID) return err } @@ -1222,8 +1212,8 @@ func (w *ServerInterfaceWrapper) PutTrustDomain(ctx echo.Context) error { return err } -// GetTrustDomainTrustDomainName converts echo context to params. -func (w *ServerInterfaceWrapper) GetTrustDomainTrustDomainName(ctx echo.Context) error { +// GetTrustDomainByName converts echo context to params. +func (w *ServerInterfaceWrapper) GetTrustDomainByName(ctx echo.Context) error { var err error // ------------- Path parameter "trustDomainName" ------------- var trustDomainName externalRef0.TrustDomainName @@ -1234,12 +1224,12 @@ func (w *ServerInterfaceWrapper) GetTrustDomainTrustDomainName(ctx echo.Context) } // Invoke the callback with all the unmarshalled arguments - err = w.Handler.GetTrustDomainTrustDomainName(ctx, trustDomainName) + err = w.Handler.GetTrustDomainByName(ctx, trustDomainName) return err } -// PutTrustDomainTrustDomainName converts echo context to params. -func (w *ServerInterfaceWrapper) PutTrustDomainTrustDomainName(ctx echo.Context) error { +// PutTrustDomainByName converts echo context to params. +func (w *ServerInterfaceWrapper) PutTrustDomainByName(ctx echo.Context) error { var err error // ------------- Path parameter "trustDomainName" ------------- var trustDomainName externalRef0.UUID @@ -1250,7 +1240,7 @@ func (w *ServerInterfaceWrapper) PutTrustDomainTrustDomainName(ctx echo.Context) } // Invoke the callback with all the unmarshalled arguments - err = w.Handler.PutTrustDomainTrustDomainName(ctx, trustDomainName) + err = w.Handler.PutTrustDomainByName(ctx, trustDomainName) return err } @@ -1299,11 +1289,11 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL } router.GET(baseURL+"/relationships", wrapper.GetRelationships) - router.PUT(baseURL+"/relationships", wrapper.PutRelationships) - router.GET(baseURL+"/relationships/:relationshipID", wrapper.GetRelationshipsRelationshipID) + router.PUT(baseURL+"/relationships", wrapper.PutRelationship) + router.GET(baseURL+"/relationships/:relationshipID", wrapper.GetRelationshipByID) router.PUT(baseURL+"/trust-domain", wrapper.PutTrustDomain) - router.GET(baseURL+"/trust-domain/:trustDomainName", wrapper.GetTrustDomainTrustDomainName) - router.PUT(baseURL+"/trust-domain/:trustDomainName", wrapper.PutTrustDomainTrustDomainName) + router.GET(baseURL+"/trust-domain/:trustDomainName", wrapper.GetTrustDomainByName) + router.PUT(baseURL+"/trust-domain/:trustDomainName", wrapper.PutTrustDomainByName) router.GET(baseURL+"/trust-domain/:trustDomainName/join-token", wrapper.GetJoinToken) } @@ -1311,31 +1301,31 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/9xYbW/bNhD+KwTXD1uhN9uJm+ib26Sdhy4LkhQYGngBLZ1sthKpklTcLNB/H0jJtiQr", - "sZwmWdtPlsWXO97zPMc73eKAJylnwJTE/i0WIFPOJJg/RxCRLFb6MeBMATOPJE1jGhBFOXM/Sc70OxnM", - "ISH66YWACPv4F3e9r1uMSneU0mMhuMB5nls4BBkImup9sI/NABqdjtHaBT2rXKu3Xi3XToQh1StJfCp4", - "CkJR7XJEYgkWTiuvtOsh6N+Ii4Qo7GPK1HAPWzghX2mSJdjfPzy0cEJZ8a/neRZWNykUU2EGAucWTkBK", - "MjM7wVeSpLEeH6EpkEzRKIsRmBMsp1lre1IJymaFwffAZmqO/X7FSDmuTyvgS0YFhNi/LPxe252s5vPp", - "JwiU9ukPTtkF/wys7tUgIgf70XDP3n/Ve2Xv7Q/79nQQBXY/OBwOouGQRGRYdTDLaFh3bzC0cEqUAqGx", - "+efSsw+JHU1uD3J79bzX4bnXz1/gjYNWHD8DWTJsB0TV8sj3kW0dm2Zgi+Vt8TyD2PBazmm6K8sEEAXh", - "FVF1LPpev2d7PXvgXXgH/sDzPe9jNfYhUWArmkCDH72WqNFw26E/fBgf6ZlKZFJdhTwhlF2Rq0DrqVDv", - "favfFNPOFVGZbNnmgfanj2N/uoP9LA2fGI0Gp4yAKhyoudAWyLbD3YnbnQHdRuIz+JKB3FlfjwR714VN", - "fXYKVtvRL/SsIzPpO5Rv7cKrGjFuo+JwSM2JQgJSARphpOaAgCmqbtDfnS6VStr+Fb28HNkfTTL+d4Je", - "/vayNRnPibgGqUBcyZRGEXTA7fx0/PbtcQF6d3owksC2uRUIT/T03MKcTTkRIWWzq2nGwrjbHq+Lqf9b", - "MjCHvTsnbKHvSRmqtbdGAU5BEifgyXYy7B20gF2xcZrtmhieh8EbPj+INw1MzB5tQTfk/KHKJ300yiK+", - "rMtJYHAsooTfUTXPpppsIsY+niuVSt91Z+a1Jo77OyxiUOqUBJ+JCN0ZiUkoKMQbOQq/Ww6hcxDXINCf", - "hJEZJBpWXarLFAIalc2Agy0c0wCYhIo7o5QEc0B9x6u55LvuYrFwiBl1uJi55VLpvh+/OT45P7b7jufM", - "VWLcUlQZaDYcGoUJZcYXG/2VAtNPA2PrGoQsTtFzPKfXM5kkBUZSqjF2PGeADUpzQ21XVK5N82YGJqya", - "/2ZgHGoHQJ3VJuotBElAgZDYv2xoBFd3RdIUNigSPEEEFZopKItSEDqYil6DhTW82MdfMhA3y0yi4Tdl", - "kVVptoDphuVSt2SCX4NmYQiMmocUmE6ZFc6vs1XTy+q92W5cNeRldWz5NmU5sepNZt/zdmowqYJEbjNb", - "K+TzVQSIEOSmrfs8z4IApNRt3ArvQg6rDrjN3Oog7rJVNi1rliRE3BRsQaJBF0Vmmii4TqNJbuE0ayHc", - "abZBOFEUda95ePNorXlb0ZjXc6gSGeTfCF53zJ4NozfmgkakBhQqY4ymoBYADKkFrwn2PiRzq5FN3Nvq", - "3/FR3jm9nNXWbUs24yPEI3Pf1mJZKlqnurWgRXPnOtBd9V0W8JOfjxdau2R1w9XYsQV7kyvtcNWG3KXr", - "etZ9ClU3ir28VHQNqN5TWGvDqRBa+AjQjMKwCo2qFJ8VaKpybUHGvW3cafeqsnK2i42r8F5R1q75silo", - "0ePmBfswQT7+hfsNkD+PNLvhb3XR4feNbTXZPmmyaM8UPzptPpju+ykyh/uJU2avPkvflUTWn6R34dXJ", - "T5Yzmt/+nztvaKyQwQpFXFTpUMN9TQftMCpwmxhnpek9C+DqXXbMAxLPuVSOXJDZDIRDuUtS6l4PsA5q", - "uWUT7xEqPqg1PShxrr3d7N5G9dKVSlMCrj7AmBFdGJKllbcQlkGtFYr3FrulK/V6Z9OXsxarlYBPecZC", - "pHij/XXWBirBzif5fwEAAP//hjJN4p8cAAA=", + "H4sIAAAAAAAC/9xYbXObuBb+Kxrdfri3w5vtxE345jRpr3e62UzSzuw0483IcLDVgkQlEdeb4b/vSGAb", + "MIlxm2TbfjIGofPyPM/ROdzhgCcpZ8CUxP4dFiBTziSYP6cQkSxW+jLgTAEzlyRNYxoQRTlzP0nO9D0Z", + "zCEh+uqFgAj7+D/uZl+3eCrdUUrPhOAC53lu4RBkIGiq98E+Ng/Q6GKMNi7oVeW7euv169qJMKT6TRJf", + "CJ6CUFS7HJFYgoXTyi3tegj6N+IiIQr7mDI1PMAWTshXmmQJ9g+Pjy2cUFb863mehdUyhWIpzEDg3MIJ", + "SElmZif4SpI01s9HaAokUzTKYgQmgtUya2NPKkHZrDD4DthMzbHfrxgpn+toBXzJqIAQ+9eF3xu7k/V6", + "Pv0EgdI+vdZ5YupKEZWZWIHpCK4xCQJIFYRYp5lRc5ECC7WdyZZhC//GKXvPPwOrhzeIyNFhNDywD1/1", + "XtkHh8O+PR1Egd0PjoeDaDgkERlWI80yGtbjHAwtnBKlQGiQ/7r27GNiR5O7o9xeXx90uO718xf4Iccv", + "QZZU3YMaahXyQ6zd5KaJUPF6GzCXEBuByDlN96WrAKIgvCGqjkXf6/dsr2cPvPfekT/wfM/7WM19SBTY", + "iibQIFqvJWs03BX0hw/jU71SiUyqm5AnhLIbchMUhNv1dp2X29t8o/3p49if7mE/S8MnRqPBKSOgCgdq", + "LrQlsi24e3G7N6G7SHwJXzKQe+vrkWDv+mJTn52S1Rb6e73q1Cz6AeVbOzmrRozbqAgOqTlRSEAqQCOM", + "1BwQMEXVEv3Z6XSqlO3/opfXI/ujKcZ/T9DL/71sLcZzIm5BKhA3MqVRBB1wu7oYv3lzVoDenR6MJLBr", + "bQXCc708tzBnU06EPgRvphkL4257nBRL/7ViYIK9vybsoO95maqNt0YBTkESJ+DJbjIcHLWAXbFxke1b", + "GJ6HwVs+fxNvGpiYPdqSbsj5U7VPOjTKIr5q8ElgcCyyhN9SNc+mmmwixj6eK5VK33Vn5rYmjvt/WMSg", + "1AUJPhMRujMSk1BQiLdqFH67eoSuQNyCQL8TRmaQaFh1zy9TCGhUThUOtnBMA2ASKu6MUhLMAfUdr+aS", + "77qLxcIh5qnDxcwtX5Xuu/Hrs/OrM7vveM5cJcYtRZWBZsuhUZhQZnyx0R8pMH01MLZuQcgiip7jOb2e", + "qSQpMJJSjbHjOQNsUJobaruicmyaOzMwadX8Nw/GoXYA1GVtod5CkAQUCIn964ZGcHVXJE1jgyLBE0RQ", + "oZmCsigFoZOp6C1YWMOLffwlA7FcVRINv2mLrI5TW6OZyq2ma9XDst2iamiqq+ltLU6s+oja97y9xlOq", + "IJG7zNa693wtGyIEWbbNrldZEICUeghcg1xoYD0/t5lbB+KuBm0z8GZJQsSyoAgSDY4oMtPswHXuTHIL", + "p1kLyy6yGstwUcpAqhMeLh9trm9rFPN63VQig/w7sesO2bNB9NocyojUcEJljtEU1AKAIbXgNZE+BGRu", + "NSqIe1f9Oz7Nu5aUk+X4dFdVGZ8iHpmDtUETo2Jd0zYirruBm+h21XTZqU9+PTJovZL1UVajxA7ATX20", + "w/W8cZ+W65X2KaTc6OryUsY1oHpPYa0Np0Jd4SNAMwrDKjSq0mVWoKlqtAUZ965xjj0oxUpsJ8vy1HtQ", + "i7VjvGz6W2S4fZZ+mw4f/2z9DqSfR5HdYLe6yO+HhLRaWp+0NLTXhZ+dLR/MUP0UdcL9xCmz11+b7ysZ", + "my/N+/Dq/BcrFc1P+s9dLjRWyGCFIi6qdKjhvqGDdhgVuE2Ms9KMlAVw9eE55gGJ51wqRy7IbAbCodwl", + "KXVvB1gntdyyifcIFd/Jmh6UONfubs9no3p3SqVp+NbfVcwT3QaSlZU3EJZJrbWFD/azpSv17mbbl8sW", + "q5WET3nGQqR4Y6p1NgYqyc4n+T8BAAD//zp9GRG/HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/server/api/admin/admin.yaml b/pkg/server/api/admin/admin.yaml index 004b31019..8a7214798 100644 --- a/pkg/server/api/admin/admin.yaml +++ b/pkg/server/api/admin/admin.yaml @@ -23,6 +23,7 @@ tags: paths: /trust-domain/{trustDomainName}: get: + operationId: GetTrustDomainByName tags: - Trust Domain summary: Get a specific trust domain @@ -43,6 +44,7 @@ paths: default: $ref: '#/components/responses/Default' put: + operationId: PutTrustDomainByName tags: - Trust Domain summary: Update a specific trust domain @@ -70,6 +72,7 @@ paths: /trust-domain: put: + operationId: PutTrustDomain tags: - Trust Domain summary: Add a specific trust domain @@ -90,6 +93,7 @@ paths: /relationships: get: + operationId: GetRelationships tags: - Relationships summary: Get relationships @@ -97,8 +101,7 @@ paths: - name: status in: query schema: - type: string - enum: [approved, denied, pending] + $ref: '../../../common/api/schemas.yaml#/components/schemas/ConsentStatus' description: relationship status from a Trust Domain perspective, - name: trustDomainName in: query @@ -117,6 +120,7 @@ paths: default: $ref: '#/components/responses/Default' put: + operationId: PutRelationship tags: - Relationships summary: Create a relationship request between two Trust Domains @@ -138,6 +142,7 @@ paths: /relationships/{relationshipID}: get: + operationId: GetRelationshipByID tags: - Relationships summary: Get a specific relationship diff --git a/pkg/server/catalog/catalog.go b/pkg/server/catalog/catalog.go index bef8f086f..59951eeb0 100644 --- a/pkg/server/catalog/catalog.go +++ b/pkg/server/catalog/catalog.go @@ -4,27 +4,32 @@ import ( "fmt" "github.com/HewlettPackard/galadriel/pkg/common/keymanager" "github.com/HewlettPackard/galadriel/pkg/common/keymanager/memory" - "github.com/HewlettPackard/galadriel/pkg/common/x509ca" "github.com/HewlettPackard/galadriel/pkg/common/x509ca/disk" + "github.com/HewlettPackard/galadriel/pkg/server/db" + "github.com/HewlettPackard/galadriel/pkg/server/db/postgres" + "github.com/HewlettPackard/galadriel/pkg/server/db/sqlite" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" ) // Catalog is a collection of provider interfaces. type Catalog interface { + GetDatastore() db.Datastore GetX509CA() x509ca.X509CA GetKeyManager() keymanager.KeyManager } // ProvidersRepository is the implementation of the Catalog interface. type ProvidersRepository struct { + datastore db.Datastore x509ca x509ca.X509CA keyManager keymanager.KeyManager } // ProvidersConfig holds the HCL configuration for the providers. type ProvidersConfig struct { + Datastore *providerConfig `hcl:"Datastore,block"` X509CA *providerConfig `hcl:"X509CA,block"` KeyManager *providerConfig `hcl:"KeyManager,block"` } @@ -34,6 +39,9 @@ type providerConfig struct { Name string `hcl:",label"` Options hcl.Body `hcl:",remain"` } +type datastoreConfig struct { + ConnectionString string `hcl:"connection_string"` +} // New creates a new ProvidersRepository. // It is the responsibility of the caller to load the catalog with providers using LoadFromProvidersConfig. @@ -63,6 +71,9 @@ func (c *ProvidersRepository) LoadFromProvidersConfig(config *ProvidersConfig) e if config.KeyManager == nil { return fmt.Errorf("KeyManager configuration is required") } + if config.Datastore == nil { + return fmt.Errorf("datastore configuration is required") + } var err error c.x509ca, err = loadX509CA(config.X509CA) @@ -74,10 +85,18 @@ func (c *ProvidersRepository) LoadFromProvidersConfig(config *ProvidersConfig) e if err != nil { return fmt.Errorf("error loading KeyManager: %w", err) } + c.datastore, err = loadDatastore(config.Datastore) + if err != nil { + return fmt.Errorf("error loading datastore: %w", err) + } return nil } +func (c *ProvidersRepository) GetDatastore() db.Datastore { + return c.datastore +} + func (c *ProvidersRepository) GetX509CA() x509ca.X509CA { return c.x509ca } @@ -109,6 +128,39 @@ func loadKeyManager(c *providerConfig) (keymanager.KeyManager, error) { return nil, fmt.Errorf("unknown KeyManager provider: %s", c.Name) } +func loadDatastore(config *providerConfig) (db.Datastore, error) { + c, err := decodeDatastoreConfig(config) + if err != nil { + return nil, fmt.Errorf("error decoding datastore config: %w", err) + } + switch config.Name { + case "postgres": + ds, err := postgres.NewDatastore(c.ConnectionString) + if err != nil { + return nil, fmt.Errorf("error creating postgres datastore: %w", err) + } + return ds, nil + case "sqlite3": + ds, err := sqlite.NewDatastore(c.ConnectionString) + if err != nil { + return nil, fmt.Errorf("error creating sqlite datastore: %w", err) + } + + return ds, nil + + } + + return nil, fmt.Errorf("unknown datastore provider: %s", config.Name) +} + +func decodeDatastoreConfig(config *providerConfig) (*datastoreConfig, error) { + var dsConfig datastoreConfig + if err := gohcl.DecodeBody(config.Options, nil, &dsConfig); err != nil { + return nil, err + } + return &dsConfig, nil +} + func makeDiskX509CA(config *providerConfig) (*disk.X509CA, error) { var diskX509CAConfig disk.Config if err := gohcl.DecodeBody(config.Options, nil, &diskX509CAConfig); err != nil { diff --git a/pkg/server/catalog/catalog_test.go b/pkg/server/catalog/catalog_test.go index 057accfbc..fba82c126 100644 --- a/pkg/server/catalog/catalog_test.go +++ b/pkg/server/catalog/catalog_test.go @@ -16,6 +16,9 @@ import ( var hclConfigTemplate = ` providers { + Datastore "sqlite3" { + connection_string = "%s" + } X509CA "disk" { key_file_path = "%s" cert_file_path = "%s" @@ -51,7 +54,7 @@ func TestLoadFromProvidersConfig(t *testing.T) { tempDir, cleanup := setupTest(t) defer cleanup() - hclConfig := fmt.Sprintf(hclConfigTemplate, tempDir+"/root-ca.key", tempDir+"/root-ca.crt") + hclConfig := fmt.Sprintf(hclConfigTemplate, ":memory:", tempDir+"/root-ca.key", tempDir+"/root-ca.crt") hclBody, diagErr := hclsyntax.ParseConfig([]byte(hclConfig), "", hcl.Pos{Line: 1, Column: 1}) require.False(t, diagErr.HasErrors()) @@ -67,6 +70,8 @@ func TestLoadFromProvidersConfig(t *testing.T) { cat := New() err = cat.LoadFromProvidersConfig(pc) require.NoError(t, err) + require.NotNil(t, cat.GetDatastore()) + require.NotNil(t, cat.GetKeyManager()) require.NotNil(t, cat.GetX509CA()) _, ok := cat.GetX509CA().(*disk.X509CA) diff --git a/pkg/server/datastore/datastore_test.go b/pkg/server/datastore/datastore_test.go deleted file mode 100644 index e9df98c9a..000000000 --- a/pkg/server/datastore/datastore_test.go +++ /dev/null @@ -1,874 +0,0 @@ -package datastore_test - -import ( - "context" - "database/sql" - "errors" - "fmt" - "testing" - "time" - - "github.com/HewlettPackard/galadriel/pkg/common/entity" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" - "github.com/google/uuid" - "github.com/jackc/pgerrcode" - "github.com/jackc/pgx/v5/pgconn" - "github.com/ory/dockertest/v3" - "github.com/ory/dockertest/v3/docker" - "github.com/sirupsen/logrus" - "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const ( - postgresImage = "15-alpine" - user = "test_user" - password = "test_password" - dbname = "test_db" -) - -var ( - spiffeTD1 = spiffeid.RequireTrustDomainFromString("foo.test") - spiffeTD2 = spiffeid.RequireTrustDomainFromString("bar.test") - spiffeTD3 = spiffeid.RequireTrustDomainFromString("baz.test") -) - -func TestCreateTrustDomain(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - req1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 := createTrustDomain(ctx, t, ds, req1) - assert.Equal(t, req1.Name, td1.Name) - require.NotNil(t, td1.ID) - require.NotNil(t, td1.CreatedAt) - require.NotNil(t, td1.UpdatedAt) - - // Look up trust domain stored in DB and compare - stored, err := ds.FindTrustDomainByID(ctx, td1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, td1, stored) -} - -func TestUpdateTrustDomain(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - req1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 := createTrustDomain(ctx, t, ds, req1) - - td1.Description = "updated_description" - td1.HarvesterSpiffeID = spiffeid.RequireFromString("spiffe://domain/test") - td1.OnboardingBundle = []byte{1, 2, 3} - - // Update Trust Domain - updated1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - require.NotNil(t, updated1) - - // Look up trust domain stored in DB and compare - stored, err := ds.FindTrustDomainByID(ctx, td1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, td1.ID, stored.ID) - assert.Equal(t, td1.Description, stored.Description) - assert.Equal(t, td1.HarvesterSpiffeID, stored.HarvesterSpiffeID) - assert.Equal(t, td1.OnboardingBundle, stored.OnboardingBundle) -} - -func TestTrustFindDomainByName(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - req1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 := createTrustDomain(ctx, t, ds, req1) - - req2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 := createTrustDomain(ctx, t, ds, req2) - - stored1, err := ds.FindTrustDomainByName(ctx, td1.Name) - require.NoError(t, err) - assert.Equal(t, td1, stored1) - - stored2, err := ds.FindTrustDomainByName(ctx, td2.Name) - require.NoError(t, err) - assert.Equal(t, td2, stored2) -} - -func TestDeleteTrustDomain(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - req1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 := createTrustDomain(ctx, t, ds, req1) - - req2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 := createTrustDomain(ctx, t, ds, req2) - - err := ds.DeleteTrustDomain(ctx, td1.ID.UUID) - require.NoError(t, err) - - stored, err := ds.FindTrustDomainByID(ctx, td1.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) - - err = ds.DeleteTrustDomain(ctx, td2.ID.UUID) - require.NoError(t, err) - - stored, err = ds.FindTrustDomainByID(ctx, td2.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) -} - -func TestListTrustDomains(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - req1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 := createTrustDomain(ctx, t, ds, req1) - - req2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 := createTrustDomain(ctx, t, ds, req2) - - list, err := ds.ListTrustDomains(ctx) - require.NoError(t, err) - require.NotNil(t, list) - assert.Equal(t, 2, len(list)) - assert.Contains(t, list, td1) - assert.Contains(t, list, td2) -} - -func TestTrustDomainUniqueTrustDomainConstraint(t *testing.T) { - t.Parallel() - datastore, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the datastore") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - _, err = datastore.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - - // second trustDomain with same trust domain - td2 := &entity.TrustDomain{ - Name: spiffeTD1, - } - _, err = datastore.CreateOrUpdateTrustDomain(ctx, td2) - require.Error(t, err) - - wrappedErr := errors.Unwrap(err) - errCode := wrappedErr.(*pgconn.PgError).SQLState() - assert.Equal(t, pgerrcode.UniqueViolation, errCode, "Unique constraint violation was expected") -} - -func TestCreateRelationship(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - // Setup - // Create TrustDomains - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 = createTrustDomain(ctx, t, ds, td1) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 = createTrustDomain(ctx, t, ds, td2) - - // Create relationship TrustDomain1 -- TrustDomain2 - req1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - - relationship1 := createRelationship(ctx, t, ds, req1) - require.NotNil(t, relationship1.ID) - require.NotNil(t, relationship1.CreatedAt) - require.NotNil(t, relationship1.UpdatedAt) - assert.Equal(t, req1.TrustDomainAID, relationship1.TrustDomainAID) - assert.Equal(t, req1.TrustDomainBID, relationship1.TrustDomainBID) - - // Look up relationship in DB and compare - stored, err := ds.FindRelationshipByID(ctx, relationship1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, relationship1, stored) -} - -func TestUpdateRelationship(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - // Setup - // Create TrustDomains - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 = createTrustDomain(ctx, t, ds, td1) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 = createTrustDomain(ctx, t, ds, td2) - - // Create relationship TrustDomain1 -- TrustDomain2 - req1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - - relationship1 := createRelationship(ctx, t, ds, req1) - - relationship1.TrustDomainAConsent = entity.ConsentStatusAccepted - relationship1.TrustDomainBConsent = entity.ConsentStatusDenied - - updated1, err := ds.CreateOrUpdateRelationship(ctx, relationship1) - require.NoError(t, err) - - // Look up relationship in DB and compare - stored, err := ds.FindRelationshipByID(ctx, updated1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, updated1, stored) - assert.Equal(t, entity.ConsentStatusAccepted, stored.TrustDomainAConsent) - assert.Equal(t, entity.ConsentStatusDenied, stored.TrustDomainBConsent) -} - -func TestFindRelationshipByTrustDomain(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - // Setup - // Create TrustDomains - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 = createTrustDomain(ctx, t, ds, td1) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 = createTrustDomain(ctx, t, ds, td2) - - td3 := &entity.TrustDomain{ - Name: spiffeTD3, - } - td3 = createTrustDomain(ctx, t, ds, td3) - - // Create relationship TrustDomain1 -- TrustDomain2 - req1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - - relationship1 := createRelationship(ctx, t, ds, req1) - - // Create relationship TrustDomain1 -- TrustDomain3 - req2 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td3.ID.UUID, - } - relationship2 := createRelationship(ctx, t, ds, req2) - - // Find relationships by TrustDomainID - relationships, err := ds.FindRelationshipsByTrustDomainID(ctx, td1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, 2, len(relationships)) - assert.Contains(t, relationships, relationship1) - assert.Contains(t, relationships, relationship2) - - relationships, err = ds.FindRelationshipsByTrustDomainID(ctx, td2.ID.UUID) - require.NoError(t, err) - assert.Equal(t, 1, len(relationships)) - assert.Contains(t, relationships, relationship1) -} - -func TestDeleteRelationship(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - // Setup - // Create TrustDomains - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 = createTrustDomain(ctx, t, ds, td1) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 = createTrustDomain(ctx, t, ds, td2) - - td3 := &entity.TrustDomain{ - Name: spiffeTD3, - } - td3 = createTrustDomain(ctx, t, ds, td3) - - // Create relationship TrustDomain1 -- TrustDomain2 - req1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - - relationship1 := createRelationship(ctx, t, ds, req1) - - // Create relationship TrustDomain1 -- TrustDomain3 - req2 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td3.ID.UUID, - } - relationship2 := createRelationship(ctx, t, ds, req2) - - // Delete relationships - err := ds.DeleteRelationship(ctx, relationship1.ID.UUID) - require.NoError(t, err) - stored, err := ds.FindRelationshipByID(ctx, relationship1.ID.UUID) - require.NoError(t, err) - assert.Nil(t, stored) - - err = ds.DeleteRelationship(ctx, relationship2.ID.UUID) - require.NoError(t, err) - stored, err = ds.FindRelationshipByID(ctx, relationship2.ID.UUID) - require.NoError(t, err) - assert.Nil(t, stored) -} - -func TestListRelationships(t *testing.T) { - t.Parallel() - ds, ctx := setupTest(t) - - // Setup - // Create TrustDomains - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1 = createTrustDomain(ctx, t, ds, td1) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2 = createTrustDomain(ctx, t, ds, td2) - - td3 := &entity.TrustDomain{ - Name: spiffeTD3, - } - td3 = createTrustDomain(ctx, t, ds, td3) - - // Create relationship TrustDomain1 -- TrustDomain2 - req1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - - relationship1 := createRelationship(ctx, t, ds, req1) - - // Create relationship TrustDomain1 -- TrustDomain3 - req2 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td3.ID.UUID, - } - relationship2 := createRelationship(ctx, t, ds, req2) - - relationships, err := ds.ListRelationships(ctx) - require.NoError(t, err) - assert.Contains(t, relationships, relationship1) - assert.Contains(t, relationships, relationship2) -} - -func TestRelationshipForeignKeysConstraints(t *testing.T) { - t.Parallel() - datastore, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the datastore") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1, err = datastore.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2, err = datastore.CreateOrUpdateTrustDomain(ctx, td2) - require.NoError(t, err) - - relationship1 := &entity.Relationship{ - TrustDomainAID: td1.ID.UUID, - TrustDomainBID: td2.ID.UUID, - } - relationship1, err = datastore.CreateOrUpdateRelationship(ctx, relationship1) - require.NoError(t, err) - - // Cannot add a new relationship for the same TrustDomains - relationship1.ID = uuid.NullUUID{} - _, err = datastore.CreateOrUpdateRelationship(ctx, relationship1) - require.Error(t, err) - - wrappedErr := errors.Unwrap(err) - errCode := wrappedErr.(*pgconn.PgError).SQLState() - assert.Equal(t, pgerrcode.UniqueViolation, errCode, "Unique constraint violation error was expected") - - // Cannot delete Trust Domain that has a relationship associated - err = datastore.DeleteTrustDomain(ctx, td1.ID.UUID) - require.Error(t, err) - - wrappedErr = errors.Unwrap(err) - errCode = wrappedErr.(*pgconn.PgError).SQLState() - assert.Equal(t, pgerrcode.ForeignKeyViolation, errCode, "Foreign key violation error was expected") - - // Cannot delete Trust Domain that has a relationship associated - err = datastore.DeleteTrustDomain(ctx, td2.ID.UUID) - require.Error(t, err) - - wrappedErr = errors.Unwrap(err) - errCode = wrappedErr.(*pgconn.PgError).SQLState() - assert.Equal(t, pgerrcode.ForeignKeyViolation, errCode, "Foreign key violation error was expected") -} - -func createTrustDomain(ctx context.Context, t *testing.T, ds *datastore.SQLDatastore, req *entity.TrustDomain) *entity.TrustDomain { - td1, err := ds.CreateOrUpdateTrustDomain(ctx, req) - require.NoError(t, err) - require.NotNil(t, td1.ID) - - return td1 -} - -func createRelationship(ctx context.Context, t *testing.T, ds *datastore.SQLDatastore, req *entity.Relationship) *entity.Relationship { - td1, err := ds.CreateOrUpdateRelationship(ctx, req) - require.NoError(t, err) - require.NotNil(t, td1.ID) - - return td1 -} - -func TestCRUDBundle(t *testing.T) { - t.Parallel() - datastore, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the datastore") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - // Create trustDomains to associate the bundles - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1, err = datastore.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - require.NotNil(t, td1.ID) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2, err = datastore.CreateOrUpdateTrustDomain(ctx, td2) - require.NoError(t, err) - require.NotNil(t, td2.ID) - - // Create first Data - trustDomain-1 - req1 := &entity.Bundle{ - Data: []byte{1, 2, 3}, - Signature: []byte{4, 2}, - SignatureAlgorithm: "SHA256WithRSA", - SigningCertificate: []byte{50, 60}, - TrustDomainID: td1.ID.UUID, - } - - b1, err := datastore.CreateOrUpdateBundle(ctx, req1) - require.NoError(t, err) - require.NotNil(t, b1) - assert.Equal(t, req1.Data, b1.Data) - assert.Equal(t, req1.Signature, b1.Signature) - assert.Equal(t, req1.SignatureAlgorithm, b1.SignatureAlgorithm) - assert.Equal(t, req1.SigningCertificate, b1.SigningCertificate) - assert.Equal(t, req1.TrustDomainID, b1.TrustDomainID) - - // Look up bundle stored in DB and compare - stored, err := datastore.FindBundleByID(ctx, b1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, b1, stored) - - // Create second Data -> trustDomain-2 - req2 := &entity.Bundle{ - Data: []byte{10, 20, 30}, - Signature: []byte{40, 20}, - SignatureAlgorithm: "SHA256WithRSA", - SigningCertificate: []byte{80, 90}, - TrustDomainID: td2.ID.UUID, - } - - b2, err := datastore.CreateOrUpdateBundle(ctx, req2) - require.NoError(t, err) - require.NotNil(t, b1) - assert.Equal(t, req2.Data, b2.Data) - assert.Equal(t, req2.Signature, b2.Signature) - assert.Equal(t, req2.SignatureAlgorithm, b2.SignatureAlgorithm) - assert.Equal(t, req2.SigningCertificate, b2.SigningCertificate) - assert.Equal(t, req2.TrustDomainID, b2.TrustDomainID) - - // Look up bundle stored in DB and compare - stored, err = datastore.FindBundleByID(ctx, b2.ID.UUID) - require.NoError(t, err) - assert.Equal(t, b2, stored) - - // Find bundles by TrustDomainID - stored, err = datastore.FindBundleByTrustDomainID(ctx, td1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, b1, stored) - - stored, err = datastore.FindBundleByTrustDomainID(ctx, td2.ID.UUID) - require.NoError(t, err) - assert.Equal(t, b2, stored) - - // Update Data - b1.Data = []byte{'a', 'b', 'c'} - b1.Signature = []byte{'f', 'g', 'h'} - b1.SignatureAlgorithm = "SHA512WithRSA" - b1.SigningCertificate = []byte{'f', 'g', 'h'} - - updated, err := datastore.CreateOrUpdateBundle(ctx, b1) - require.NoError(t, err) - require.NotNil(t, updated) - assert.Equal(t, b1.Data, updated.Data) - assert.Equal(t, b1.Signature, updated.Signature) - assert.Equal(t, b1.SignatureAlgorithm, updated.SignatureAlgorithm) - assert.Equal(t, b1.SigningCertificate, updated.SigningCertificate) - assert.Equal(t, b1.TrustDomainID, updated.TrustDomainID) - - // Look up bundle stored in DB and compare - stored, err = datastore.FindBundleByID(ctx, b1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, updated, stored) - - // List bundles - bundles, err := datastore.ListBundles(ctx) - require.NoError(t, err) - assert.Equal(t, 2, len(bundles)) - require.Contains(t, bundles, updated) - require.Contains(t, bundles, b2) - - // Delete first bundle - err = datastore.DeleteBundle(ctx, b1.ID.UUID) - require.NoError(t, err) - - // Look up deleted bundle - stored, err = datastore.FindBundleByID(ctx, b1.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) - - // Delete second bundle - err = datastore.DeleteBundle(ctx, b2.ID.UUID) - require.NoError(t, err) - - // Look up deleted bundle - stored, err = datastore.FindBundleByID(ctx, b2.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) -} - -func TestBundleUniqueTrustDomainConstraint(t *testing.T) { - t.Parallel() - datastore, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the datastore") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - // Create trustDomain to associate the bundles - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1, err = datastore.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - require.NotNil(t, td1.ID) - - // Create Data - b1 := &entity.Bundle{ - Data: []byte{1, 2, 3}, - Signature: []byte{4, 2}, - SignatureAlgorithm: "SHA512WithRSA", - SigningCertificate: []byte{50, 60}, - TrustDomainID: td1.ID.UUID, - } - b1, err = datastore.CreateOrUpdateBundle(ctx, b1) - require.NoError(t, err) - require.NotNil(t, b1) - - // Create second Data associated to same trustDomain - b2 := &entity.Bundle{ - Data: []byte{10, 20, 30}, - Signature: []byte{40, 20}, - SignatureAlgorithm: "SHA512WithRSA", - SigningCertificate: []byte{80, 90}, - TrustDomainID: td1.ID.UUID, - } - b2, err = datastore.CreateOrUpdateBundle(ctx, b2) - require.Error(t, err) - require.Nil(t, b2) - - wrappedErr := errors.Unwrap(err) - errCode := wrappedErr.(*pgconn.PgError).SQLState() - assert.Equal(t, pgerrcode.UniqueViolation, errCode, "Unique constraint violation error was expected") -} - -func TestCRUDJoinToken(t *testing.T) { - t.Parallel() - datastore, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the datastore") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - //// Create trustDomains to associate the join tokens - td1 := &entity.TrustDomain{ - Name: spiffeTD1, - } - td1, err = datastore.CreateOrUpdateTrustDomain(ctx, td1) - require.NoError(t, err) - require.NotNil(t, td1.ID) - - td2 := &entity.TrustDomain{ - Name: spiffeTD2, - } - td2, err = datastore.CreateOrUpdateTrustDomain(ctx, td2) - require.NoError(t, err) - require.NotNil(t, td2.ID) - - loc, _ := time.LoadLocation("UTC") - expiry := time.Now().In(loc).Add(1 * time.Hour) - - // Create first join_token -> trustDomain_1 - req1 := &entity.JoinToken{ - Token: uuid.NewString(), - ExpiresAt: expiry, - TrustDomainID: td1.ID.UUID, - } - - token1, err := datastore.CreateJoinToken(ctx, req1) - require.NoError(t, err) - require.NotNil(t, token1) - assert.Equal(t, req1.Token, token1.Token) - assertEqualDate(t, req1.ExpiresAt, token1.ExpiresAt.In(loc)) - require.False(t, token1.Used) - assert.Equal(t, req1.TrustDomainID, token1.TrustDomainID) - - // Look up token stored in DB and compare - stored, err := datastore.FindJoinTokensByID(ctx, token1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, token1, stored) - - // Create second join_token -> trustDomain_2 - req2 := &entity.JoinToken{ - Token: uuid.NewString(), - ExpiresAt: expiry, - TrustDomainID: td2.ID.UUID, - } - - token2, err := datastore.CreateJoinToken(ctx, req2) - require.NoError(t, err) - require.NotNil(t, token1) - assert.Equal(t, req2.Token, token2.Token) - assert.Equal(t, req1.TrustDomainID, token1.TrustDomainID) - require.False(t, token2.Used) - - assertEqualDate(t, req2.ExpiresAt, token2.ExpiresAt.In(loc)) - assert.Equal(t, req2.TrustDomainID, token2.TrustDomainID) - - // Look up token stored in DB and compare - stored, err = datastore.FindJoinTokensByID(ctx, token2.ID.UUID) - require.NoError(t, err) - assert.Equal(t, token2, stored) - - // Create second join_token -> trustDomain_2 - req3 := &entity.JoinToken{ - Token: uuid.NewString(), - ExpiresAt: expiry, - TrustDomainID: td2.ID.UUID, - } - - token3, err := datastore.CreateJoinToken(ctx, req3) - require.NoError(t, err) - require.NotNil(t, token3) - - // Find tokens by TrustDomainID - tokens, err := datastore.FindJoinTokensByTrustDomainID(ctx, td1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, 1, len(tokens)) - require.Contains(t, tokens, token1) - - tokens, err = datastore.FindJoinTokensByTrustDomainID(ctx, td2.ID.UUID) - require.NoError(t, err) - assert.Equal(t, 2, len(tokens)) - require.Contains(t, tokens, token2) - require.Contains(t, tokens, token3) - - // Look up join token by token string - stored, err = datastore.FindJoinToken(ctx, token1.Token) - require.NoError(t, err) - assert.Equal(t, token1, stored) - - stored, err = datastore.FindJoinToken(ctx, token2.Token) - require.NoError(t, err) - assert.Equal(t, token2, stored) - - stored, err = datastore.FindJoinToken(ctx, token3.Token) - require.NoError(t, err) - assert.Equal(t, token3, stored) - - // List tokens - tokens, err = datastore.ListJoinTokens(ctx) - require.NoError(t, err) - assert.Equal(t, 3, len(tokens)) - require.Contains(t, tokens, token1) - require.Contains(t, tokens, token2) - require.Contains(t, tokens, token3) - - // Update join token - updated, err := datastore.UpdateJoinToken(ctx, token1.ID.UUID, true) - require.NoError(t, err) - assert.Equal(t, true, updated.Used) - - // Look up and compare - stored, err = datastore.FindJoinTokensByID(ctx, token1.ID.UUID) - require.NoError(t, err) - assert.Equal(t, true, stored.Used) - assert.Equal(t, updated.UpdatedAt, stored.UpdatedAt) - - // Delete join tokens - err = datastore.DeleteJoinToken(ctx, token1.ID.UUID) - require.NoError(t, err) - stored, err = datastore.FindJoinTokensByID(ctx, token1.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) - - err = datastore.DeleteJoinToken(ctx, token2.ID.UUID) - require.NoError(t, err) - stored, err = datastore.FindJoinTokensByID(ctx, token2.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) - - err = datastore.DeleteJoinToken(ctx, token3.ID.UUID) - require.NoError(t, err) - stored, err = datastore.FindJoinTokensByID(ctx, token3.ID.UUID) - require.NoError(t, err) - require.Nil(t, stored) - - tokens, err = datastore.ListJoinTokens(ctx) - require.NoError(t, err) - assert.Equal(t, 0, len(tokens)) -} - -func assertEqualDate(t *testing.T, time1 time.Time, time2 time.Time) { - y1, td1, d1 := time1.Date() - y2, td2, d2 := time2.Date() - h1, mt1, s1 := time1.Clock() - h2, mt2, s2 := time2.Clock() - - require.Equal(t, y1, y2, "Year doesn't match") - require.Equal(t, td1, td2, "Month doesn't match") - require.Equal(t, d1, d2, "Day doesn't match") - require.Equal(t, h1, h2, "Hour doesn't match") - require.Equal(t, mt1, mt2, "Minute doesn't match") - require.Equal(t, s1, s2, "Seconds doesn't match") -} - -func setupTest(t *testing.T) (*datastore.SQLDatastore, context.Context) { - ds, err := setupDatastore(t) - require.NoError(t, err, "Failed to setup the ds") - - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - return ds, ctx -} - -func setupDatastore(t *testing.T) (*datastore.SQLDatastore, error) { - log := logrus.New() - - conn := startDB(t) - datastore, err := datastore.NewSQLDatastore(log, conn) - require.NoError(t, err) - - t.Cleanup(func() { - err = datastore.Close() - require.NoError(t, err) - }) - return datastore, nil -} - -// starts a postgres DB in a docker container and returns the connection string -func startDB(tb testing.TB) string { - pool, err := dockertest.NewPool("") - require.NoError(tb, err) - - err = pool.Client.Ping() - require.NoError(tb, err) - - // pulls an image, creates a container based on it and runs it - resource, err := pool.RunWithOptions(&dockertest.RunOptions{ - Repository: "postgres", - Tag: postgresImage, - Env: []string{ - "POSTGRES_PASSWORD=" + password, - "POSTGRES_USER=" + user, - "POSTGRES_DB=" + dbname, - }, - }, func(config *docker.HostConfig) { - // set AutoRemove to true so that stopped container goes away by itself - config.AutoRemove = true - config.RestartPolicy = docker.RestartPolicy{Name: "no"} - }) - require.NoError(tb, err) - - hostAndPort := resource.GetHostPort("5432/tcp") - databaseURL := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", user, password, hostAndPort, dbname) - - tb.Logf("Connecting to a test database on url: %s", databaseURL) - - // wait until db in container is ready using exponential backoff-retry - pool.MaxWait = 60 * time.Second - if err = pool.Retry(func() error { - db, err := sql.Open("postgres", databaseURL) - if err != nil { - return err - } - defer func() { - cerr := db.Close() - if err != nil { - err = cerr - } - }() - - return db.Ping() - }); err != nil { - tb.Fatalf("Could not connect to docker: %s", err) - } - - tb.Cleanup(func() { - err = pool.Purge(resource) - require.NoError(tb, err) - }) - - return databaseURL -} diff --git a/pkg/server/datastore/sqlc.yaml b/pkg/server/datastore/sqlc.yaml deleted file mode 100644 index 6f2c37850..000000000 --- a/pkg/server/datastore/sqlc.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: "1" -packages: - - name: "datastore" - path: "." - queries: "queries" - schema: "migrations" - engine: "postgresql" - emit_json_tags: false - emit_prepared_queries: true - emit_interface: true - emit_exact_table_names: false -overrides: - - go_type: "github.com/jackc/pgtype.UUID" - db_type: "uuid" diff --git a/pkg/server/datastore/README.md b/pkg/server/db/README.md similarity index 70% rename from pkg/server/datastore/README.md rename to pkg/server/db/README.md index 086741549..f1678ecf2 100644 --- a/pkg/server/datastore/README.md +++ b/pkg/server/db/README.md @@ -1,4 +1,4 @@ -# Datastore code +# Datastore code Type-safe code from SQL is generated using [sqlc](https://github.com/kyleconroy/sqlc). @@ -7,7 +7,7 @@ Type-safe code from SQL is generated using [sqlc](https://github.com/kyleconroy/ When there is a change in the schema or in the queries, the DB code should be re-generated: ``` -make generate-sql-server +make generate-sqlc-code ``` This regenerates the files `models.go`, `db.go`, `querier.go`, and files ending in `.sql.go`. @@ -18,10 +18,11 @@ This regenerates the files `models.go`, `db.go`, `querier.go`, and files ending Migrations are done using [golang-migrate](https://github.com/golang-migrate/migrate). -When a new Datastore object is created using the NewDatastore method, the schema version is verified and -migrations are applied if needed. +When a new Datastore object is created using the NewDatastore method, the schema version is verified and +migrations are applied if needed. # Change the DB schema Once there was an initial release of Galadriel, changes in the DB schema should be added through new files -in the [migrations](migrations) folder and the queries in the [queries](queries) should be updated. \ No newline at end of file +in the [migrations](postgres/migrations) folder and the queries in the [queries](postgres/queries) should be updated. +For SQLite, the files are in the [sqlite](sqlite) folder. \ No newline at end of file diff --git a/pkg/server/db/datastore.go b/pkg/server/db/datastore.go new file mode 100644 index 000000000..2ad5863a7 --- /dev/null +++ b/pkg/server/db/datastore.go @@ -0,0 +1,33 @@ +package db + +import ( + "context" + "github.com/HewlettPackard/galadriel/pkg/common/entity" + "github.com/google/uuid" + "github.com/spiffe/go-spiffe/v2/spiffeid" +) + +type Datastore interface { + CreateOrUpdateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*entity.TrustDomain, error) + DeleteTrustDomain(ctx context.Context, trustDomainID uuid.UUID) error + ListTrustDomains(ctx context.Context) ([]*entity.TrustDomain, error) + FindTrustDomainByID(ctx context.Context, trustDomainID uuid.UUID) (*entity.TrustDomain, error) + FindTrustDomainByName(ctx context.Context, trustDomain spiffeid.TrustDomain) (*entity.TrustDomain, error) + CreateOrUpdateBundle(ctx context.Context, req *entity.Bundle) (*entity.Bundle, error) + FindBundleByID(ctx context.Context, bundleID uuid.UUID) (*entity.Bundle, error) + FindBundleByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) (*entity.Bundle, error) + ListBundles(ctx context.Context) ([]*entity.Bundle, error) + DeleteBundle(ctx context.Context, bundleID uuid.UUID) error + CreateJoinToken(ctx context.Context, req *entity.JoinToken) (*entity.JoinToken, error) + FindJoinTokensByID(ctx context.Context, joinTokenID uuid.UUID) (*entity.JoinToken, error) + FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.JoinToken, error) + ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, error) + UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUID, used bool) (*entity.JoinToken, error) + DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUID) error + FindJoinToken(ctx context.Context, token string) (*entity.JoinToken, error) + CreateOrUpdateRelationship(ctx context.Context, req *entity.Relationship) (*entity.Relationship, error) + FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) + FindRelationshipsByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.Relationship, error) + ListRelationships(ctx context.Context) ([]*entity.Relationship, error) + DeleteRelationship(ctx context.Context, relationshipID uuid.UUID) error +} diff --git a/pkg/server/datastore/bundles.sql.go b/pkg/server/db/postgres/bundles.sql.go similarity index 99% rename from pkg/server/datastore/bundles.sql.go rename to pkg/server/db/postgres/bundles.sql.go index 9373b420e..5aa98ff5d 100644 --- a/pkg/server/datastore/bundles.sql.go +++ b/pkg/server/db/postgres/bundles.sql.go @@ -1,9 +1,9 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 // source: bundles.sql -package datastore +package postgres import ( "context" diff --git a/pkg/server/datastore/datastore.go b/pkg/server/db/postgres/datastore.go similarity index 69% rename from pkg/server/datastore/datastore.go rename to pkg/server/db/postgres/datastore.go index e77d2eff3..8cc424483 100644 --- a/pkg/server/datastore/datastore.go +++ b/pkg/server/db/postgres/datastore.go @@ -1,4 +1,4 @@ -package datastore +package postgres import ( "context" @@ -10,47 +10,21 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/stdlib" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spiffe/go-spiffe/v2/spiffeid" ) -type Datastore interface { - CreateOrUpdateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*entity.TrustDomain, error) - DeleteTrustDomain(ctx context.Context, trustDomainID uuid.UUID) error - ListTrustDomains(ctx context.Context) ([]*entity.TrustDomain, error) - FindTrustDomainByID(ctx context.Context, trustDomainID uuid.UUID) (*entity.TrustDomain, error) - FindTrustDomainByName(ctx context.Context, trustDomain spiffeid.TrustDomain) (*entity.TrustDomain, error) - CreateOrUpdateBundle(ctx context.Context, req *entity.Bundle) (*entity.Bundle, error) - FindBundleByID(ctx context.Context, bundleID uuid.UUID) (*entity.Bundle, error) - FindBundleByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) (*entity.Bundle, error) - ListBundles(ctx context.Context) ([]*entity.Bundle, error) - DeleteBundle(ctx context.Context, bundleID uuid.UUID) error - CreateJoinToken(ctx context.Context, req *entity.JoinToken) (*entity.JoinToken, error) - FindJoinTokensByID(ctx context.Context, joinTokenID uuid.UUID) (*entity.JoinToken, error) - FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.JoinToken, error) - ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, error) - UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUID, used bool) (*entity.JoinToken, error) - DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUID) error - FindJoinToken(ctx context.Context, token string) (*entity.JoinToken, error) - CreateOrUpdateRelationship(ctx context.Context, req *entity.Relationship) (*entity.Relationship, error) - FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) - FindRelationshipsByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.Relationship, error) - ListRelationships(ctx context.Context) ([]*entity.Relationship, error) - DeleteRelationship(ctx context.Context, relationshipID uuid.UUID) error -} - -// SQLDatastore is a SQL database accessor that provides convenient methods +// Datastore is a SQL database accessor that provides convenient methods // to perform CRUD operations for Galadriel entities. -type SQLDatastore struct { - logger logrus.FieldLogger +// It implements the Datastore interface. +type Datastore struct { db *sql.DB querier Querier } -// NewSQLDatastore creates a new instance of a Datastore object that connects to a Postgres database +// NewDatastore creates a new instance of a Datastore object that connects to a Postgres database // parsing the connString. // The connString can be a URL, e.g, "postgresql://host...", or a DSN, e.g., "host= user= password= dbname= port=". -func NewSQLDatastore(logger logrus.FieldLogger, connString string) (*SQLDatastore, error) { +func NewDatastore(connString string) (*Datastore, error) { c, err := pgx.ParseConfig(connString) if err != nil { return nil, fmt.Errorf("failed to parse Postgres Connection URL: %w", err) @@ -63,20 +37,19 @@ func NewSQLDatastore(logger logrus.FieldLogger, connString string) (*SQLDatastor return nil, fmt.Errorf("failed to validate or migrate schema: %w", err) } - return &SQLDatastore{ - logger: logger, + return &Datastore{ db: db, querier: New(db), }, nil } -func (d *SQLDatastore) Close() error { +func (d *Datastore) Close() error { return d.db.Close() } -// CreateOrUpdateTrustDomain creates or updates the given TrustDomain in the underlying datastore, based on +// CreateOrUpdateTrustDomain creates or updates the given TrustDomain in the underlying db, based on // whether the given entity has an ID, in which case, it is updated. -func (d *SQLDatastore) CreateOrUpdateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*entity.TrustDomain, error) { +func (d *Datastore) CreateOrUpdateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*entity.TrustDomain, error) { if req.Name.String() == "" { return nil, errors.New("trustDomain trust domain is missing") } @@ -100,58 +73,7 @@ func (d *SQLDatastore) CreateOrUpdateTrustDomain(ctx context.Context, req *entit return response, nil } -func (d *SQLDatastore) createTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { - - params := CreateTrustDomainParams{ - Name: req.Name.String(), - } - if req.Description != "" { - params.Description = sql.NullString{ - String: req.Description, - Valid: true, - } - } - - td, err := d.querier.CreateTrustDomain(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed creating new trust domain: %w", err) - } - return &td, nil -} - -func (d *SQLDatastore) updateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { - pgID, err := uuidToPgType(req.ID.UUID) - if err != nil { - return nil, err - } - - params := UpdateTrustDomainParams{ - ID: pgID, - OnboardingBundle: req.OnboardingBundle, - } - - if req.Description != "" { - params.Description = sql.NullString{ - String: req.Description, - Valid: true, - } - } - - if !req.HarvesterSpiffeID.IsZero() { - params.HarvesterSpiffeID = sql.NullString{ - String: req.HarvesterSpiffeID.String(), - Valid: true, - } - } - - td, err := d.querier.UpdateTrustDomain(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed updating trust domain: %w", err) - } - return &td, nil -} - -func (d *SQLDatastore) DeleteTrustDomain(ctx context.Context, trustDomainID uuid.UUID) error { +func (d *Datastore) DeleteTrustDomain(ctx context.Context, trustDomainID uuid.UUID) error { pgID, err := uuidToPgType(trustDomainID) if err != nil { return err @@ -164,7 +86,7 @@ func (d *SQLDatastore) DeleteTrustDomain(ctx context.Context, trustDomainID uuid return nil } -func (d *SQLDatastore) ListTrustDomains(ctx context.Context) ([]*entity.TrustDomain, error) { +func (d *Datastore) ListTrustDomains(ctx context.Context) ([]*entity.TrustDomain, error) { trustDomains, err := d.querier.ListTrustDomains(ctx) if err != nil { return nil, fmt.Errorf("failed getting trust domain list: %w", err) @@ -182,7 +104,7 @@ func (d *SQLDatastore) ListTrustDomains(ctx context.Context) ([]*entity.TrustDom return result, nil } -func (d *SQLDatastore) FindTrustDomainByID(ctx context.Context, trustDomainID uuid.UUID) (*entity.TrustDomain, error) { +func (d *Datastore) FindTrustDomainByID(ctx context.Context, trustDomainID uuid.UUID) (*entity.TrustDomain, error) { pgID, err := uuidToPgType(trustDomainID) if err != nil { return nil, err @@ -204,7 +126,7 @@ func (d *SQLDatastore) FindTrustDomainByID(ctx context.Context, trustDomainID uu return r, nil } -func (d *SQLDatastore) FindTrustDomainByName(ctx context.Context, name spiffeid.TrustDomain) (*entity.TrustDomain, error) { +func (d *Datastore) FindTrustDomainByName(ctx context.Context, name spiffeid.TrustDomain) (*entity.TrustDomain, error) { trustDomain, err := d.querier.FindTrustDomainByName(ctx, name.String()) switch { case errors.Is(err, sql.ErrNoRows): @@ -221,7 +143,7 @@ func (d *SQLDatastore) FindTrustDomainByName(ctx context.Context, name spiffeid. return r, nil } -func (d *SQLDatastore) CreateOrUpdateBundle(ctx context.Context, req *entity.Bundle) (*entity.Bundle, error) { +func (d *Datastore) CreateOrUpdateBundle(ctx context.Context, req *entity.Bundle) (*entity.Bundle, error) { var bundle *Bundle var err error if req.ID.Valid { @@ -241,55 +163,7 @@ func (d *SQLDatastore) CreateOrUpdateBundle(ctx context.Context, req *entity.Bun return response, nil } -func (d *SQLDatastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { - pgTrustDomainID, err := uuidToPgType(req.TrustDomainID) - if err != nil { - return nil, err - } - params := CreateBundleParams{ - Data: req.Data, - Signature: req.Signature, - SignatureAlgorithm: sql.NullString{ - String: req.SignatureAlgorithm, - Valid: true, - }, - SigningCertificate: req.SigningCertificate, - TrustDomainID: pgTrustDomainID, - } - - bundle, err := d.querier.CreateBundle(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed creating new bundle: %w", err) - } - - return &bundle, nil -} - -func (d *SQLDatastore) updateBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { - pgID, err := uuidToPgType(req.ID.UUID) - if err != nil { - return nil, err - } - params := UpdateBundleParams{ - ID: pgID, - Data: req.Data, - Signature: req.Signature, - SignatureAlgorithm: sql.NullString{ - String: req.SignatureAlgorithm, - Valid: true, - }, - SigningCertificate: req.SigningCertificate, - } - - bundle, err := d.querier.UpdateBundle(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed updating bundle: %w", err) - } - - return &bundle, nil -} - -func (d *SQLDatastore) FindBundleByID(ctx context.Context, bundleID uuid.UUID) (*entity.Bundle, error) { +func (d *Datastore) FindBundleByID(ctx context.Context, bundleID uuid.UUID) (*entity.Bundle, error) { pgID, err := uuidToPgType(bundleID) if err != nil { return nil, err @@ -311,7 +185,7 @@ func (d *SQLDatastore) FindBundleByID(ctx context.Context, bundleID uuid.UUID) ( return b, nil } -func (d *SQLDatastore) FindBundleByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) (*entity.Bundle, error) { +func (d *Datastore) FindBundleByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) (*entity.Bundle, error) { pgID, err := uuidToPgType(trustDomainID) if err != nil { return nil, err @@ -333,7 +207,7 @@ func (d *SQLDatastore) FindBundleByTrustDomainID(ctx context.Context, trustDomai return td, nil } -func (d *SQLDatastore) ListBundles(ctx context.Context) ([]*entity.Bundle, error) { +func (d *Datastore) ListBundles(ctx context.Context) ([]*entity.Bundle, error) { bundles, err := d.querier.ListBundles(ctx) if err != nil { return nil, fmt.Errorf("failed getting bundle list: %w", err) @@ -351,7 +225,7 @@ func (d *SQLDatastore) ListBundles(ctx context.Context) ([]*entity.Bundle, error return result, nil } -func (d *SQLDatastore) DeleteBundle(ctx context.Context, bundleID uuid.UUID) error { +func (d *Datastore) DeleteBundle(ctx context.Context, bundleID uuid.UUID) error { pgID, err := uuidToPgType(bundleID) if err != nil { return err @@ -364,7 +238,7 @@ func (d *SQLDatastore) DeleteBundle(ctx context.Context, bundleID uuid.UUID) err return nil } -func (d *SQLDatastore) CreateJoinToken(ctx context.Context, req *entity.JoinToken) (*entity.JoinToken, error) { +func (d *Datastore) CreateJoinToken(ctx context.Context, req *entity.JoinToken) (*entity.JoinToken, error) { pgID, err := uuidToPgType(req.TrustDomainID) if err != nil { return nil, err @@ -383,7 +257,7 @@ func (d *SQLDatastore) CreateJoinToken(ctx context.Context, req *entity.JoinToke return joinToken.ToEntity(), nil } -func (d *SQLDatastore) FindJoinTokensByID(ctx context.Context, joinTokenID uuid.UUID) (*entity.JoinToken, error) { +func (d *Datastore) FindJoinTokensByID(ctx context.Context, joinTokenID uuid.UUID) (*entity.JoinToken, error) { pgID, err := uuidToPgType(joinTokenID) if err != nil { return nil, err @@ -400,7 +274,7 @@ func (d *SQLDatastore) FindJoinTokensByID(ctx context.Context, joinTokenID uuid. return joinToken.ToEntity(), nil } -func (d *SQLDatastore) FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.JoinToken, error) { +func (d *Datastore) FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.JoinToken, error) { pgID, err := uuidToPgType(trustDomainID) if err != nil { return nil, err @@ -422,7 +296,7 @@ func (d *SQLDatastore) FindJoinTokensByTrustDomainID(ctx context.Context, trustD return result, nil } -func (d *SQLDatastore) ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, error) { +func (d *Datastore) ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, error) { tokens, err := d.querier.ListJoinTokens(ctx) if err != nil { return nil, fmt.Errorf("failed looking up join tokens: %w", err) @@ -436,7 +310,7 @@ func (d *SQLDatastore) ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, return result, nil } -func (d *SQLDatastore) UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUID, used bool) (*entity.JoinToken, error) { +func (d *Datastore) UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUID, used bool) (*entity.JoinToken, error) { pgID, err := uuidToPgType(joinTokenID) if err != nil { return nil, err @@ -455,7 +329,7 @@ func (d *SQLDatastore) UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUI return jt.ToEntity(), nil } -func (d *SQLDatastore) DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUID) error { +func (d *Datastore) DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUID) error { pgID, err := uuidToPgType(joinTokenID) if err != nil { return err @@ -468,7 +342,7 @@ func (d *SQLDatastore) DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUI return nil } -func (d *SQLDatastore) FindJoinToken(ctx context.Context, token string) (*entity.JoinToken, error) { +func (d *Datastore) FindJoinToken(ctx context.Context, token string) (*entity.JoinToken, error) { joinToken, err := d.querier.FindJoinToken(ctx, token) switch { case errors.Is(err, sql.ErrNoRows): @@ -480,7 +354,7 @@ func (d *SQLDatastore) FindJoinToken(ctx context.Context, token string) (*entity return joinToken.ToEntity(), nil } -func (d *SQLDatastore) CreateOrUpdateRelationship(ctx context.Context, req *entity.Relationship) (*entity.Relationship, error) { +func (d *Datastore) CreateOrUpdateRelationship(ctx context.Context, req *entity.Relationship) (*entity.Relationship, error) { var relationship *Relationship var err error if req.ID.Valid { @@ -500,51 +374,7 @@ func (d *SQLDatastore) CreateOrUpdateRelationship(ctx context.Context, req *enti return response, nil } -func (d *SQLDatastore) createRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { - pgTrustDomainAID, err := uuidToPgType(req.TrustDomainAID) - if err != nil { - return nil, err - } - - pgTrustDomainBID, err := uuidToPgType(req.TrustDomainBID) - if err != nil { - return nil, err - } - - params := CreateRelationshipParams{ - TrustDomainAID: pgTrustDomainAID, - TrustDomainBID: pgTrustDomainBID, - } - - relationship, err := d.querier.CreateRelationship(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed creating new relationship: %w", err) - } - - return &relationship, nil -} - -func (d *SQLDatastore) updateRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { - pgID, err := uuidToPgType(req.ID.UUID) - if err != nil { - return nil, err - } - - params := UpdateRelationshipParams{ - ID: pgID, - TrustDomainAConsent: ConsentStatus(req.TrustDomainAConsent), - TrustDomainBConsent: ConsentStatus(req.TrustDomainBConsent), - } - - relationship, err := d.querier.UpdateRelationship(ctx, params) - if err != nil { - return nil, fmt.Errorf("failed updating relationship: %w", err) - } - - return &relationship, nil -} - -func (d *SQLDatastore) FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) { +func (d *Datastore) FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) { pgID, err := uuidToPgType(relationshipID) if err != nil { return nil, err @@ -566,7 +396,7 @@ func (d *SQLDatastore) FindRelationshipByID(ctx context.Context, relationshipID return response, nil } -func (d *SQLDatastore) FindRelationshipsByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.Relationship, error) { +func (d *Datastore) FindRelationshipsByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.Relationship, error) { pgID, err := uuidToPgType(trustDomainID) if err != nil { return nil, err @@ -592,7 +422,7 @@ func (d *SQLDatastore) FindRelationshipsByTrustDomainID(ctx context.Context, tru return result, nil } -func (d *SQLDatastore) ListRelationships(ctx context.Context) ([]*entity.Relationship, error) { +func (d *Datastore) ListRelationships(ctx context.Context) ([]*entity.Relationship, error) { relationships, err := d.querier.ListRelationships(ctx) if err != nil { return nil, fmt.Errorf("failed looking up relationships: %w", err) @@ -610,7 +440,7 @@ func (d *SQLDatastore) ListRelationships(ctx context.Context) ([]*entity.Relatio return result, nil } -func (d *SQLDatastore) DeleteRelationship(ctx context.Context, relationshipID uuid.UUID) error { +func (d *Datastore) DeleteRelationship(ctx context.Context, relationshipID uuid.UUID) error { pgID, err := uuidToPgType(relationshipID) if err != nil { return err @@ -622,3 +452,145 @@ func (d *SQLDatastore) DeleteRelationship(ctx context.Context, relationshipID uu return nil } + +func (d *Datastore) createTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { + params := CreateTrustDomainParams{ + Name: req.Name.String(), + } + if req.Description != "" { + params.Description = sql.NullString{ + String: req.Description, + Valid: true, + } + } + + td, err := d.querier.CreateTrustDomain(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new trust domain: %w", err) + } + return &td, nil +} + +func (d *Datastore) updateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { + pgID, err := uuidToPgType(req.ID.UUID) + if err != nil { + return nil, err + } + + params := UpdateTrustDomainParams{ + ID: pgID, + OnboardingBundle: req.OnboardingBundle, + } + + if req.Description != "" { + params.Description = sql.NullString{ + String: req.Description, + Valid: true, + } + } + + if !req.HarvesterSpiffeID.IsZero() { + params.HarvesterSpiffeID = sql.NullString{ + String: req.HarvesterSpiffeID.String(), + Valid: true, + } + } + + td, err := d.querier.UpdateTrustDomain(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating trust domain: %w", err) + } + return &td, nil +} + +func (d *Datastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { + pgTrustDomainID, err := uuidToPgType(req.TrustDomainID) + if err != nil { + return nil, err + } + params := CreateBundleParams{ + Data: req.Data, + Signature: req.Signature, + SignatureAlgorithm: sql.NullString{ + String: req.SignatureAlgorithm, + Valid: true, + }, + SigningCertificate: req.SigningCertificate, + TrustDomainID: pgTrustDomainID, + } + + bundle, err := d.querier.CreateBundle(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new bundle: %w", err) + } + + return &bundle, nil +} + +func (d *Datastore) updateBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { + pgID, err := uuidToPgType(req.ID.UUID) + if err != nil { + return nil, err + } + params := UpdateBundleParams{ + ID: pgID, + Data: req.Data, + Signature: req.Signature, + SignatureAlgorithm: sql.NullString{ + String: req.SignatureAlgorithm, + Valid: true, + }, + SigningCertificate: req.SigningCertificate, + } + + bundle, err := d.querier.UpdateBundle(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating bundle: %w", err) + } + + return &bundle, nil +} + +func (d *Datastore) createRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { + pgTrustDomainAID, err := uuidToPgType(req.TrustDomainAID) + if err != nil { + return nil, err + } + + pgTrustDomainBID, err := uuidToPgType(req.TrustDomainBID) + if err != nil { + return nil, err + } + + params := CreateRelationshipParams{ + TrustDomainAID: pgTrustDomainAID, + TrustDomainBID: pgTrustDomainBID, + } + + relationship, err := d.querier.CreateRelationship(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new relationship: %w", err) + } + + return &relationship, nil +} + +func (d *Datastore) updateRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { + pgID, err := uuidToPgType(req.ID.UUID) + if err != nil { + return nil, err + } + + params := UpdateRelationshipParams{ + ID: pgID, + TrustDomainAConsent: ConsentStatus(req.TrustDomainAConsent), + TrustDomainBConsent: ConsentStatus(req.TrustDomainBConsent), + } + + relationship, err := d.querier.UpdateRelationship(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating relationship: %w", err) + } + + return &relationship, nil +} diff --git a/pkg/server/datastore/db.go b/pkg/server/db/postgres/db.gen.go similarity index 99% rename from pkg/server/datastore/db.go rename to pkg/server/db/postgres/db.gen.go index cc64e64af..287cefc40 100644 --- a/pkg/server/datastore/db.go +++ b/pkg/server/db/postgres/db.gen.go @@ -1,8 +1,8 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 -package datastore +package postgres import ( "context" diff --git a/pkg/server/datastore/helpers.go b/pkg/server/db/postgres/helpers.go similarity index 99% rename from pkg/server/datastore/helpers.go rename to pkg/server/db/postgres/helpers.go index 03a6ecc9b..bec6a7ed6 100644 --- a/pkg/server/datastore/helpers.go +++ b/pkg/server/db/postgres/helpers.go @@ -1,4 +1,4 @@ -package datastore +package postgres import ( "fmt" diff --git a/pkg/server/datastore/join_tokens.sql.go b/pkg/server/db/postgres/join_tokens.sql.go similarity index 99% rename from pkg/server/datastore/join_tokens.sql.go rename to pkg/server/db/postgres/join_tokens.sql.go index 057ca0f83..8cf9e3d66 100644 --- a/pkg/server/datastore/join_tokens.sql.go +++ b/pkg/server/db/postgres/join_tokens.sql.go @@ -1,9 +1,9 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 // source: join_tokens.sql -package datastore +package postgres import ( "context" diff --git a/pkg/server/datastore/migrations/1_initialize_schema.down.sql b/pkg/server/db/postgres/migrations/1_initialize_schema.down.sql similarity index 100% rename from pkg/server/datastore/migrations/1_initialize_schema.down.sql rename to pkg/server/db/postgres/migrations/1_initialize_schema.down.sql diff --git a/pkg/server/datastore/migrations/1_initialize_schema.up.sql b/pkg/server/db/postgres/migrations/1_initialize_schema.up.sql similarity index 100% rename from pkg/server/datastore/migrations/1_initialize_schema.up.sql rename to pkg/server/db/postgres/migrations/1_initialize_schema.up.sql diff --git a/pkg/server/datastore/models.go b/pkg/server/db/postgres/models.gen.go similarity index 98% rename from pkg/server/datastore/models.go rename to pkg/server/db/postgres/models.gen.go index de5a3632a..4efcd7062 100644 --- a/pkg/server/datastore/models.go +++ b/pkg/server/db/postgres/models.gen.go @@ -1,8 +1,8 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 -package datastore +package postgres import ( "database/sql" diff --git a/pkg/server/datastore/querier.go b/pkg/server/db/postgres/querier.gen.go similarity index 98% rename from pkg/server/datastore/querier.go rename to pkg/server/db/postgres/querier.gen.go index 4c33b49e8..43262ffb1 100644 --- a/pkg/server/datastore/querier.go +++ b/pkg/server/db/postgres/querier.gen.go @@ -1,8 +1,8 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 -package datastore +package postgres import ( "context" diff --git a/pkg/server/datastore/queries/bundles.sql b/pkg/server/db/postgres/queries/bundles.sql similarity index 100% rename from pkg/server/datastore/queries/bundles.sql rename to pkg/server/db/postgres/queries/bundles.sql diff --git a/pkg/server/datastore/queries/join_tokens.sql b/pkg/server/db/postgres/queries/join_tokens.sql similarity index 100% rename from pkg/server/datastore/queries/join_tokens.sql rename to pkg/server/db/postgres/queries/join_tokens.sql diff --git a/pkg/server/datastore/queries/relationships.sql b/pkg/server/db/postgres/queries/relationships.sql similarity index 100% rename from pkg/server/datastore/queries/relationships.sql rename to pkg/server/db/postgres/queries/relationships.sql diff --git a/pkg/server/datastore/queries/trust_domains.sql b/pkg/server/db/postgres/queries/trust_domains.sql similarity index 100% rename from pkg/server/datastore/queries/trust_domains.sql rename to pkg/server/db/postgres/queries/trust_domains.sql diff --git a/pkg/server/datastore/relationships.sql.go b/pkg/server/db/postgres/relationships.sql.go similarity index 99% rename from pkg/server/datastore/relationships.sql.go rename to pkg/server/db/postgres/relationships.sql.go index be571bb64..b765451b0 100644 --- a/pkg/server/datastore/relationships.sql.go +++ b/pkg/server/db/postgres/relationships.sql.go @@ -1,9 +1,9 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 // source: relationships.sql -package datastore +package postgres import ( "context" diff --git a/pkg/server/datastore/schema.go b/pkg/server/db/postgres/schema.go similarity index 98% rename from pkg/server/datastore/schema.go rename to pkg/server/db/postgres/schema.go index b8d02a7ab..c364d6847 100644 --- a/pkg/server/datastore/schema.go +++ b/pkg/server/db/postgres/schema.go @@ -1,4 +1,4 @@ -package datastore +package postgres import ( "database/sql" diff --git a/pkg/server/datastore/trust_domains.sql.go b/pkg/server/db/postgres/trust_domains.sql.go similarity index 99% rename from pkg/server/datastore/trust_domains.sql.go rename to pkg/server/db/postgres/trust_domains.sql.go index b811d4f77..2ef198c4b 100644 --- a/pkg/server/datastore/trust_domains.sql.go +++ b/pkg/server/db/postgres/trust_domains.sql.go @@ -1,9 +1,9 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.17.0 +// sqlc v1.18.0 // source: trust_domains.sql -package datastore +package postgres import ( "context" diff --git a/pkg/server/db/sqlc.yaml b/pkg/server/db/sqlc.yaml new file mode 100644 index 000000000..415a266f1 --- /dev/null +++ b/pkg/server/db/sqlc.yaml @@ -0,0 +1,30 @@ +version: "1" +packages: + - name: "postgres" + path: "postgres" + queries: "postgres/queries" + schema: "postgres/migrations" + engine: "postgresql" + emit_json_tags: false + emit_prepared_queries: true + emit_interface: true + emit_exact_table_names: false + output_db_file_name: "db.gen.go" + output_models_file_name: "models.gen.go" + output_querier_file_name: "querier.gen.go" + - name: "sqlite" + path: "sqlite" + queries: "sqlite/queries" + schema: "sqlite/migrations" + engine: "sqlite" + emit_json_tags: false + emit_prepared_queries: true + emit_interface: true + emit_exact_table_names: false + output_db_file_name: "db.gen.go" + output_models_file_name: "models.gen.go" + output_querier_file_name: "querier.gen.go" +overrides: + - go_type: "github.com/jackc/pgtype.UUID" + db_type: "uuid" + engine: "postgresql" diff --git a/pkg/server/db/sqlite/bundles.sql.go b/pkg/server/db/sqlite/bundles.sql.go new file mode 100644 index 000000000..a003e60f7 --- /dev/null +++ b/pkg/server/db/sqlite/bundles.sql.go @@ -0,0 +1,184 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: bundles.sql + +package sqlite + +import ( + "context" + "database/sql" +) + +const createBundle = `-- name: CreateBundle :one +INSERT INTO bundles(id, data, signature, signature_algorithm, signing_certificate, trust_domain_id) +VALUES (?, ?, ?, ?, ?, ?) +RETURNING id, trust_domain_id, data, signature, signature_algorithm, signing_certificate, created_at, updated_at +` + +type CreateBundleParams struct { + ID string + Data []byte + Signature []byte + SignatureAlgorithm sql.NullString + SigningCertificate []byte + TrustDomainID string +} + +func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bundle, error) { + row := q.queryRow(ctx, q.createBundleStmt, createBundle, + arg.ID, + arg.Data, + arg.Signature, + arg.SignatureAlgorithm, + arg.SigningCertificate, + arg.TrustDomainID, + ) + var i Bundle + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Data, + &i.Signature, + &i.SignatureAlgorithm, + &i.SigningCertificate, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteBundle = `-- name: DeleteBundle :exec +DELETE +FROM bundles +WHERE id = ? +` + +func (q *Queries) DeleteBundle(ctx context.Context, id string) error { + _, err := q.exec(ctx, q.deleteBundleStmt, deleteBundle, id) + return err +} + +const findBundleByID = `-- name: FindBundleByID :one +SELECT id, trust_domain_id, data, signature, signature_algorithm, signing_certificate, created_at, updated_at +FROM bundles +WHERE id = ? +` + +func (q *Queries) FindBundleByID(ctx context.Context, id string) (Bundle, error) { + row := q.queryRow(ctx, q.findBundleByIDStmt, findBundleByID, id) + var i Bundle + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Data, + &i.Signature, + &i.SignatureAlgorithm, + &i.SigningCertificate, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const findBundleByTrustDomainID = `-- name: FindBundleByTrustDomainID :one +SELECT id, trust_domain_id, data, signature, signature_algorithm, signing_certificate, created_at, updated_at +FROM bundles +WHERE trust_domain_id = ? +LIMIT 1 +` + +func (q *Queries) FindBundleByTrustDomainID(ctx context.Context, trustDomainID string) (Bundle, error) { + row := q.queryRow(ctx, q.findBundleByTrustDomainIDStmt, findBundleByTrustDomainID, trustDomainID) + var i Bundle + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Data, + &i.Signature, + &i.SignatureAlgorithm, + &i.SigningCertificate, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const listBundles = `-- name: ListBundles :many +SELECT id, trust_domain_id, data, signature, signature_algorithm, signing_certificate, created_at, updated_at +FROM bundles +ORDER BY created_at DESC +` + +func (q *Queries) ListBundles(ctx context.Context) ([]Bundle, error) { + rows, err := q.query(ctx, q.listBundlesStmt, listBundles) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bundle + for rows.Next() { + var i Bundle + if err := rows.Scan( + &i.ID, + &i.TrustDomainID, + &i.Data, + &i.Signature, + &i.SignatureAlgorithm, + &i.SigningCertificate, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateBundle = `-- name: UpdateBundle :one +UPDATE bundles +SET data = ?, + signature = ?, + signature_algorithm = ?, + signing_certificate = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING id, trust_domain_id, data, signature, signature_algorithm, signing_certificate, created_at, updated_at +` + +type UpdateBundleParams struct { + Data []byte + Signature []byte + SignatureAlgorithm sql.NullString + SigningCertificate []byte + ID string +} + +func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bundle, error) { + row := q.queryRow(ctx, q.updateBundleStmt, updateBundle, + arg.Data, + arg.Signature, + arg.SignatureAlgorithm, + arg.SigningCertificate, + arg.ID, + ) + var i Bundle + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Data, + &i.Signature, + &i.SignatureAlgorithm, + &i.SigningCertificate, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/pkg/server/db/sqlite/datastore.go b/pkg/server/db/sqlite/datastore.go new file mode 100644 index 000000000..dc1859afe --- /dev/null +++ b/pkg/server/db/sqlite/datastore.go @@ -0,0 +1,551 @@ +package sqlite + +import ( + "context" + "database/sql" + "fmt" + + "github.com/HewlettPackard/galadriel/pkg/common/entity" + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/pkg/errors" + "github.com/spiffe/go-spiffe/v2/spiffeid" +) + +// Datastore is a SQL database accessor that provides convenient methods +// to perform CRUD operations for Galadriel entities. +// It implements the Datastore interface. +type Datastore struct { + db *sql.DB + querier Querier +} + +// NewDatastore creates a new instance of a Datastore object that connects to an SQLite database +// parsing the connString. +// The connString should be a file path to the SQLite database file. +func NewDatastore(connString string) (*Datastore, error) { + db, err := sql.Open("sqlite3", connString) + if err != nil { + return nil, fmt.Errorf("failed to open SQLite database: %w", err) + } + + // enable foreign key constraint enforcement + _, err = db.Exec("PRAGMA foreign_keys = ON;") + if err != nil { + return nil, fmt.Errorf("failed to enable foreign key constraint enforcement: %w", err) + } + + // validates if the schema in the DB matches the schema supported by the app, and runs the migrations if needed + if err = validateAndMigrateSchema(db); err != nil { + return nil, fmt.Errorf("failed to validate or migrate schema: %w", err) + } + + return &Datastore{ + db: db, + querier: New(db), + }, nil +} + +func (d *Datastore) Close() error { + return d.db.Close() +} + +// CreateOrUpdateTrustDomain creates or updates the given TrustDomain in the underlying db, based on +// whether the given entity has an ID, in which case, it is updated. +func (d *Datastore) CreateOrUpdateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*entity.TrustDomain, error) { + if req.Name.String() == "" { + return nil, errors.New("trustDomain trust domain is missing") + } + + var trustDomain *TrustDomain + var err error + if req.ID.Valid { + trustDomain, err = d.updateTrustDomain(ctx, req) + } else { + trustDomain, err = d.createTrustDomain(ctx, req) + } + if err != nil { + return nil, err + } + + response, err := trustDomain.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting trustDomain model to entity: %w", err) + } + + return response, nil +} + +func (d *Datastore) DeleteTrustDomain(ctx context.Context, trustDomainID uuid.UUID) error { + if err := d.querier.DeleteTrustDomain(ctx, trustDomainID.String()); err != nil { + return fmt.Errorf("failed deleting trust domain with ID=%q: %w", trustDomainID, err) + } + + return nil +} + +func (d *Datastore) ListTrustDomains(ctx context.Context) ([]*entity.TrustDomain, error) { + trustDomains, err := d.querier.ListTrustDomains(ctx) + if err != nil { + return nil, fmt.Errorf("failed getting trust domain list: %w", err) + } + + result := make([]*entity.TrustDomain, len(trustDomains)) + for i, m := range trustDomains { + r, err := m.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model trust domain to entity: %v", err) + } + result[i] = r + } + + return result, nil +} + +func (d *Datastore) FindTrustDomainByID(ctx context.Context, trustDomainID uuid.UUID) (*entity.TrustDomain, error) { + m, err := d.querier.FindTrustDomainByID(ctx, trustDomainID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up trust domain for ID=%q: %w", trustDomainID, err) + } + + r, err := m.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model trust domain to entity: %w", err) + } + + return r, nil +} + +func (d *Datastore) FindTrustDomainByName(ctx context.Context, name spiffeid.TrustDomain) (*entity.TrustDomain, error) { + trustDomain, err := d.querier.FindTrustDomainByName(ctx, name.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up trust domain for Trust Domain=%q: %w", name, err) + } + + r, err := trustDomain.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model trust domain to entity: %w", err) + } + + return r, nil +} + +func (d *Datastore) CreateOrUpdateBundle(ctx context.Context, req *entity.Bundle) (*entity.Bundle, error) { + var bundle *Bundle + var err error + if req.ID.Valid { + bundle, err = d.updateBundle(ctx, req) + } else { + bundle, err = d.createBundle(ctx, req) + } + if err != nil { + return nil, err + } + + response, err := bundle.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting trust domain model to entity: %w", err) + } + + return response, nil +} + +func (d *Datastore) FindBundleByID(ctx context.Context, bundleID uuid.UUID) (*entity.Bundle, error) { + bundle, err := d.querier.FindBundleByID(ctx, bundleID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up bundle with ID=%q: %w", bundleID, err) + } + + b, err := bundle.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model bundle to entity: %w", err) + } + + return b, nil +} + +func (d *Datastore) FindBundleByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) (*entity.Bundle, error) { + trustDomain, err := d.querier.FindBundleByTrustDomainID(ctx, trustDomainID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up bundle for ID=%q: %w", trustDomainID, err) + } + + td, err := trustDomain.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model bundle to entity: %w", err) + } + + return td, nil +} + +func (d *Datastore) ListBundles(ctx context.Context) ([]*entity.Bundle, error) { + bundles, err := d.querier.ListBundles(ctx) + if err != nil { + return nil, fmt.Errorf("failed getting bundle list: %w", err) + } + + result := make([]*entity.Bundle, len(bundles)) + for i, m := range bundles { + r, err := m.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model bundle to entity: %w", err) + } + result[i] = r + } + + return result, nil +} + +func (d *Datastore) DeleteBundle(ctx context.Context, bundleID uuid.UUID) error { + if err := d.querier.DeleteBundle(ctx, bundleID.String()); err != nil { + return fmt.Errorf("failed deleting bundle with ID=%q: %w", bundleID, err) + } + + return nil +} + +func (d *Datastore) CreateJoinToken(ctx context.Context, req *entity.JoinToken) (*entity.JoinToken, error) { + id := uuid.New() + params := CreateJoinTokenParams{ + ID: id.String(), + Token: req.Token, + ExpiresAt: req.ExpiresAt, + TrustDomainID: req.TrustDomainID.String(), + } + joinToken, err := d.querier.CreateJoinToken(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating join token: %w", err) + } + + ent, err := joinToken.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + + return ent, nil +} + +func (d *Datastore) FindJoinTokensByID(ctx context.Context, joinTokenID uuid.UUID) (*entity.JoinToken, error) { + joinToken, err := d.querier.FindJoinTokenByID(ctx, joinTokenID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up join token with ID=%q: %w", joinTokenID, err) + } + + ent, err := joinToken.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + + return ent, nil +} + +func (d *Datastore) FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.JoinToken, error) { + tokens, err := d.querier.FindJoinTokensByTrustDomainID(ctx, trustDomainID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up join token for Name ID=%q: %w", trustDomainID, err) + } + + result := make([]*entity.JoinToken, len(tokens)) + for i, t := range tokens { + ent, err := t.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + result[i] = ent + } + + return result, nil +} + +func (d *Datastore) ListJoinTokens(ctx context.Context) ([]*entity.JoinToken, error) { + tokens, err := d.querier.ListJoinTokens(ctx) + if err != nil { + return nil, fmt.Errorf("failed looking up join tokens: %w", err) + } + + result := make([]*entity.JoinToken, len(tokens)) + for i, t := range tokens { + ent, err := t.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + result[i] = ent + } + + return result, nil +} + +func (d *Datastore) UpdateJoinToken(ctx context.Context, joinTokenID uuid.UUID, used bool) (*entity.JoinToken, error) { + params := UpdateJoinTokenParams{ + ID: joinTokenID.String(), + Used: used, + } + + jt, err := d.querier.UpdateJoinToken(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating join token with ID=%q, %w", joinTokenID, err) + } + + ent, err := jt.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + + return ent, nil +} + +func (d *Datastore) DeleteJoinToken(ctx context.Context, joinTokenID uuid.UUID) error { + if err := d.querier.DeleteJoinToken(ctx, joinTokenID.String()); err != nil { + return fmt.Errorf("failed deleting join token with ID=%q, %w", joinTokenID, err) + } + + return nil +} + +func (d *Datastore) FindJoinToken(ctx context.Context, token string) (*entity.JoinToken, error) { + joinToken, err := d.querier.FindJoinToken(ctx, token) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up join token: %w", err) + } + + ent, err := joinToken.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting model join token to entity: %w", err) + } + + return ent, nil +} + +func (d *Datastore) CreateOrUpdateRelationship(ctx context.Context, req *entity.Relationship) (*entity.Relationship, error) { + var relationship *Relationship + var err error + if req.ID.Valid { + relationship, err = d.updateRelationship(ctx, req) + } else { + relationship, err = d.createRelationship(ctx, req) + } + if err != nil { + return nil, err + } + + response, err := relationship.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting relationship model to entity: %w", err) + } + + return response, nil +} + +func (d *Datastore) FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) { + relationship, err := d.querier.FindRelationshipByID(ctx, relationshipID.String()) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up relationship for ID=%q: %w", relationshipID, err) + } + + response, err := relationship.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting relationship model to entity: %w", err) + } + + return response, nil +} + +func (d *Datastore) FindRelationshipsByTrustDomainID(ctx context.Context, trustDomainID uuid.UUID) ([]*entity.Relationship, error) { + params := FindRelationshipsByTrustDomainIDParams{ + TrustDomainAID: trustDomainID.String(), + TrustDomainBID: trustDomainID.String(), + } + relationships, err := d.querier.FindRelationshipsByTrustDomainID(ctx, params) + switch { + case errors.Is(err, sql.ErrNoRows): + return nil, nil + case err != nil: + return nil, fmt.Errorf("failed looking up relationships for TrustDomainID %q: %w", trustDomainID, err) + } + + result := make([]*entity.Relationship, len(relationships)) + for i, m := range relationships { + ent, err := m.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting relationship model to entity: %w", err) + } + result[i] = ent + } + + return result, nil +} + +func (d *Datastore) ListRelationships(ctx context.Context) ([]*entity.Relationship, error) { + relationships, err := d.querier.ListRelationships(ctx) + if err != nil { + return nil, fmt.Errorf("failed looking up relationships: %w", err) + } + + result := make([]*entity.Relationship, len(relationships)) + for i, m := range relationships { + ent, err := m.ToEntity() + if err != nil { + return nil, fmt.Errorf("failed converting relationship model to entity: %w", err) + } + result[i] = ent + } + + return result, nil +} + +func (d *Datastore) DeleteRelationship(ctx context.Context, relationshipID uuid.UUID) error { + if err := d.querier.DeleteRelationship(ctx, relationshipID.String()); err != nil { + return fmt.Errorf("failed deleting relationship ID=%q: %w", relationshipID, err) + } + + return nil +} + +func (d *Datastore) createTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { + id := uuid.New() + params := CreateTrustDomainParams{ + ID: id.String(), + Name: req.Name.String(), + } + if req.Description != "" { + params.Description = sql.NullString{ + String: req.Description, + Valid: true, + } + } else { + params.Description = sql.NullString{ + String: "", + Valid: false, + } + } + + td, err := d.querier.CreateTrustDomain(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new trust domain: %w", err) + } + return &td, nil +} + +func (d *Datastore) updateTrustDomain(ctx context.Context, req *entity.TrustDomain) (*TrustDomain, error) { + params := UpdateTrustDomainParams{ + ID: req.ID.UUID.String(), + OnboardingBundle: req.OnboardingBundle, + } + + if req.Description != "" { + params.Description = sql.NullString{ + String: req.Description, + Valid: true, + } + } + + if !req.HarvesterSpiffeID.IsZero() { + params.HarvesterSpiffeID = sql.NullString{ + String: req.HarvesterSpiffeID.String(), + Valid: true, + } + } + + td, err := d.querier.UpdateTrustDomain(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating trust domain: %w", err) + } + return &td, nil +} + +func (d *Datastore) createRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { + id := uuid.New() + params := CreateRelationshipParams{ + ID: id.String(), + TrustDomainAID: req.TrustDomainAID.String(), + TrustDomainBID: req.TrustDomainBID.String(), + } + + relationship, err := d.querier.CreateRelationship(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new relationship: %w", err) + } + + return &relationship, nil +} + +func (d *Datastore) updateRelationship(ctx context.Context, req *entity.Relationship) (*Relationship, error) { + params := UpdateRelationshipParams{ + ID: req.ID.UUID.String(), + TrustDomainAConsent: string(req.TrustDomainAConsent), + TrustDomainBConsent: string(req.TrustDomainBConsent), + } + + relationship, err := d.querier.UpdateRelationship(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating relationship: %w", err) + } + + return &relationship, nil +} + +func (d *Datastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { + id := uuid.New() + params := CreateBundleParams{ + ID: id.String(), + Data: req.Data, + Signature: req.Signature, + SignatureAlgorithm: sql.NullString{ + String: req.SignatureAlgorithm, + Valid: true, + }, + SigningCertificate: req.SigningCertificate, + TrustDomainID: req.TrustDomainID.String(), + } + + bundle, err := d.querier.CreateBundle(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed creating new bundle: %w", err) + } + + return &bundle, nil +} + +func (d *Datastore) updateBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { + params := UpdateBundleParams{ + ID: req.ID.UUID.String(), + Data: req.Data, + Signature: req.Signature, + SignatureAlgorithm: sql.NullString{ + String: req.SignatureAlgorithm, + Valid: true, + }, + SigningCertificate: req.SigningCertificate, + } + + bundle, err := d.querier.UpdateBundle(ctx, params) + if err != nil { + return nil, fmt.Errorf("failed updating bundle: %w", err) + } + + return &bundle, nil +} diff --git a/pkg/server/db/sqlite/db.gen.go b/pkg/server/db/sqlite/db.gen.go new file mode 100644 index 000000000..f82055d7b --- /dev/null +++ b/pkg/server/db/sqlite/db.gen.go @@ -0,0 +1,328 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 + +package sqlite + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createBundleStmt, err = db.PrepareContext(ctx, createBundle); err != nil { + return nil, fmt.Errorf("error preparing query CreateBundle: %w", err) + } + if q.createJoinTokenStmt, err = db.PrepareContext(ctx, createJoinToken); err != nil { + return nil, fmt.Errorf("error preparing query CreateJoinToken: %w", err) + } + if q.createRelationshipStmt, err = db.PrepareContext(ctx, createRelationship); err != nil { + return nil, fmt.Errorf("error preparing query CreateRelationship: %w", err) + } + if q.createTrustDomainStmt, err = db.PrepareContext(ctx, createTrustDomain); err != nil { + return nil, fmt.Errorf("error preparing query CreateTrustDomain: %w", err) + } + if q.deleteBundleStmt, err = db.PrepareContext(ctx, deleteBundle); err != nil { + return nil, fmt.Errorf("error preparing query DeleteBundle: %w", err) + } + if q.deleteJoinTokenStmt, err = db.PrepareContext(ctx, deleteJoinToken); err != nil { + return nil, fmt.Errorf("error preparing query DeleteJoinToken: %w", err) + } + if q.deleteRelationshipStmt, err = db.PrepareContext(ctx, deleteRelationship); err != nil { + return nil, fmt.Errorf("error preparing query DeleteRelationship: %w", err) + } + if q.deleteTrustDomainStmt, err = db.PrepareContext(ctx, deleteTrustDomain); err != nil { + return nil, fmt.Errorf("error preparing query DeleteTrustDomain: %w", err) + } + if q.findBundleByIDStmt, err = db.PrepareContext(ctx, findBundleByID); err != nil { + return nil, fmt.Errorf("error preparing query FindBundleByID: %w", err) + } + if q.findBundleByTrustDomainIDStmt, err = db.PrepareContext(ctx, findBundleByTrustDomainID); err != nil { + return nil, fmt.Errorf("error preparing query FindBundleByTrustDomainID: %w", err) + } + if q.findJoinTokenStmt, err = db.PrepareContext(ctx, findJoinToken); err != nil { + return nil, fmt.Errorf("error preparing query FindJoinToken: %w", err) + } + if q.findJoinTokenByIDStmt, err = db.PrepareContext(ctx, findJoinTokenByID); err != nil { + return nil, fmt.Errorf("error preparing query FindJoinTokenByID: %w", err) + } + if q.findJoinTokensByTrustDomainIDStmt, err = db.PrepareContext(ctx, findJoinTokensByTrustDomainID); err != nil { + return nil, fmt.Errorf("error preparing query FindJoinTokensByTrustDomainID: %w", err) + } + if q.findRelationshipByIDStmt, err = db.PrepareContext(ctx, findRelationshipByID); err != nil { + return nil, fmt.Errorf("error preparing query FindRelationshipByID: %w", err) + } + if q.findRelationshipsByTrustDomainIDStmt, err = db.PrepareContext(ctx, findRelationshipsByTrustDomainID); err != nil { + return nil, fmt.Errorf("error preparing query FindRelationshipsByTrustDomainID: %w", err) + } + if q.findTrustDomainByIDStmt, err = db.PrepareContext(ctx, findTrustDomainByID); err != nil { + return nil, fmt.Errorf("error preparing query FindTrustDomainByID: %w", err) + } + if q.findTrustDomainByNameStmt, err = db.PrepareContext(ctx, findTrustDomainByName); err != nil { + return nil, fmt.Errorf("error preparing query FindTrustDomainByName: %w", err) + } + if q.listBundlesStmt, err = db.PrepareContext(ctx, listBundles); err != nil { + return nil, fmt.Errorf("error preparing query ListBundles: %w", err) + } + if q.listJoinTokensStmt, err = db.PrepareContext(ctx, listJoinTokens); err != nil { + return nil, fmt.Errorf("error preparing query ListJoinTokens: %w", err) + } + if q.listRelationshipsStmt, err = db.PrepareContext(ctx, listRelationships); err != nil { + return nil, fmt.Errorf("error preparing query ListRelationships: %w", err) + } + if q.listTrustDomainsStmt, err = db.PrepareContext(ctx, listTrustDomains); err != nil { + return nil, fmt.Errorf("error preparing query ListTrustDomains: %w", err) + } + if q.updateBundleStmt, err = db.PrepareContext(ctx, updateBundle); err != nil { + return nil, fmt.Errorf("error preparing query UpdateBundle: %w", err) + } + if q.updateJoinTokenStmt, err = db.PrepareContext(ctx, updateJoinToken); err != nil { + return nil, fmt.Errorf("error preparing query UpdateJoinToken: %w", err) + } + if q.updateRelationshipStmt, err = db.PrepareContext(ctx, updateRelationship); err != nil { + return nil, fmt.Errorf("error preparing query UpdateRelationship: %w", err) + } + if q.updateTrustDomainStmt, err = db.PrepareContext(ctx, updateTrustDomain); err != nil { + return nil, fmt.Errorf("error preparing query UpdateTrustDomain: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createBundleStmt != nil { + if cerr := q.createBundleStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createBundleStmt: %w", cerr) + } + } + if q.createJoinTokenStmt != nil { + if cerr := q.createJoinTokenStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createJoinTokenStmt: %w", cerr) + } + } + if q.createRelationshipStmt != nil { + if cerr := q.createRelationshipStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createRelationshipStmt: %w", cerr) + } + } + if q.createTrustDomainStmt != nil { + if cerr := q.createTrustDomainStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createTrustDomainStmt: %w", cerr) + } + } + if q.deleteBundleStmt != nil { + if cerr := q.deleteBundleStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteBundleStmt: %w", cerr) + } + } + if q.deleteJoinTokenStmt != nil { + if cerr := q.deleteJoinTokenStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteJoinTokenStmt: %w", cerr) + } + } + if q.deleteRelationshipStmt != nil { + if cerr := q.deleteRelationshipStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteRelationshipStmt: %w", cerr) + } + } + if q.deleteTrustDomainStmt != nil { + if cerr := q.deleteTrustDomainStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteTrustDomainStmt: %w", cerr) + } + } + if q.findBundleByIDStmt != nil { + if cerr := q.findBundleByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findBundleByIDStmt: %w", cerr) + } + } + if q.findBundleByTrustDomainIDStmt != nil { + if cerr := q.findBundleByTrustDomainIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findBundleByTrustDomainIDStmt: %w", cerr) + } + } + if q.findJoinTokenStmt != nil { + if cerr := q.findJoinTokenStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findJoinTokenStmt: %w", cerr) + } + } + if q.findJoinTokenByIDStmt != nil { + if cerr := q.findJoinTokenByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findJoinTokenByIDStmt: %w", cerr) + } + } + if q.findJoinTokensByTrustDomainIDStmt != nil { + if cerr := q.findJoinTokensByTrustDomainIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findJoinTokensByTrustDomainIDStmt: %w", cerr) + } + } + if q.findRelationshipByIDStmt != nil { + if cerr := q.findRelationshipByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findRelationshipByIDStmt: %w", cerr) + } + } + if q.findRelationshipsByTrustDomainIDStmt != nil { + if cerr := q.findRelationshipsByTrustDomainIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findRelationshipsByTrustDomainIDStmt: %w", cerr) + } + } + if q.findTrustDomainByIDStmt != nil { + if cerr := q.findTrustDomainByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findTrustDomainByIDStmt: %w", cerr) + } + } + if q.findTrustDomainByNameStmt != nil { + if cerr := q.findTrustDomainByNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing findTrustDomainByNameStmt: %w", cerr) + } + } + if q.listBundlesStmt != nil { + if cerr := q.listBundlesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listBundlesStmt: %w", cerr) + } + } + if q.listJoinTokensStmt != nil { + if cerr := q.listJoinTokensStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listJoinTokensStmt: %w", cerr) + } + } + if q.listRelationshipsStmt != nil { + if cerr := q.listRelationshipsStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listRelationshipsStmt: %w", cerr) + } + } + if q.listTrustDomainsStmt != nil { + if cerr := q.listTrustDomainsStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listTrustDomainsStmt: %w", cerr) + } + } + if q.updateBundleStmt != nil { + if cerr := q.updateBundleStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateBundleStmt: %w", cerr) + } + } + if q.updateJoinTokenStmt != nil { + if cerr := q.updateJoinTokenStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateJoinTokenStmt: %w", cerr) + } + } + if q.updateRelationshipStmt != nil { + if cerr := q.updateRelationshipStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateRelationshipStmt: %w", cerr) + } + } + if q.updateTrustDomainStmt != nil { + if cerr := q.updateTrustDomainStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateTrustDomainStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createBundleStmt *sql.Stmt + createJoinTokenStmt *sql.Stmt + createRelationshipStmt *sql.Stmt + createTrustDomainStmt *sql.Stmt + deleteBundleStmt *sql.Stmt + deleteJoinTokenStmt *sql.Stmt + deleteRelationshipStmt *sql.Stmt + deleteTrustDomainStmt *sql.Stmt + findBundleByIDStmt *sql.Stmt + findBundleByTrustDomainIDStmt *sql.Stmt + findJoinTokenStmt *sql.Stmt + findJoinTokenByIDStmt *sql.Stmt + findJoinTokensByTrustDomainIDStmt *sql.Stmt + findRelationshipByIDStmt *sql.Stmt + findRelationshipsByTrustDomainIDStmt *sql.Stmt + findTrustDomainByIDStmt *sql.Stmt + findTrustDomainByNameStmt *sql.Stmt + listBundlesStmt *sql.Stmt + listJoinTokensStmt *sql.Stmt + listRelationshipsStmt *sql.Stmt + listTrustDomainsStmt *sql.Stmt + updateBundleStmt *sql.Stmt + updateJoinTokenStmt *sql.Stmt + updateRelationshipStmt *sql.Stmt + updateTrustDomainStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createBundleStmt: q.createBundleStmt, + createJoinTokenStmt: q.createJoinTokenStmt, + createRelationshipStmt: q.createRelationshipStmt, + createTrustDomainStmt: q.createTrustDomainStmt, + deleteBundleStmt: q.deleteBundleStmt, + deleteJoinTokenStmt: q.deleteJoinTokenStmt, + deleteRelationshipStmt: q.deleteRelationshipStmt, + deleteTrustDomainStmt: q.deleteTrustDomainStmt, + findBundleByIDStmt: q.findBundleByIDStmt, + findBundleByTrustDomainIDStmt: q.findBundleByTrustDomainIDStmt, + findJoinTokenStmt: q.findJoinTokenStmt, + findJoinTokenByIDStmt: q.findJoinTokenByIDStmt, + findJoinTokensByTrustDomainIDStmt: q.findJoinTokensByTrustDomainIDStmt, + findRelationshipByIDStmt: q.findRelationshipByIDStmt, + findRelationshipsByTrustDomainIDStmt: q.findRelationshipsByTrustDomainIDStmt, + findTrustDomainByIDStmt: q.findTrustDomainByIDStmt, + findTrustDomainByNameStmt: q.findTrustDomainByNameStmt, + listBundlesStmt: q.listBundlesStmt, + listJoinTokensStmt: q.listJoinTokensStmt, + listRelationshipsStmt: q.listRelationshipsStmt, + listTrustDomainsStmt: q.listTrustDomainsStmt, + updateBundleStmt: q.updateBundleStmt, + updateJoinTokenStmt: q.updateJoinTokenStmt, + updateRelationshipStmt: q.updateRelationshipStmt, + updateTrustDomainStmt: q.updateTrustDomainStmt, + } +} diff --git a/pkg/server/db/sqlite/helpers.go b/pkg/server/db/sqlite/helpers.go new file mode 100644 index 000000000..0c0d1f876 --- /dev/null +++ b/pkg/server/db/sqlite/helpers.go @@ -0,0 +1,130 @@ +package sqlite + +import ( + "fmt" + + "github.com/HewlettPackard/galadriel/pkg/common/entity" + "github.com/google/uuid" + "github.com/spiffe/go-spiffe/v2/spiffeid" +) + +func (td TrustDomain) ToEntity() (*entity.TrustDomain, error) { + trustDomain, err := spiffeid.TrustDomainFromString(td.Name) + if err != nil { + return nil, err + } + + id, err := uuid.Parse(td.ID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + nullID := uuid.NullUUID{ + UUID: id, + Valid: true, + } + + result := &entity.TrustDomain{ + ID: nullID, + Name: trustDomain, + OnboardingBundle: td.OnboardingBundle, + CreatedAt: td.CreatedAt, + UpdatedAt: td.UpdatedAt, + } + + if td.Description.Valid { + result.Description = td.Description.String + } + + if td.HarvesterSpiffeID.Valid { + id, err := spiffeid.FromStringf(td.HarvesterSpiffeID.String) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + result.HarvesterSpiffeID = id + } + + return result, nil +} + +func (r Relationship) ToEntity() (*entity.Relationship, error) { + id, err := uuid.Parse(r.ID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + nullID := uuid.NullUUID{ + UUID: id, + Valid: true, + } + + tdAID, err := uuid.Parse(r.TrustDomainAID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + tdBID, err := uuid.Parse(r.TrustDomainBID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + + return &entity.Relationship{ + ID: nullID, + TrustDomainAID: tdAID, + TrustDomainBID: tdBID, + TrustDomainAConsent: entity.ConsentStatus(r.TrustDomainAConsent), + TrustDomainBConsent: entity.ConsentStatus(r.TrustDomainBConsent), + CreatedAt: r.CreatedAt, + UpdatedAt: r.UpdatedAt, + }, nil +} + +func (b Bundle) ToEntity() (*entity.Bundle, error) { + id, err := uuid.Parse(b.ID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + nullID := uuid.NullUUID{ + UUID: id, + Valid: true, + } + + tdID, err := uuid.Parse(b.TrustDomainID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + + return &entity.Bundle{ + ID: nullID, + Data: b.Data, + Signature: b.Signature, + SignatureAlgorithm: b.SignatureAlgorithm.String, + SigningCertificate: b.SigningCertificate, + TrustDomainID: tdID, + CreatedAt: b.CreatedAt, + UpdatedAt: b.UpdatedAt, + }, nil +} + +func (jt JoinToken) ToEntity() (*entity.JoinToken, error) { + id, err := uuid.Parse(jt.ID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + nullID := uuid.NullUUID{ + UUID: id, + Valid: true, + } + + tdID, err := uuid.Parse(jt.TrustDomainID) + if err != nil { + return nil, fmt.Errorf("cannot convert model to entity: %v", err) + } + + return &entity.JoinToken{ + ID: nullID, + Token: jt.Token, + ExpiresAt: jt.ExpiresAt, + Used: jt.Used, + TrustDomainID: tdID, + CreatedAt: jt.CreatedAt, + UpdatedAt: jt.UpdatedAt, + }, nil +} diff --git a/pkg/server/db/sqlite/join_tokens.sql.go b/pkg/server/db/sqlite/join_tokens.sql.go new file mode 100644 index 000000000..b317f6676 --- /dev/null +++ b/pkg/server/db/sqlite/join_tokens.sql.go @@ -0,0 +1,199 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: join_tokens.sql + +package sqlite + +import ( + "context" + "time" +) + +const createJoinToken = `-- name: CreateJoinToken :one +INSERT INTO join_tokens(id, token, expires_at, trust_domain_id) +VALUES (?, ?, ?, ?) +RETURNING id, trust_domain_id, token, used, expires_at, created_at, updated_at +` + +type CreateJoinTokenParams struct { + ID string + Token string + ExpiresAt time.Time + TrustDomainID string +} + +func (q *Queries) CreateJoinToken(ctx context.Context, arg CreateJoinTokenParams) (JoinToken, error) { + row := q.queryRow(ctx, q.createJoinTokenStmt, createJoinToken, + arg.ID, + arg.Token, + arg.ExpiresAt, + arg.TrustDomainID, + ) + var i JoinToken + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteJoinToken = `-- name: DeleteJoinToken :exec +DELETE FROM join_tokens +WHERE id = ? +` + +func (q *Queries) DeleteJoinToken(ctx context.Context, id string) error { + _, err := q.exec(ctx, q.deleteJoinTokenStmt, deleteJoinToken, id) + return err +} + +const findJoinToken = `-- name: FindJoinToken :one +SELECT id, trust_domain_id, token, used, expires_at, created_at, updated_at +FROM join_tokens +WHERE token = ? +` + +func (q *Queries) FindJoinToken(ctx context.Context, token string) (JoinToken, error) { + row := q.queryRow(ctx, q.findJoinTokenStmt, findJoinToken, token) + var i JoinToken + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const findJoinTokenByID = `-- name: FindJoinTokenByID :one +SELECT id, trust_domain_id, token, used, expires_at, created_at, updated_at +FROM join_tokens +WHERE id = ? +` + +func (q *Queries) FindJoinTokenByID(ctx context.Context, id string) (JoinToken, error) { + row := q.queryRow(ctx, q.findJoinTokenByIDStmt, findJoinTokenByID, id) + var i JoinToken + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const findJoinTokensByTrustDomainID = `-- name: FindJoinTokensByTrustDomainID :many +SELECT id, trust_domain_id, token, used, expires_at, created_at, updated_at +FROM join_tokens +WHERE trust_domain_id = ? +ORDER BY created_at DESC +` + +func (q *Queries) FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID string) ([]JoinToken, error) { + rows, err := q.query(ctx, q.findJoinTokensByTrustDomainIDStmt, findJoinTokensByTrustDomainID, trustDomainID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []JoinToken + for rows.Next() { + var i JoinToken + if err := rows.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listJoinTokens = `-- name: ListJoinTokens :many +SELECT id, trust_domain_id, token, used, expires_at, created_at, updated_at +FROM join_tokens +ORDER BY created_at DESC +` + +func (q *Queries) ListJoinTokens(ctx context.Context) ([]JoinToken, error) { + rows, err := q.query(ctx, q.listJoinTokensStmt, listJoinTokens) + if err != nil { + return nil, err + } + defer rows.Close() + var items []JoinToken + for rows.Next() { + var i JoinToken + if err := rows.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateJoinToken = `-- name: UpdateJoinToken :one +UPDATE join_tokens +SET used = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING id, trust_domain_id, token, used, expires_at, created_at, updated_at +` + +type UpdateJoinTokenParams struct { + Used bool + ID string +} + +func (q *Queries) UpdateJoinToken(ctx context.Context, arg UpdateJoinTokenParams) (JoinToken, error) { + row := q.queryRow(ctx, q.updateJoinTokenStmt, updateJoinToken, arg.Used, arg.ID) + var i JoinToken + err := row.Scan( + &i.ID, + &i.TrustDomainID, + &i.Token, + &i.Used, + &i.ExpiresAt, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/pkg/server/db/sqlite/migrations/1_initialize_schema.down.sql b/pkg/server/db/sqlite/migrations/1_initialize_schema.down.sql new file mode 100644 index 000000000..d550f58c0 --- /dev/null +++ b/pkg/server/db/sqlite/migrations/1_initialize_schema.down.sql @@ -0,0 +1,4 @@ +DROP TABLE IF EXISTS join_tokens; +DROP TABLE IF EXISTS relationships; +DROP TABLE IF EXISTS bundles; +DROP TABLE IF EXISTS trust_domains; diff --git a/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql b/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql new file mode 100644 index 000000000..881449023 --- /dev/null +++ b/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql @@ -0,0 +1,54 @@ +-- create tables +CREATE TABLE IF NOT EXISTS trust_domains +( + id text PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + description TEXT, + harvester_spiffe_id TEXT, + onboarding_bundle BLOB, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS relationships +( + id TEXT PRIMARY KEY, + trust_domain_a_id TEXT NOT NULL, + trust_domain_b_id TEXT NOT NULL, + trust_domain_a_consent TEXT NOT NULL DEFAULT 'pending', + trust_domain_b_consent TEXT NOT NULL DEFAULT 'pending', + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE (trust_domain_a_id, trust_domain_b_id), + FOREIGN KEY (trust_domain_a_id) + REFERENCES trust_domains (id), + FOREIGN KEY (trust_domain_b_id) + REFERENCES trust_domains (id) +); + +CREATE TABLE IF NOT EXISTS bundles +( + id TEXT PRIMARY KEY, + trust_domain_id TEXT NOT NULL UNIQUE, + data BLOB NOT NULL, + signature BLOB, + signature_algorithm TEXT, + signing_certificate BLOB, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (trust_domain_id) + REFERENCES trust_domains (id) +); + +CREATE TABLE IF NOT EXISTS join_tokens +( + id TEXT PRIMARY KEY, + trust_domain_id TEXT NOT NULL, + token TEXT NOT NULL UNIQUE, + used BOOL NOT NULL DEFAULT 0, + expires_at TIMESTAMP NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (trust_domain_id) + REFERENCES trust_domains (id) +); diff --git a/pkg/server/db/sqlite/models.gen.go b/pkg/server/db/sqlite/models.gen.go new file mode 100644 index 000000000..bb0626673 --- /dev/null +++ b/pkg/server/db/sqlite/models.gen.go @@ -0,0 +1,51 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 + +package sqlite + +import ( + "database/sql" + "time" +) + +type Bundle struct { + ID string + TrustDomainID string + Data []byte + Signature []byte + SignatureAlgorithm sql.NullString + SigningCertificate []byte + CreatedAt time.Time + UpdatedAt time.Time +} + +type JoinToken struct { + ID string + TrustDomainID string + Token string + Used bool + ExpiresAt time.Time + CreatedAt time.Time + UpdatedAt time.Time +} + +type Relationship struct { + ID string + TrustDomainAID string + TrustDomainBID string + TrustDomainAConsent string + TrustDomainBConsent string + CreatedAt time.Time + UpdatedAt time.Time +} + +type TrustDomain struct { + ID string + Name string + Description sql.NullString + HarvesterSpiffeID sql.NullString + OnboardingBundle []byte + CreatedAt time.Time + UpdatedAt time.Time +} diff --git a/pkg/server/db/sqlite/querier.gen.go b/pkg/server/db/sqlite/querier.gen.go new file mode 100644 index 000000000..a572b9d90 --- /dev/null +++ b/pkg/server/db/sqlite/querier.gen.go @@ -0,0 +1,39 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 + +package sqlite + +import ( + "context" +) + +type Querier interface { + CreateBundle(ctx context.Context, arg CreateBundleParams) (Bundle, error) + CreateJoinToken(ctx context.Context, arg CreateJoinTokenParams) (JoinToken, error) + CreateRelationship(ctx context.Context, arg CreateRelationshipParams) (Relationship, error) + CreateTrustDomain(ctx context.Context, arg CreateTrustDomainParams) (TrustDomain, error) + DeleteBundle(ctx context.Context, id string) error + DeleteJoinToken(ctx context.Context, id string) error + DeleteRelationship(ctx context.Context, id string) error + DeleteTrustDomain(ctx context.Context, id string) error + FindBundleByID(ctx context.Context, id string) (Bundle, error) + FindBundleByTrustDomainID(ctx context.Context, trustDomainID string) (Bundle, error) + FindJoinToken(ctx context.Context, token string) (JoinToken, error) + FindJoinTokenByID(ctx context.Context, id string) (JoinToken, error) + FindJoinTokensByTrustDomainID(ctx context.Context, trustDomainID string) ([]JoinToken, error) + FindRelationshipByID(ctx context.Context, id string) (Relationship, error) + FindRelationshipsByTrustDomainID(ctx context.Context, arg FindRelationshipsByTrustDomainIDParams) ([]Relationship, error) + FindTrustDomainByID(ctx context.Context, id string) (TrustDomain, error) + FindTrustDomainByName(ctx context.Context, name string) (TrustDomain, error) + ListBundles(ctx context.Context) ([]Bundle, error) + ListJoinTokens(ctx context.Context) ([]JoinToken, error) + ListRelationships(ctx context.Context) ([]Relationship, error) + ListTrustDomains(ctx context.Context) ([]TrustDomain, error) + UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bundle, error) + UpdateJoinToken(ctx context.Context, arg UpdateJoinTokenParams) (JoinToken, error) + UpdateRelationship(ctx context.Context, arg UpdateRelationshipParams) (Relationship, error) + UpdateTrustDomain(ctx context.Context, arg UpdateTrustDomainParams) (TrustDomain, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/pkg/server/db/sqlite/queries/bundles.sql b/pkg/server/db/sqlite/queries/bundles.sql new file mode 100644 index 000000000..00224dec8 --- /dev/null +++ b/pkg/server/db/sqlite/queries/bundles.sql @@ -0,0 +1,35 @@ +-- name: CreateBundle :one +INSERT INTO bundles(id, data, signature, signature_algorithm, signing_certificate, trust_domain_id) +VALUES (?, ?, ?, ?, ?, ?) +RETURNING *; + +-- name: UpdateBundle :one +UPDATE bundles +SET data = ?, + signature = ?, + signature_algorithm = ?, + signing_certificate = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING *; + +-- name: DeleteBundle :exec +DELETE +FROM bundles +WHERE id = ?; + +-- name: FindBundleByID :one +SELECT * +FROM bundles +WHERE id = ?; + +-- name: FindBundleByTrustDomainID :one +SELECT * +FROM bundles +WHERE trust_domain_id = ? +LIMIT 1; + +-- name: ListBundles :many +SELECT * +FROM bundles +ORDER BY created_at DESC; diff --git a/pkg/server/db/sqlite/queries/join_tokens.sql b/pkg/server/db/sqlite/queries/join_tokens.sql new file mode 100644 index 000000000..be5411f65 --- /dev/null +++ b/pkg/server/db/sqlite/queries/join_tokens.sql @@ -0,0 +1,36 @@ +-- name: CreateJoinToken :one +INSERT INTO join_tokens(id, token, expires_at, trust_domain_id) +VALUES (?, ?, ?, ?) +RETURNING *; + +-- name: UpdateJoinToken :one +UPDATE join_tokens +SET used = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING *; + +-- name: DeleteJoinToken :exec +DELETE FROM join_tokens +WHERE id = ?; + +-- name: FindJoinTokenByID :one +SELECT * +FROM join_tokens +WHERE id = ?; + +-- name: FindJoinToken :one +SELECT * +FROM join_tokens +WHERE token = ?; + +-- name: FindJoinTokensByTrustDomainID :many +SELECT * +FROM join_tokens +WHERE trust_domain_id = ? +ORDER BY created_at DESC; + +-- name: ListJoinTokens :many +SELECT * +FROM join_tokens +ORDER BY created_at DESC; diff --git a/pkg/server/db/sqlite/queries/relationships.sql b/pkg/server/db/sqlite/queries/relationships.sql new file mode 100644 index 000000000..ad3766ba0 --- /dev/null +++ b/pkg/server/db/sqlite/queries/relationships.sql @@ -0,0 +1,32 @@ +-- name: CreateRelationship :one +INSERT INTO relationships(id, trust_domain_a_id, trust_domain_b_id) +VALUES (?, ?, ?) +RETURNING *; + +-- name: UpdateRelationship :one +UPDATE relationships +SET trust_domain_a_consent = ?, + trust_domain_b_consent = ?, + updated_at = CURRENT_TIMESTAMP +WHERE id = ? +RETURNING *; + +-- name: DeleteRelationship :exec +DELETE +FROM relationships +WHERE id = ?; + +-- name: FindRelationshipByID :one +SELECT * +FROM relationships +WHERE id = ?; + +-- name: FindRelationshipsByTrustDomainID :many +SELECT * +FROM relationships +WHERE trust_domain_a_id = ? OR trust_domain_b_id = ?; + +-- name: ListRelationships :many +SELECT * +FROM relationships +ORDER BY created_at DESC; diff --git a/pkg/server/db/sqlite/queries/trust_domains.sql b/pkg/server/db/sqlite/queries/trust_domains.sql new file mode 100644 index 000000000..c2096d1b5 --- /dev/null +++ b/pkg/server/db/sqlite/queries/trust_domains.sql @@ -0,0 +1,33 @@ +-- name: CreateTrustDomain :one +INSERT INTO trust_domains(id, name, description) +VALUES (?, ?, ?) +RETURNING *; + +-- name: UpdateTrustDomain :one +UPDATE trust_domains +SET description = ?, + harvester_spiffe_id = ?, + onboarding_bundle = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING *; + +-- name: DeleteTrustDomain :exec +DELETE +FROM trust_domains +WHERE id = ?; + +-- name: FindTrustDomainByID :one +SELECT * +FROM trust_domains +WHERE id = ?; + +-- name: FindTrustDomainByName :one +SELECT * +FROM trust_domains +WHERE name = ?; + +-- name: ListTrustDomains :many +SELECT * +FROM trust_domains +ORDER BY name; diff --git a/pkg/server/db/sqlite/relationships.sql.go b/pkg/server/db/sqlite/relationships.sql.go new file mode 100644 index 000000000..aacdf99a1 --- /dev/null +++ b/pkg/server/db/sqlite/relationships.sql.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: relationships.sql + +package sqlite + +import ( + "context" +) + +const createRelationship = `-- name: CreateRelationship :one +INSERT INTO relationships(id, trust_domain_a_id, trust_domain_b_id) +VALUES (?, ?, ?) +RETURNING id, trust_domain_a_id, trust_domain_b_id, trust_domain_a_consent, trust_domain_b_consent, created_at, updated_at +` + +type CreateRelationshipParams struct { + ID string + TrustDomainAID string + TrustDomainBID string +} + +func (q *Queries) CreateRelationship(ctx context.Context, arg CreateRelationshipParams) (Relationship, error) { + row := q.queryRow(ctx, q.createRelationshipStmt, createRelationship, arg.ID, arg.TrustDomainAID, arg.TrustDomainBID) + var i Relationship + err := row.Scan( + &i.ID, + &i.TrustDomainAID, + &i.TrustDomainBID, + &i.TrustDomainAConsent, + &i.TrustDomainBConsent, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteRelationship = `-- name: DeleteRelationship :exec +DELETE +FROM relationships +WHERE id = ? +` + +func (q *Queries) DeleteRelationship(ctx context.Context, id string) error { + _, err := q.exec(ctx, q.deleteRelationshipStmt, deleteRelationship, id) + return err +} + +const findRelationshipByID = `-- name: FindRelationshipByID :one +SELECT id, trust_domain_a_id, trust_domain_b_id, trust_domain_a_consent, trust_domain_b_consent, created_at, updated_at +FROM relationships +WHERE id = ? +` + +func (q *Queries) FindRelationshipByID(ctx context.Context, id string) (Relationship, error) { + row := q.queryRow(ctx, q.findRelationshipByIDStmt, findRelationshipByID, id) + var i Relationship + err := row.Scan( + &i.ID, + &i.TrustDomainAID, + &i.TrustDomainBID, + &i.TrustDomainAConsent, + &i.TrustDomainBConsent, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const findRelationshipsByTrustDomainID = `-- name: FindRelationshipsByTrustDomainID :many +SELECT id, trust_domain_a_id, trust_domain_b_id, trust_domain_a_consent, trust_domain_b_consent, created_at, updated_at +FROM relationships +WHERE trust_domain_a_id = ? OR trust_domain_b_id = ? +` + +type FindRelationshipsByTrustDomainIDParams struct { + TrustDomainAID string + TrustDomainBID string +} + +func (q *Queries) FindRelationshipsByTrustDomainID(ctx context.Context, arg FindRelationshipsByTrustDomainIDParams) ([]Relationship, error) { + rows, err := q.query(ctx, q.findRelationshipsByTrustDomainIDStmt, findRelationshipsByTrustDomainID, arg.TrustDomainAID, arg.TrustDomainBID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Relationship + for rows.Next() { + var i Relationship + if err := rows.Scan( + &i.ID, + &i.TrustDomainAID, + &i.TrustDomainBID, + &i.TrustDomainAConsent, + &i.TrustDomainBConsent, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listRelationships = `-- name: ListRelationships :many +SELECT id, trust_domain_a_id, trust_domain_b_id, trust_domain_a_consent, trust_domain_b_consent, created_at, updated_at +FROM relationships +ORDER BY created_at DESC +` + +func (q *Queries) ListRelationships(ctx context.Context) ([]Relationship, error) { + rows, err := q.query(ctx, q.listRelationshipsStmt, listRelationships) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Relationship + for rows.Next() { + var i Relationship + if err := rows.Scan( + &i.ID, + &i.TrustDomainAID, + &i.TrustDomainBID, + &i.TrustDomainAConsent, + &i.TrustDomainBConsent, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateRelationship = `-- name: UpdateRelationship :one +UPDATE relationships +SET trust_domain_a_consent = ?, + trust_domain_b_consent = ?, + updated_at = CURRENT_TIMESTAMP +WHERE id = ? +RETURNING id, trust_domain_a_id, trust_domain_b_id, trust_domain_a_consent, trust_domain_b_consent, created_at, updated_at +` + +type UpdateRelationshipParams struct { + TrustDomainAConsent string + TrustDomainBConsent string + ID string +} + +func (q *Queries) UpdateRelationship(ctx context.Context, arg UpdateRelationshipParams) (Relationship, error) { + row := q.queryRow(ctx, q.updateRelationshipStmt, updateRelationship, arg.TrustDomainAConsent, arg.TrustDomainBConsent, arg.ID) + var i Relationship + err := row.Scan( + &i.ID, + &i.TrustDomainAID, + &i.TrustDomainBID, + &i.TrustDomainAConsent, + &i.TrustDomainBConsent, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/pkg/server/db/sqlite/schema.go b/pkg/server/db/sqlite/schema.go new file mode 100644 index 000000000..a530dab32 --- /dev/null +++ b/pkg/server/db/sqlite/schema.go @@ -0,0 +1,46 @@ +package sqlite + +import ( + "database/sql" + "embed" + + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/database/sqlite" + "github.com/golang-migrate/migrate/v4/source/iofs" +) + +//go:embed migrations/*.sql +var fs embed.FS + +// currentDBVersion defines the current migration version supported by the app. +// This is used to ensure that the app is compatible with the database schema. +// When a new migration is created, this version should be updated in order to force +// the migrations to run when starting up the app. +const currentDBVersion = 1 + +const scheme = "sqlite3" + +func validateAndMigrateSchema(db *sql.DB) error { + + sourceInstance, err := iofs.New(fs, "migrations") + if err != nil { + return err + } + + driverInstance, err := sqlite.WithInstance(db, new(sqlite.Config)) + if err != nil { + return err + } + + m, err := migrate.NewWithInstance("iofs", sourceInstance, scheme, driverInstance) + if err != nil { + return err + } + + err = m.Migrate(currentDBVersion) + if err != nil && err != migrate.ErrNoChange { + return err + } + + return sourceInstance.Close() +} diff --git a/pkg/server/db/sqlite/trust_domains.sql.go b/pkg/server/db/sqlite/trust_domains.sql.go new file mode 100644 index 000000000..5a90434a8 --- /dev/null +++ b/pkg/server/db/sqlite/trust_domains.sql.go @@ -0,0 +1,165 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: trust_domains.sql + +package sqlite + +import ( + "context" + "database/sql" +) + +const createTrustDomain = `-- name: CreateTrustDomain :one +INSERT INTO trust_domains(id, name, description) +VALUES (?, ?, ?) +RETURNING id, name, description, harvester_spiffe_id, onboarding_bundle, created_at, updated_at +` + +type CreateTrustDomainParams struct { + ID string + Name string + Description sql.NullString +} + +func (q *Queries) CreateTrustDomain(ctx context.Context, arg CreateTrustDomainParams) (TrustDomain, error) { + row := q.queryRow(ctx, q.createTrustDomainStmt, createTrustDomain, arg.ID, arg.Name, arg.Description) + var i TrustDomain + err := row.Scan( + &i.ID, + &i.Name, + &i.Description, + &i.HarvesterSpiffeID, + &i.OnboardingBundle, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteTrustDomain = `-- name: DeleteTrustDomain :exec +DELETE +FROM trust_domains +WHERE id = ? +` + +func (q *Queries) DeleteTrustDomain(ctx context.Context, id string) error { + _, err := q.exec(ctx, q.deleteTrustDomainStmt, deleteTrustDomain, id) + return err +} + +const findTrustDomainByID = `-- name: FindTrustDomainByID :one +SELECT id, name, description, harvester_spiffe_id, onboarding_bundle, created_at, updated_at +FROM trust_domains +WHERE id = ? +` + +func (q *Queries) FindTrustDomainByID(ctx context.Context, id string) (TrustDomain, error) { + row := q.queryRow(ctx, q.findTrustDomainByIDStmt, findTrustDomainByID, id) + var i TrustDomain + err := row.Scan( + &i.ID, + &i.Name, + &i.Description, + &i.HarvesterSpiffeID, + &i.OnboardingBundle, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const findTrustDomainByName = `-- name: FindTrustDomainByName :one +SELECT id, name, description, harvester_spiffe_id, onboarding_bundle, created_at, updated_at +FROM trust_domains +WHERE name = ? +` + +func (q *Queries) FindTrustDomainByName(ctx context.Context, name string) (TrustDomain, error) { + row := q.queryRow(ctx, q.findTrustDomainByNameStmt, findTrustDomainByName, name) + var i TrustDomain + err := row.Scan( + &i.ID, + &i.Name, + &i.Description, + &i.HarvesterSpiffeID, + &i.OnboardingBundle, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const listTrustDomains = `-- name: ListTrustDomains :many +SELECT id, name, description, harvester_spiffe_id, onboarding_bundle, created_at, updated_at +FROM trust_domains +ORDER BY name +` + +func (q *Queries) ListTrustDomains(ctx context.Context) ([]TrustDomain, error) { + rows, err := q.query(ctx, q.listTrustDomainsStmt, listTrustDomains) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TrustDomain + for rows.Next() { + var i TrustDomain + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Description, + &i.HarvesterSpiffeID, + &i.OnboardingBundle, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateTrustDomain = `-- name: UpdateTrustDomain :one +UPDATE trust_domains +SET description = ?, + harvester_spiffe_id = ?, + onboarding_bundle = ?, + updated_at = datetime('now') +WHERE id = ? +RETURNING id, name, description, harvester_spiffe_id, onboarding_bundle, created_at, updated_at +` + +type UpdateTrustDomainParams struct { + Description sql.NullString + HarvesterSpiffeID sql.NullString + OnboardingBundle []byte + ID string +} + +func (q *Queries) UpdateTrustDomain(ctx context.Context, arg UpdateTrustDomainParams) (TrustDomain, error) { + row := q.queryRow(ctx, q.updateTrustDomainStmt, updateTrustDomain, + arg.Description, + arg.HarvesterSpiffeID, + arg.OnboardingBundle, + arg.ID, + ) + var i TrustDomain + err := row.Scan( + &i.ID, + &i.Name, + &i.Description, + &i.HarvesterSpiffeID, + &i.OnboardingBundle, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/pkg/server/db/tests/datastore_setup.go b/pkg/server/db/tests/datastore_setup.go new file mode 100644 index 000000000..3783815c2 --- /dev/null +++ b/pkg/server/db/tests/datastore_setup.go @@ -0,0 +1,104 @@ +package tests + +import ( + "database/sql" + "fmt" + "testing" + "time" + + "github.com/HewlettPackard/galadriel/pkg/server/db/postgres" + "github.com/HewlettPackard/galadriel/pkg/server/db/sqlite" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" + "github.com/stretchr/testify/require" +) + +const ( + postgresImage = "15-alpine" + user = "test_user" + password = "test_password" + dbname = "test_db" +) + +func setupSQLiteDatastore(t *testing.T) *sqlite.Datastore { + // Use an in-memory database + dsn := ":memory:" + + datastore, err := sqlite.NewDatastore(dsn) + require.NoError(t, err) + + t.Cleanup(func() { + err = datastore.Close() + require.NoError(t, err) + }) + + return datastore +} + +func setupPostgresDatastore(t *testing.T) *postgres.Datastore { + conn := startPostgresDB(t) + datastore, err := postgres.NewDatastore(conn) + require.NoError(t, err) + + t.Cleanup(func() { + err = datastore.Close() + require.NoError(t, err) + }) + return datastore +} + +// starts a postgres DB in a docker container and returns the connection string +func startPostgresDB(tb testing.TB) string { + pool, err := dockertest.NewPool("") + require.NoError(tb, err) + + err = pool.Client.Ping() + require.NoError(tb, err) + + // pulls an image, creates a container based on it and runs it + resource, err := pool.RunWithOptions(&dockertest.RunOptions{ + Repository: "postgres", + Tag: postgresImage, + Env: []string{ + "POSTGRES_PASSWORD=" + password, + "POSTGRES_USER=" + user, + "POSTGRES_DB=" + dbname, + }, + }, func(config *docker.HostConfig) { + // set AutoRemove to true so that stopped container goes away by itself + config.AutoRemove = true + config.RestartPolicy = docker.RestartPolicy{Name: "no"} + }) + require.NoError(tb, err) + + hostAndPort := resource.GetHostPort("5432/tcp") + databaseURL := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", user, password, hostAndPort, dbname) + + tb.Logf("Connecting to a test database on url: %s", databaseURL) + + // wait until db in container is ready using exponential backoff-retry + pool.MaxWait = 60 * time.Second + if err = pool.Retry(func() error { + db, err := sql.Open("postgres", databaseURL) + if err != nil { + return err + } + defer func() { + cerr := db.Close() + if err != nil { + err = cerr + } + }() + + return db.Ping() + }); err != nil { + tb.Fatalf("Could not connect to docker: %s", err) + } + + tb.Cleanup(func() { + err = pool.Purge(resource) + require.NoError(tb, err) + }) + + return databaseURL +} diff --git a/pkg/server/db/tests/datastore_test.go b/pkg/server/db/tests/datastore_test.go new file mode 100644 index 000000000..ea0e0d6b3 --- /dev/null +++ b/pkg/server/db/tests/datastore_test.go @@ -0,0 +1,624 @@ +package tests + +import ( + "context" + "github.com/HewlettPackard/galadriel/pkg/common/entity" + "github.com/HewlettPackard/galadriel/pkg/server/db" + "github.com/google/uuid" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "strings" + "testing" + "time" +) + +var ( + spiffeTD1 = spiffeid.RequireTrustDomainFromString("foo.test") + spiffeTD2 = spiffeid.RequireTrustDomainFromString("bar.test") + spiffeTD3 = spiffeid.RequireTrustDomainFromString("baz.test") +) + +func TestSuite(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + sqliteDS := func() db.Datastore { + return setupSQLiteDatastore(t) + } + runTests(t, ctx, sqliteDS) + + postgresDS := func() db.Datastore { + return setupPostgresDatastore(t) + } + runTests(t, ctx, postgresDS) +} + +func runTests(t *testing.T, ctx context.Context, newDS func() db.Datastore) { + t.Run("Test CRUD TrustDomains", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + // Create trust domain + req1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1, err := ds.CreateOrUpdateTrustDomain(ctx, req1) + assert.NoError(t, err) + assert.NotNil(t, td1.ID) + assert.Equal(t, req1.Name, td1.Name) + assert.NotNil(t, td1.CreatedAt) + assert.NotNil(t, td1.UpdatedAt) + + // Create second trust domain + req2 := &entity.TrustDomain{ + Name: spiffeTD2, + } + td2, err := ds.CreateOrUpdateTrustDomain(ctx, req2) + assert.NoError(t, err) + assert.NotNil(t, td2.ID) + assert.Equal(t, req2.Name, td2.Name) + assert.NotNil(t, td2.CreatedAt) + assert.NotNil(t, td2.UpdatedAt) + + // Find trust domain by ID + stored, err := ds.FindTrustDomainByID(ctx, td1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, td1, stored) + stored, err = ds.FindTrustDomainByID(ctx, td2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, td2, stored) + + // Update trust domain + td1.Description = "updated_description" + td1.HarvesterSpiffeID = spiffeid.RequireFromString("spiffe://domain/test") + td1.OnboardingBundle = []byte{1, 2, 3} + + updated1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + assert.NotNil(t, updated1) + + // Look up trust domain stored in DB and compare + stored, err = ds.FindTrustDomainByID(ctx, td1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, td1.ID, stored.ID) + assert.Equal(t, td1.Description, stored.Description) + assert.Equal(t, td1.HarvesterSpiffeID, stored.HarvesterSpiffeID) + assert.Equal(t, td1.OnboardingBundle, stored.OnboardingBundle) + + // Find trust domain by name + td1 = updated1 + stored, err = ds.FindTrustDomainByName(ctx, td1.Name) + assert.NoError(t, err) + assert.Equal(t, td1, stored) + + // List all trust domains + list, err := ds.ListTrustDomains(ctx) + assert.NoError(t, err) + assert.Equal(t, 2, len(list)) + assert.Contains(t, list, td1) + assert.Contains(t, list, td2) + + // Delete trust domain + err = ds.DeleteTrustDomain(ctx, td1.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindTrustDomainByID(ctx, td1.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + }) + t.Run("Test TrustDomain Unique Constraint", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + _, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + + // second trustDomain with same trust domain + td2 := &entity.TrustDomain{ + Name: spiffeTD1, + } + _, err = ds.CreateOrUpdateTrustDomain(ctx, td2) + require.Error(t, err) + + sqliteExpectedErr := "UNIQUE constraint failed" + postgresExpectedErr := "duplicate key value violates unique constraint" + assertErrorString(t, err, sqliteExpectedErr, postgresExpectedErr) + }) + t.Run("Test CRUD Relationships", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + // Create TrustDomains + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1 = createTrustDomain(ctx, t, ds, td1) + + td2 := &entity.TrustDomain{ + Name: spiffeTD2, + } + td2 = createTrustDomain(ctx, t, ds, td2) + + td3 := &entity.TrustDomain{ + Name: spiffeTD3, + } + td3 = createTrustDomain(ctx, t, ds, td3) + + // Create relationship TrustDomain1 -- TrustDomain2 + req1 := &entity.Relationship{ + TrustDomainAID: td1.ID.UUID, + TrustDomainBID: td2.ID.UUID, + } + + relationship1, err := ds.CreateOrUpdateRelationship(ctx, req1) + assert.NoError(t, err) + assert.NotNil(t, relationship1.ID) + assert.NotNil(t, relationship1.CreatedAt) + assert.NotNil(t, relationship1.UpdatedAt) + assert.Equal(t, req1.TrustDomainAID, relationship1.TrustDomainAID) + assert.Equal(t, req1.TrustDomainBID, relationship1.TrustDomainBID) + assert.Equal(t, entity.ConsentStatusPending, relationship1.TrustDomainAConsent) + assert.Equal(t, entity.ConsentStatusPending, relationship1.TrustDomainBConsent) + + // Create relationship TrustDomain2 -- TrustDomain3 + req2 := &entity.Relationship{ + TrustDomainAID: td2.ID.UUID, + TrustDomainBID: td3.ID.UUID, + } + + relationship2, err := ds.CreateOrUpdateRelationship(ctx, req2) + assert.NoError(t, err) + assert.NotNil(t, relationship2.ID) + assert.NotNil(t, relationship2.CreatedAt) + assert.NotNil(t, relationship2.UpdatedAt) + assert.Equal(t, req2.TrustDomainAID, relationship2.TrustDomainAID) + assert.Equal(t, req2.TrustDomainBID, relationship2.TrustDomainBID) + assert.Equal(t, entity.ConsentStatusPending, relationship2.TrustDomainAConsent) + assert.Equal(t, entity.ConsentStatusPending, relationship2.TrustDomainBConsent) + + // Find relationship by ID + stored, err := ds.FindRelationshipByID(ctx, relationship1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, relationship1, stored) + stored, err = ds.FindRelationshipByID(ctx, relationship2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, relationship2, stored) + + // Update relationship + relationship1.TrustDomainAConsent = entity.ConsentStatusAccepted + relationship1.TrustDomainBConsent = entity.ConsentStatusDenied + updated1, err := ds.CreateOrUpdateRelationship(ctx, relationship1) + assert.NoError(t, err) + assert.Equal(t, relationship1.TrustDomainAConsent, updated1.TrustDomainAConsent) + assert.Equal(t, relationship1.TrustDomainBConsent, updated1.TrustDomainBConsent) + relationship1 = updated1 + + // Find relationship by trust domain IDs + rels, err := ds.FindRelationshipsByTrustDomainID(ctx, td2.ID.UUID) + assert.NoError(t, err) + assert.Len(t, rels, 2) + assert.Contains(t, rels, relationship1) + assert.Contains(t, rels, relationship2) + + rels, err = ds.FindRelationshipsByTrustDomainID(ctx, td1.ID.UUID) + assert.NoError(t, err) + assert.Len(t, rels, 1) + assert.Contains(t, rels, relationship1) + + // List all relationships + rels, err = ds.ListRelationships(ctx) + assert.NoError(t, err) + assert.Len(t, rels, 2) + + // Delete relationship + err = ds.DeleteRelationship(ctx, relationship1.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindRelationshipByID(ctx, relationship1.ID.UUID) + assert.NoError(t, err) + assert.Nil(t, stored) + + err = ds.DeleteRelationship(ctx, relationship2.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindRelationshipByID(ctx, relationship2.ID.UUID) + assert.NoError(t, err) + assert.Nil(t, stored) + }) + t.Run("Test Relationship ForeignKey Constraints", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + + td2 := &entity.TrustDomain{ + Name: spiffeTD2, + } + td2, err = ds.CreateOrUpdateTrustDomain(ctx, td2) + assert.NoError(t, err) + + relationship1 := &entity.Relationship{ + TrustDomainAID: td1.ID.UUID, + TrustDomainBID: td2.ID.UUID, + } + relationship1, err = ds.CreateOrUpdateRelationship(ctx, relationship1) + assert.NoError(t, err) + + // Cannot add a new relationship for the same TrustDomains + relationship1.ID = uuid.NullUUID{} + _, err = ds.CreateOrUpdateRelationship(ctx, relationship1) + require.Error(t, err) + + sqliteExpectedError := "UNIQUE constraint failed" + postgresExpectedError := "duplicate key value violates unique constraint" + assertErrorString(t, err, sqliteExpectedError, postgresExpectedError) + + // Cannot delete Trust Domain that has a relationship associated + err = ds.DeleteTrustDomain(ctx, td1.ID.UUID) + require.Error(t, err) + + sqliteExpectedError = "FOREIGN KEY constraint failed" + postgresExpectedError = "violates foreign key constraint" + assertErrorString(t, err, sqliteExpectedError, postgresExpectedError) + + // Cannot delete Trust Domain that has a relationship associated + err = ds.DeleteTrustDomain(ctx, td2.ID.UUID) + require.Error(t, err) + assertErrorString(t, err, sqliteExpectedError, postgresExpectedError) + }) + t.Run("Test CRUD Bundles", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + // Create trustDomains to associate the bundles + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + assert.NotNil(t, td1.ID) + + td2 := &entity.TrustDomain{ + Name: spiffeTD2, + } + td2, err = ds.CreateOrUpdateTrustDomain(ctx, td2) + assert.NoError(t, err) + assert.NotNil(t, td2.ID) + + // Create first Data - trustDomain-1 + req1 := &entity.Bundle{ + Data: []byte{1, 2, 3}, + Signature: []byte{4, 2}, + SignatureAlgorithm: "SHA256WithRSA", + SigningCertificate: []byte{50, 60}, + TrustDomainID: td1.ID.UUID, + } + + b1, err := ds.CreateOrUpdateBundle(ctx, req1) + assert.NoError(t, err) + assert.NotNil(t, b1) + assert.Equal(t, req1.Data, b1.Data) + assert.Equal(t, req1.Signature, b1.Signature) + assert.Equal(t, req1.SignatureAlgorithm, b1.SignatureAlgorithm) + assert.Equal(t, req1.SigningCertificate, b1.SigningCertificate) + assert.Equal(t, req1.TrustDomainID, b1.TrustDomainID) + + // Look up bundle stored in DB and compare + stored, err := ds.FindBundleByID(ctx, b1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, b1, stored) + + // Create second Data -> trustDomain-2 + req2 := &entity.Bundle{ + Data: []byte{10, 20, 30}, + Signature: []byte{40, 20}, + SignatureAlgorithm: "SHA256WithRSA", + SigningCertificate: []byte{80, 90}, + TrustDomainID: td2.ID.UUID, + } + + b2, err := ds.CreateOrUpdateBundle(ctx, req2) + assert.NoError(t, err) + assert.NotNil(t, b1) + assert.Equal(t, req2.Data, b2.Data) + assert.Equal(t, req2.Signature, b2.Signature) + assert.Equal(t, req2.SignatureAlgorithm, b2.SignatureAlgorithm) + assert.Equal(t, req2.SigningCertificate, b2.SigningCertificate) + assert.Equal(t, req2.TrustDomainID, b2.TrustDomainID) + + // Look up bundle stored in DB and compare + stored, err = ds.FindBundleByID(ctx, b2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, b2, stored) + + // Find bundles by TrustDomainID + stored, err = ds.FindBundleByTrustDomainID(ctx, td1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, b1, stored) + + stored, err = ds.FindBundleByTrustDomainID(ctx, td2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, b2, stored) + + // Update Data + b1.Data = []byte{'a', 'b', 'c'} + b1.Signature = []byte{'f', 'g', 'h'} + b1.SignatureAlgorithm = "SHA512WithRSA" + b1.SigningCertificate = []byte{'f', 'g', 'h'} + + updated, err := ds.CreateOrUpdateBundle(ctx, b1) + assert.NoError(t, err) + assert.NotNil(t, updated) + assert.Equal(t, b1.Data, updated.Data) + assert.Equal(t, b1.Signature, updated.Signature) + assert.Equal(t, b1.SignatureAlgorithm, updated.SignatureAlgorithm) + assert.Equal(t, b1.SigningCertificate, updated.SigningCertificate) + assert.Equal(t, b1.TrustDomainID, updated.TrustDomainID) + + // Look up bundle stored in DB and compare + stored, err = ds.FindBundleByID(ctx, b1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, updated, stored) + + // List bundles + bundles, err := ds.ListBundles(ctx) + assert.NoError(t, err) + assert.Equal(t, 2, len(bundles)) + require.Contains(t, bundles, updated) + require.Contains(t, bundles, b2) + + // Delete first bundle + err = ds.DeleteBundle(ctx, b1.ID.UUID) + assert.NoError(t, err) + + // Look up deleted bundle + stored, err = ds.FindBundleByID(ctx, b1.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + + // Delete second bundle + err = ds.DeleteBundle(ctx, b2.ID.UUID) + assert.NoError(t, err) + + // Look up deleted bundle + stored, err = ds.FindBundleByID(ctx, b2.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + }) + t.Run("Test Bundle Unique TrustDomain Constraint", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + // Create trustDomain to associate the bundles + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + assert.NotNil(t, td1.ID) + + // Create Data + b1 := &entity.Bundle{ + Data: []byte{1, 2, 3}, + Signature: []byte{4, 2}, + SignatureAlgorithm: "SHA512WithRSA", + SigningCertificate: []byte{50, 60}, + TrustDomainID: td1.ID.UUID, + } + b1, err = ds.CreateOrUpdateBundle(ctx, b1) + assert.NoError(t, err) + assert.NotNil(t, b1) + + // Create second Data associated to same trustDomain + b2 := &entity.Bundle{ + Data: []byte{10, 20, 30}, + Signature: []byte{40, 20}, + SignatureAlgorithm: "SHA512WithRSA", + SigningCertificate: []byte{80, 90}, + TrustDomainID: td1.ID.UUID, + } + b2, err = ds.CreateOrUpdateBundle(ctx, b2) + require.Error(t, err) + require.Nil(t, b2) + + sqliteExpectedErr := "UNIQUE constraint failed" + postgresExpectedErr := "duplicate key value violates unique constraint" + assertErrorString(t, err, sqliteExpectedErr, postgresExpectedErr) + }) + t.Run("Test CRUD Join Tokens", func(t *testing.T) { + t.Parallel() + ds := newDS() + defer closeDatastore(t, ds) + + // Create trustDomains to associate the join tokens + td1 := &entity.TrustDomain{ + Name: spiffeTD1, + } + td1, err := ds.CreateOrUpdateTrustDomain(ctx, td1) + assert.NoError(t, err) + assert.NotNil(t, td1.ID) + + td2 := &entity.TrustDomain{ + Name: spiffeTD2, + } + td2, err = ds.CreateOrUpdateTrustDomain(ctx, td2) + assert.NoError(t, err) + assert.NotNil(t, td2.ID) + + loc, _ := time.LoadLocation("UTC") + expiry := time.Now().In(loc).Add(1 * time.Hour) + + // Create first join_token -> trustDomain_1 + req1 := &entity.JoinToken{ + Token: uuid.NewString(), + ExpiresAt: expiry, + TrustDomainID: td1.ID.UUID, + } + + token1, err := ds.CreateJoinToken(ctx, req1) + assert.NoError(t, err) + assert.NotNil(t, token1) + assert.Equal(t, req1.Token, token1.Token) + assertEqualDate(t, req1.ExpiresAt, token1.ExpiresAt.In(loc)) + require.False(t, token1.Used) + assert.Equal(t, req1.TrustDomainID, token1.TrustDomainID) + + // Look up token stored in DB and compare + stored, err := ds.FindJoinTokensByID(ctx, token1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, token1, stored) + + // Create second join_token -> trustDomain_2 + req2 := &entity.JoinToken{ + Token: uuid.NewString(), + ExpiresAt: expiry, + TrustDomainID: td2.ID.UUID, + } + + token2, err := ds.CreateJoinToken(ctx, req2) + assert.NoError(t, err) + assert.NotNil(t, token1) + assert.Equal(t, req2.Token, token2.Token) + assert.Equal(t, req1.TrustDomainID, token1.TrustDomainID) + require.False(t, token2.Used) + + assertEqualDate(t, req2.ExpiresAt, token2.ExpiresAt.In(loc)) + assert.Equal(t, req2.TrustDomainID, token2.TrustDomainID) + + // Look up token stored in DB and compare + stored, err = ds.FindJoinTokensByID(ctx, token2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, token2, stored) + + // Create second join_token -> trustDomain_2 + req3 := &entity.JoinToken{ + Token: uuid.NewString(), + ExpiresAt: expiry, + TrustDomainID: td2.ID.UUID, + } + + token3, err := ds.CreateJoinToken(ctx, req3) + assert.NoError(t, err) + assert.NotNil(t, token3) + + // Find tokens by TrustDomainID + tokens, err := ds.FindJoinTokensByTrustDomainID(ctx, td1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, 1, len(tokens)) + require.Contains(t, tokens, token1) + + tokens, err = ds.FindJoinTokensByTrustDomainID(ctx, td2.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, 2, len(tokens)) + require.Contains(t, tokens, token2) + require.Contains(t, tokens, token3) + + // Look up join token by token string + stored, err = ds.FindJoinToken(ctx, token1.Token) + assert.NoError(t, err) + assert.Equal(t, token1, stored) + + stored, err = ds.FindJoinToken(ctx, token2.Token) + assert.NoError(t, err) + assert.Equal(t, token2, stored) + + stored, err = ds.FindJoinToken(ctx, token3.Token) + assert.NoError(t, err) + assert.Equal(t, token3, stored) + + // List tokens + tokens, err = ds.ListJoinTokens(ctx) + assert.NoError(t, err) + assert.Equal(t, 3, len(tokens)) + require.Contains(t, tokens, token1) + require.Contains(t, tokens, token2) + require.Contains(t, tokens, token3) + + // Update join token + updated, err := ds.UpdateJoinToken(ctx, token1.ID.UUID, true) + assert.NoError(t, err) + assert.Equal(t, true, updated.Used) + + // Look up and compare + stored, err = ds.FindJoinTokensByID(ctx, token1.ID.UUID) + assert.NoError(t, err) + assert.Equal(t, true, stored.Used) + assert.Equal(t, updated.UpdatedAt, stored.UpdatedAt) + + // Delete join tokens + err = ds.DeleteJoinToken(ctx, token1.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindJoinTokensByID(ctx, token1.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + + err = ds.DeleteJoinToken(ctx, token2.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindJoinTokensByID(ctx, token2.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + + err = ds.DeleteJoinToken(ctx, token3.ID.UUID) + assert.NoError(t, err) + stored, err = ds.FindJoinTokensByID(ctx, token3.ID.UUID) + assert.NoError(t, err) + require.Nil(t, stored) + + tokens, err = ds.ListJoinTokens(ctx) + assert.NoError(t, err) + assert.Equal(t, 0, len(tokens)) + }) +} + +func createTrustDomain(ctx context.Context, t *testing.T, ds db.Datastore, req *entity.TrustDomain) *entity.TrustDomain { + td1, err := ds.CreateOrUpdateTrustDomain(ctx, req) + require.NoError(t, err) + return td1 +} + +func closeDatastore(t *testing.T, ds db.Datastore) { + switch d := ds.(type) { + case interface { + Close() error + }: + if err := d.Close(); err != nil { + t.Errorf("error closing datastore: %v", err) + } + } +} + +// assertErrorString asserts that the error string is one of the expected error strings +func assertErrorString(t *testing.T, err error, s1, s2 string) { + if err == nil { + t.Fatalf("expected error containing either '%s' or '%s', but got no error", s1, s2) + } + errMsg := err.Error() + if !strings.Contains(errMsg, s1) && !strings.Contains(errMsg, s2) { + t.Fatalf("expected error containing either '%s' or '%s', but got '%s'", s1, s2, errMsg) + } +} + +func assertEqualDate(t *testing.T, time1 time.Time, time2 time.Time) { + y1, td1, d1 := time1.Date() + y2, td2, d2 := time2.Date() + h1, mt1, s1 := time1.Clock() + h2, mt2, s2 := time2.Clock() + + require.Equal(t, y1, y2, "Year doesn't match") + require.Equal(t, td1, td2, "Month doesn't match") + require.Equal(t, d1, d2, "Day doesn't match") + require.Equal(t, h1, h2, "Hour doesn't match") + require.Equal(t, mt1, mt2, "Minute doesn't match") + require.Equal(t, s1, s2, "Seconds doesn't match") +} diff --git a/pkg/server/endpoints/auth.go b/pkg/server/endpoints/auth.go index 6b70c40d1..c0f3c1b92 100644 --- a/pkg/server/endpoints/auth.go +++ b/pkg/server/endpoints/auth.go @@ -4,19 +4,19 @@ import ( "net/http" "github.com/HewlettPackard/galadriel/pkg/common/jwt" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" + "github.com/HewlettPackard/galadriel/pkg/server/db" "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" "github.com/spiffe/go-spiffe/v2/spiffeid" ) type AuthenticationMiddleware struct { - datastore datastore.Datastore + datastore db.Datastore jwtValidator jwt.Validator logger logrus.FieldLogger } -func NewAuthenticationMiddleware(l logrus.FieldLogger, ds datastore.Datastore, jwtValidator jwt.Validator) *AuthenticationMiddleware { +func NewAuthenticationMiddleware(l logrus.FieldLogger, ds db.Datastore, jwtValidator jwt.Validator) *AuthenticationMiddleware { return &AuthenticationMiddleware{ logger: l, datastore: ds, diff --git a/pkg/server/endpoints/auth_test.go b/pkg/server/endpoints/auth_test.go index f6909beda..753ca8d1b 100644 --- a/pkg/server/endpoints/auth_test.go +++ b/pkg/server/endpoints/auth_test.go @@ -2,6 +2,7 @@ package endpoints import ( "context" + "github.com/HewlettPackard/galadriel/test/fakes/fakedatastore" "net/http" "net/http/httptest" "testing" @@ -10,7 +11,6 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/cryptoutil" "github.com/HewlettPackard/galadriel/pkg/common/jwt" "github.com/HewlettPackard/galadriel/pkg/common/keymanager" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/sirupsen/logrus" @@ -19,19 +19,17 @@ import ( "github.com/stretchr/testify/require" ) -const testTrustDomain = "test.com" - type AuthNTestSetup struct { EchoCtx echo.Context Middleware *AuthenticationMiddleware Recorder *httptest.ResponseRecorder - FakeDatabase *datastore.FakeDatabase + FakeDatabase *fakedatastore.FakeDatabase JWTIssuer jwt.Issuer } func SetupMiddleware(t *testing.T) *AuthNTestSetup { logger := logrus.New() - fakeDB := datastore.NewFakeDB() + fakeDB := fakedatastore.NewFakeDB() km := keymanager.New(&keymanager.Config{}) c := jwt.ValidatorConfig{ diff --git a/pkg/server/endpoints/config.go b/pkg/server/endpoints/config.go index 5f76acda1..cee3101b4 100644 --- a/pkg/server/endpoints/config.go +++ b/pkg/server/endpoints/config.go @@ -5,7 +5,6 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/jwt" "github.com/HewlettPackard/galadriel/pkg/server/catalog" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" "github.com/sirupsen/logrus" ) @@ -17,8 +16,6 @@ type Config struct { // LocalAddress is the local address to bind the listener to. LocalAddress net.Addr - Datastore datastore.Datastore - JWTIssuer jwt.Issuer JWTValidator jwt.Validator diff --git a/pkg/server/endpoints/harvester.go b/pkg/server/endpoints/harvester.go index 275146fa2..a287ff4d3 100644 --- a/pkg/server/endpoints/harvester.go +++ b/pkg/server/endpoints/harvester.go @@ -16,7 +16,7 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/jwt" "github.com/HewlettPackard/galadriel/pkg/common/util" "github.com/HewlettPackard/galadriel/pkg/server/api/harvester" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" + "github.com/HewlettPackard/galadriel/pkg/server/db" gojwt "github.com/golang-jwt/jwt/v4" "github.com/google/uuid" "github.com/labstack/echo/v4" @@ -32,13 +32,13 @@ const ( type HarvesterAPIHandlers struct { Logger logrus.FieldLogger - Datastore datastore.Datastore + Datastore db.Datastore jwtIssuer jwt.Issuer jwtValidator jwt.Validator } // NewHarvesterAPIHandlers create a new HarvesterAPIHandlers -func NewHarvesterAPIHandlers(l logrus.FieldLogger, ds datastore.Datastore, jwtIssuer jwt.Issuer, jwtValidator jwt.Validator) *HarvesterAPIHandlers { +func NewHarvesterAPIHandlers(l logrus.FieldLogger, ds db.Datastore, jwtIssuer jwt.Issuer, jwtValidator jwt.Validator) *HarvesterAPIHandlers { return &HarvesterAPIHandlers{ Logger: l, Datastore: ds, @@ -85,7 +85,7 @@ func (h *HarvesterAPIHandlers) GetRelationships(echoCtx echo.Context, params har apiRelationships = append(apiRelationships, api.RelationshipFromEntity(r)) } - return chttp.WriteResponse(echoCtx, apiRelationships) + return chttp.WriteResponse(echoCtx, http.StatusOK, apiRelationships) } // PatchRelationship accept/denies relationships requests - (PATCH /relationships/{relationshipID}) @@ -145,7 +145,7 @@ func (h *HarvesterAPIHandlers) PatchRelationship(echoCtx echo.Context, relations return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - if err = chttp.BodylessResponse(echoCtx); err != nil { + if err = chttp.BodilessResponse(echoCtx, http.StatusOK); err != nil { return h.handleErrorAndLog(err, err.Error(), http.StatusInternalServerError) } @@ -215,7 +215,7 @@ func (h *HarvesterAPIHandlers) Onboard(echoCtx echo.Context, params harvester.On return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - return chttp.WriteResponse(echoCtx, jwtToken) + return chttp.WriteResponse(echoCtx, http.StatusOK, jwtToken) } // GetNewJWTToken renews a JWT access token - (GET /trust-domain/jwt) @@ -255,7 +255,7 @@ func (h *HarvesterAPIHandlers) GetNewJWTToken(echoCtx echo.Context) error { return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - return chttp.WriteResponse(echoCtx, newToken) + return chttp.WriteResponse(echoCtx, http.StatusOK, newToken) } // BundleSync synchronize the status of trust bundles between server and harvester - (POST /trust-domain/{trustDomainName}/bundles/sync) @@ -294,7 +294,7 @@ func (h *HarvesterAPIHandlers) BundleSync(echoCtx echo.Context, trustDomainName return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - return chttp.WriteResponse(echoCtx, resp) + return chttp.WriteResponse(echoCtx, http.StatusOK, resp) } // BundlePut uploads a new trust bundle to the server - (PUT /trust-domain/{trustDomainName}/bundles) @@ -340,7 +340,7 @@ func (h *HarvesterAPIHandlers) BundlePut(echoCtx echo.Context, trustDomainName a return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - // the bundle already exists in the datastore, so we need to update it + // the bundle already exists in the db, so we need to update it if storedBundle != nil { bundle.ID = storedBundle.ID } @@ -351,7 +351,7 @@ func (h *HarvesterAPIHandlers) BundlePut(echoCtx echo.Context, trustDomainName a return h.handleErrorAndLog(err, msg, http.StatusInternalServerError) } - if err = chttp.BodylessResponse(echoCtx); err != nil { + if err = chttp.BodilessResponse(echoCtx, http.StatusOK); err != nil { return h.handleErrorAndLog(err, err.Error(), http.StatusInternalServerError) } diff --git a/pkg/server/endpoints/harvester_test.go b/pkg/server/endpoints/harvester_test.go index 06dba651b..b4aac09b0 100644 --- a/pkg/server/endpoints/harvester_test.go +++ b/pkg/server/endpoints/harvester_test.go @@ -5,6 +5,8 @@ import ( "crypto/sha256" "encoding/base64" "encoding/json" + "github.com/HewlettPackard/galadriel/test/fakes/fakedatastore" + "io" "net/http" "net/http/httptest" "reflect" @@ -14,7 +16,7 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/api" "github.com/HewlettPackard/galadriel/pkg/common/entity" "github.com/HewlettPackard/galadriel/pkg/server/api/harvester" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" + "github.com/HewlettPackard/galadriel/pkg/server/db" "github.com/HewlettPackard/galadriel/test/fakes/fakejwtissuer" "github.com/HewlettPackard/galadriel/test/jwttest" gojwt "github.com/golang-jwt/jwt/v4" @@ -51,21 +53,28 @@ var ( type HarvesterTestSetup struct { EchoCtx echo.Context Handler *HarvesterAPIHandlers - Datastore *datastore.FakeDatabase + Datastore *fakedatastore.FakeDatabase JWTIssuer *fakejwtissuer.JWTIssuer Recorder *httptest.ResponseRecorder } -func NewHarvesterTestSetup(t *testing.T, method, url, body string) *HarvesterTestSetup { +func NewHarvesterTestSetup(t *testing.T, method, url string, body interface{}) *HarvesterTestSetup { + var bodyReader io.Reader + if body != nil { + bodyStr, err := json.Marshal(body) + assert.NoError(t, err) + bodyReader = strings.NewReader(string(bodyStr)) + } + e := echo.New() - req := httptest.NewRequest(method, url, strings.NewReader(body)) + req := httptest.NewRequest(method, url, bodyReader) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() - fakeDB := datastore.NewFakeDB() + fakeDB := fakedatastore.NewFakeDB() logger := logrus.New() jwtAudience := []string{"test"} - jwtIssuer := fakejwtissuer.New(t, "test", testTrustDomain, jwtAudience) + jwtIssuer := fakejwtissuer.New(t, "test", td1, jwtAudience) jwtValidator := jwttest.NewJWTValidator(jwtIssuer.Signer, jwtAudience) return &HarvesterTestSetup{ @@ -77,22 +86,21 @@ func NewHarvesterTestSetup(t *testing.T, method, url, body string) *HarvesterTes } } -func SetupTrustDomain(t *testing.T, ds datastore.Datastore) *entity.TrustDomain { - td, err := spiffeid.TrustDomainFromString(testTrustDomain) +func SetupTrustDomain(t *testing.T, ds db.Datastore) *entity.TrustDomain { + td, err := spiffeid.TrustDomainFromString(td1) assert.NoError(t, err) tdEntity := &entity.TrustDomain{ Name: td, Description: "Fake domain", } - trustDomain, err := ds.CreateOrUpdateTrustDomain(context.TODO(), tdEntity) require.NoError(t, err) return trustDomain } -func SetupBundle(t *testing.T, ds datastore.Datastore, td uuid.UUID) *entity.Bundle { +func SetupBundle(t *testing.T, ds db.Datastore, td uuid.UUID) *entity.Bundle { bundle := &entity.Bundle{ TrustDomainID: td, Data: []byte("test-bundle"), @@ -105,7 +113,7 @@ func SetupBundle(t *testing.T, ds datastore.Datastore, td uuid.UUID) *entity.Bun return bundle } -func SetupJoinToken(t *testing.T, ds datastore.Datastore, td uuid.UUID) *entity.JoinToken { +func SetupJoinToken(t *testing.T, ds db.Datastore, td uuid.UUID) *entity.JoinToken { jt := &entity.JoinToken{ Token: "test-join-token", TrustDomainID: td, @@ -143,7 +151,7 @@ func TestTCPGetRelationships(t *testing.T) { }) t.Run("Fails with invalid consent status", func(t *testing.T) { - setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, "") + setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, nil) echoCtx := setup.EchoCtx setup.EchoCtx.Set(authTrustDomainKey, tdA) @@ -161,7 +169,7 @@ func TestTCPGetRelationships(t *testing.T) { }) t.Run("Fails if no authenticated trust domain", func(t *testing.T) { - setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, "") + setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, nil) echoCtx := setup.EchoCtx tdName := tdA.Name.String() @@ -176,7 +184,7 @@ func TestTCPGetRelationships(t *testing.T) { }) t.Run("Fails if authenticated trust domain does not match trust domain parameter", func(t *testing.T) { - setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, "") + setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, nil) echoCtx := setup.EchoCtx setup.EchoCtx.Set(authTrustDomainKey, tdA) @@ -193,7 +201,7 @@ func TestTCPGetRelationships(t *testing.T) { } func testGetRelationships(t *testing.T, setupFn func(*HarvesterTestSetup, *entity.TrustDomain), status api.ConsentStatus, trustDomain *entity.TrustDomain, expectedRelationshipCount int) { - setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, "") + setup := NewHarvesterTestSetup(t, http.MethodGet, relationshipsPath, nil) echoCtx := setup.EchoCtx setup.Datastore.WithTrustDomains(tdA, tdB, tdC) @@ -261,10 +269,7 @@ func testPatchRelationship(t *testing.T, f func(setup *HarvesterTestSetup, trust ConsentStatus: status, } - body, err := json.Marshal(requestBody) - require.NoError(t, err) - - setup := NewHarvesterTestSetup(t, http.MethodPatch, relationshipsPath+"/"+relationship.ID.UUID.String(), string(body)) + setup := NewHarvesterTestSetup(t, http.MethodPatch, relationshipsPath+"/"+relationship.ID.UUID.String(), &requestBody) echoCtx := setup.EchoCtx setup.Datastore.WithTrustDomains(tdA, tdB, tdC) @@ -272,7 +277,7 @@ func testPatchRelationship(t *testing.T, f func(setup *HarvesterTestSetup, trust f(setup, trustDomain) - err = setup.Handler.PatchRelationship(echoCtx, relationship.ID.UUID) + err := setup.Handler.PatchRelationship(echoCtx, relationship.ID.UUID) assert.NoError(t, err) recorder := setup.Recorder @@ -297,7 +302,7 @@ func testPatchRelationship(t *testing.T, f func(setup *HarvesterTestSetup, trust func TestTCPOnboard(t *testing.T) { t.Run("Successfully onboard a new agent", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, nil) echoCtx := harvesterTestSetup.EchoCtx td := SetupTrustDomain(t, harvesterTestSetup.Handler.Datastore) @@ -318,7 +323,7 @@ func TestTCPOnboard(t *testing.T) { assert.Equal(t, harvesterTestSetup.JWTIssuer.Token, jwtToken) }) t.Run("Onboard without join token fails", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, nil) echoCtx := harvesterTestSetup.EchoCtx SetupTrustDomain(t, harvesterTestSetup.Handler.Datastore) @@ -334,7 +339,7 @@ func TestTCPOnboard(t *testing.T) { assert.Contains(t, httpErr.Message, "join token is required") }) t.Run("Onboard with join token that does not exist fails", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, nil) echoCtx := harvesterTestSetup.EchoCtx td := SetupTrustDomain(t, harvesterTestSetup.Handler.Datastore) @@ -351,7 +356,7 @@ func TestTCPOnboard(t *testing.T) { assert.Contains(t, httpErr.Message, "token not found") }) t.Run("Onboard with join token that was used", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, onboardPath, nil) echoCtx := harvesterTestSetup.EchoCtx td := SetupTrustDomain(t, harvesterTestSetup.Handler.Datastore) @@ -375,7 +380,7 @@ func TestTCPOnboard(t *testing.T) { func TestTCPGetNewJWTToken(t *testing.T) { t.Run("Successfully get a new JWT token", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, jwtPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, jwtPath, nil) echoCtx := harvesterTestSetup.EchoCtx SetupTrustDomain(t, harvesterTestSetup.Handler.Datastore) @@ -399,7 +404,7 @@ func TestTCPGetNewJWTToken(t *testing.T) { assert.Equal(t, harvesterTestSetup.JWTIssuer.Token, jwtToken) }) t.Run("Fails if no JWT token was sent", func(t *testing.T) { - harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, jwtPath, "") + harvesterTestSetup := NewHarvesterTestSetup(t, http.MethodGet, jwtPath, nil) echoCtx := harvesterTestSetup.EchoCtx err := harvesterTestSetup.Handler.GetNewJWTToken(echoCtx) @@ -518,10 +523,7 @@ func TestTCPBundleSync(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - body, err := json.Marshal(tc.bundleState) - require.NoError(t, err) - - setup := NewHarvesterTestSetup(t, http.MethodPost, "/trust-domain/:trustDomainName/bundles/sync", string(body)) + setup := NewHarvesterTestSetup(t, http.MethodPost, "/trust-domain/:trustDomainName/bundles/sync", &tc.bundleState) echoCtx := setup.EchoCtx setup.EchoCtx.Set(authTrustDomainKey, tdA) @@ -530,7 +532,7 @@ func TestTCPBundleSync(t *testing.T) { setup.Datastore.WithBundles(bundleA, bundleB, bundleC) // test bundle sync - err = setup.Handler.BundleSync(echoCtx, tdA.Name.String()) + err := setup.Handler.BundleSync(echoCtx, tdA.Name.String()) assert.NoError(t, err) recorder := setup.Recorder @@ -571,16 +573,13 @@ func TestBundlePut(t *testing.T) { Signature: "bundle signature", SigningCertificate: "certificate PEM", TrustBundle: "a new bundle", - TrustDomain: testTrustDomain, + TrustDomain: td1, } - body, err := json.Marshal(bundlePut) - require.NoError(t, err) - - setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", string(body)) + setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", &bundlePut) setup.EchoCtx.Set(authTrustDomainKey, "") - err = setup.Handler.BundlePut(setup.EchoCtx, testTrustDomain) + err := setup.Handler.BundlePut(setup.EchoCtx, td1) require.Error(t, err) assert.Equal(t, http.StatusUnauthorized, err.(*echo.HTTPError).Code) assert.Contains(t, err.(*echo.HTTPError).Message, "no authenticated trust domain") @@ -599,7 +598,7 @@ func TestBundlePut(t *testing.T) { }) t.Run("Fail post bundle bundle trust domain does not match authenticated trust domain", func(t *testing.T) { - testInvalidBundleRequest(t, "TrustDomain", "other-trust-domain", http.StatusUnauthorized, "trust domain in request bundle \"other-trust-domain\" does not match authenticated trust domain: \"test.com\"") + testInvalidBundleRequest(t, "TrustDomain", "other-trust-domain", http.StatusUnauthorized, "trust domain in request bundle \"other-trust-domain\" does not match authenticated trust domain: \"test1.com\"") }) } @@ -608,18 +607,15 @@ func testBundlePut(t *testing.T, setupFunc func(*HarvesterTestSetup) *entity.Tru Signature: "bundle signature", SigningCertificate: "certificate PEM", TrustBundle: "a new bundle", - TrustDomain: testTrustDomain, + TrustDomain: td1, } - body, err := json.Marshal(bundlePut) - require.NoError(t, err) - - setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", string(body)) + setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", &bundlePut) echoCtx := setup.EchoCtx td := setupFunc(setup) - err = setup.Handler.BundlePut(echoCtx, testTrustDomain) + err := setup.Handler.BundlePut(echoCtx, td1) require.NoError(t, err) recorder := setup.Recorder @@ -639,20 +635,17 @@ func testInvalidBundleRequest(t *testing.T, fieldName string, fieldValue interfa Signature: "test-signature", SigningCertificate: "certificate PEM", TrustBundle: "test trust bundle", - TrustDomain: testTrustDomain, + TrustDomain: td1, } reflect.ValueOf(&bundlePut).Elem().FieldByName(fieldName).Set(reflect.ValueOf(fieldValue)) - body, err := json.Marshal(bundlePut) - require.NoError(t, err) - - setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", string(body)) + setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", &bundlePut) echoCtx := setup.EchoCtx td := SetupTrustDomain(t, setup.Handler.Datastore) echoCtx.Set(authTrustDomainKey, td) - err = setup.Handler.BundlePut(echoCtx, testTrustDomain) + err := setup.Handler.BundlePut(echoCtx, td1) require.Error(t, err) assert.Equal(t, expectedStatusCode, err.(*echo.HTTPError).Code) assert.Contains(t, err.(*echo.HTTPError).Message, expectedErrorMessage) diff --git a/pkg/server/endpoints/management.go b/pkg/server/endpoints/management.go index ea691aa86..fcdea70cb 100644 --- a/pkg/server/endpoints/management.go +++ b/pkg/server/endpoints/management.go @@ -3,6 +3,7 @@ package endpoints import ( "context" + "errors" "fmt" "net/http" "time" @@ -12,7 +13,7 @@ import ( chttp "github.com/HewlettPackard/galadriel/pkg/common/http" "github.com/HewlettPackard/galadriel/pkg/common/util" "github.com/HewlettPackard/galadriel/pkg/server/api/admin" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" + "github.com/HewlettPackard/galadriel/pkg/server/db" "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" @@ -21,11 +22,11 @@ import ( type AdminAPIHandlers struct { Logger logrus.FieldLogger - Datastore datastore.Datastore + Datastore db.Datastore } // NewAdminAPIHandlers create a new NewAdminAPIHandlers -func NewAdminAPIHandlers(l logrus.FieldLogger, ds datastore.Datastore) *AdminAPIHandlers { +func NewAdminAPIHandlers(l logrus.FieldLogger, ds db.Datastore) *AdminAPIHandlers { return &AdminAPIHandlers{ Logger: l, Datastore: ds, @@ -33,134 +34,255 @@ func NewAdminAPIHandlers(l logrus.FieldLogger, ds datastore.Datastore) *AdminAPI } // GetRelationships list all relationships filtered by the request params - (GET /relationships) -func (h AdminAPIHandlers) GetRelationships(ctx echo.Context, params admin.GetRelationshipsParams) error { - gctx := ctx.Request().Context() +func (h *AdminAPIHandlers) GetRelationships(echoContext echo.Context, params admin.GetRelationshipsParams) error { + ctx := echoContext.Request().Context() - rels, err := h.Datastore.ListRelationships(gctx) - if err != nil { - err = fmt.Errorf("failed listing relationships: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + var err error + var rels []*entity.Relationship + + if params.TrustDomainName != nil { + td, err := h.findTrustDomainByName(ctx, *params.TrustDomainName) + if err != nil { + err = fmt.Errorf("failed looking up trust domain name: %w", err) + return h.handleAndLog(err, http.StatusBadRequest) + } + + rels, err = h.Datastore.FindRelationshipsByTrustDomainID(ctx, td.ID.UUID) + if err != nil { + err = fmt.Errorf("failed looking up relationships: %v", err) + return h.handleAndLog(err, http.StatusInternalServerError) + } + } else { + rels, err = h.Datastore.ListRelationships(ctx) + if err != nil { + err = fmt.Errorf("failed listing relationships: %v", err) + return h.handleAndLog(err, http.StatusInternalServerError) + } + } + + if params.Status != nil { + rels, err = h.adminFilterRelationshipsByConsentStatus(rels, api.ConsentStatus(*params.Status)) + if err != nil { + return err + } } - rels, err = h.populateTrustDomainNames(gctx, rels) + rels, err = h.populateTrustDomainNames(ctx, rels) if err != nil { err = fmt.Errorf("failed populating relationships entities: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } cRelationships := mapRelationships(rels) - err = chttp.WriteResponse(ctx, cRelationships) + err = chttp.WriteResponse(echoContext, http.StatusOK, cRelationships) if err != nil { err = fmt.Errorf("relationships entities - %v", err.Error()) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } return nil } // PutRelationships create a new relationship request between two trust domains - (PUT /relationships) -func (h AdminAPIHandlers) PutRelationships(ctx echo.Context) error { - gctx := ctx.Request().Context() +func (h *AdminAPIHandlers) PutRelationship(echoCtx echo.Context) error { + ctx := echoCtx.Request().Context() - reqBody := &admin.PutRelationshipsJSONRequestBody{} - err := chttp.FromBody(ctx, reqBody) + reqBody := &admin.PutRelationshipJSONRequestBody{} + err := chttp.FromBody(echoCtx, reqBody) if err != nil { err := fmt.Errorf("failed to read relationship put body: %v", err) - return h.HandleAndLog(err, http.StatusBadRequest) + return h.handleAndLog(err, http.StatusBadRequest) } - eRelationship := reqBody.ToEntity() - rel, err := h.Datastore.CreateOrUpdateRelationship(gctx, eRelationship) + + _, err = h.lookupTrustDomain(ctx, eRelationship.TrustDomainAID, http.StatusBadRequest) + if err != nil { + return err + } + + _, err = h.lookupTrustDomain(ctx, eRelationship.TrustDomainBID, http.StatusBadRequest) + if err != nil { + return err + } + + rel, err := h.Datastore.CreateOrUpdateRelationship(ctx, eRelationship) if err != nil { err = fmt.Errorf("failed creating relationship: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } h.Logger.Printf("Created relationship between trust domains %s and %s", rel.TrustDomainAID, rel.TrustDomainBID) response := api.RelationshipFromEntity(rel) - err = chttp.WriteResponse(ctx, response) + err = chttp.WriteResponse(echoCtx, http.StatusCreated, response) if err != nil { err = fmt.Errorf("relationships - %v", err.Error()) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } return nil } -// GetRelationshipsRelationshipID retrieve a specific relationship based on its id - (GET /relationships/{relationshipID}) -func (h AdminAPIHandlers) GetRelationshipsRelationshipID(ctx echo.Context, relationshipID api.UUID) error { +// GetRelationshipByID retrieve a specific relationship based on its id - (GET /relationships/{relationshipID}) +func (h *AdminAPIHandlers) GetRelationshipByID(echoCtx echo.Context, relationshipID api.UUID) error { + ctx := echoCtx.Request().Context() + + r, err := h.Datastore.FindRelationshipByID(ctx, relationshipID) + if err != nil { + err = fmt.Errorf("failed getting relationships: %v", err) + return h.handleAndLog(err, http.StatusInternalServerError) + } + + if r == nil { + err = errors.New("relationship not found") + return h.handleAndLog(err, http.StatusNotFound) + } + + response := api.RelationshipFromEntity(r) + err = chttp.WriteResponse(echoCtx, http.StatusOK, response) + if err != nil { + err = fmt.Errorf("relationship entity - %v", err.Error()) + return h.handleAndLog(err, http.StatusInternalServerError) + } + return nil } // PutTrustDomain create a new trust domain - (PUT /trust-domain) -func (h AdminAPIHandlers) PutTrustDomain(ctx echo.Context) error { +func (h *AdminAPIHandlers) PutTrustDomain(echoCtx echo.Context) error { // Getting golang context - gctx := ctx.Request().Context() + ctx := echoCtx.Request().Context() reqBody := &admin.PutTrustDomainJSONRequestBody{} - err := chttp.FromBody(ctx, reqBody) + err := chttp.FromBody(echoCtx, reqBody) if err != nil { - return h.HandleAndLog(err, http.StatusBadRequest) + return h.handleAndLog(err, http.StatusBadRequest) } dbTD, err := reqBody.ToEntity() if err != nil { - return h.HandleAndLog(err, http.StatusBadRequest) + return h.handleAndLog(err, http.StatusBadRequest) } - td, err := h.Datastore.FindTrustDomainByName(gctx, dbTD.Name) + td, err := h.Datastore.FindTrustDomainByName(ctx, dbTD.Name) if err != nil { err = fmt.Errorf("failed looking up trust domain: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } + if td != nil { err = fmt.Errorf("trust domain already exists: %q", dbTD.Name) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusBadRequest) } - m, err := h.Datastore.CreateOrUpdateTrustDomain(gctx, dbTD) + m, err := h.Datastore.CreateOrUpdateTrustDomain(ctx, dbTD) if err != nil { err = fmt.Errorf("failed creating trustDomain: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } h.Logger.Printf("Created trustDomain for trust domain: %s", dbTD.Name) response := api.TrustDomainFromEntity(m) - err = chttp.WriteResponse(ctx, response) + err = chttp.WriteResponse(echoCtx, http.StatusCreated, response) if err != nil { err = fmt.Errorf("trustDomain entity - %v", err.Error()) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } return nil } // TODO: customize these names. -// GetTrustDomainTrustDomainName retrieve a specific trust domain by its name - (GET /trust-domain/{trustDomainName}) -func (h AdminAPIHandlers) GetTrustDomainTrustDomainName(ctx echo.Context, trustDomainName api.TrustDomainName) error { +// GetTrustDomainByName retrieve a specific trust domain by its name - (GET /trust-domain/{trustDomainName}) +func (h *AdminAPIHandlers) GetTrustDomainByName(echoCtx echo.Context, trustDomainName api.TrustDomainName) error { + ctx := echoCtx.Request().Context() + + tdName, err := spiffeid.TrustDomainFromString(trustDomainName) + if err != nil { + err = fmt.Errorf("failed parsing trust domain name: %v", err) + return h.handleAndLog(err, http.StatusBadRequest) + } + + td, err := h.Datastore.FindTrustDomainByName(ctx, tdName) + if err != nil { + err = fmt.Errorf("failed getting trust domain: %v", err) + return h.handleAndLog(err, http.StatusInternalServerError) + } + + if td == nil { + err = fmt.Errorf("trust domain does not exists") + return h.handleAndLog(err, http.StatusNotFound) + } + + response := api.TrustDomainFromEntity(td) + err = chttp.WriteResponse(echoCtx, http.StatusOK, response) + if err != nil { + err = fmt.Errorf("trust domain entity - %v", err.Error()) + return h.handleAndLog(err, http.StatusInternalServerError) + } + return nil } // PutTrustDomainTrustDomainName updates the trust domain - (PUT /trust-domain/{trustDomainName}) -func (h AdminAPIHandlers) PutTrustDomainTrustDomainName(ctx echo.Context, trustDomainName api.UUID) error { +func (h *AdminAPIHandlers) PutTrustDomainByName(echoCtx echo.Context, trustDomainID api.UUID) error { + ctx := echoCtx.Request().Context() + + reqBody := &admin.PutTrustDomainByNameJSONRequestBody{} + err := chttp.FromBody(echoCtx, reqBody) + if err != nil { + err := fmt.Errorf("failed to read trust domain put body: %v", err) + return h.handleAndLog(err, http.StatusBadRequest) + } + + etd, err := reqBody.ToEntity() + if err != nil { + err := fmt.Errorf("failed to read trust domain put body: %v", err) + return h.handleAndLog(err, http.StatusBadRequest) + } + + _, err = h.lookupTrustDomain(ctx, trustDomainID, http.StatusNotFound) + if err != nil { + return err + } + + td, err := h.Datastore.CreateOrUpdateTrustDomain(ctx, etd) + if err != nil { + err = fmt.Errorf("failed creating/updating trust domain: %v", err) + return h.handleAndLog(err, http.StatusInternalServerError) + } + + h.Logger.Printf("Trust Bundle %v updated", td.Name) + + response := api.TrustDomainFromEntity(td) + err = chttp.WriteResponse(echoCtx, http.StatusOK, response) + if err != nil { + err = fmt.Errorf("relationships - %v", err.Error()) + return h.handleAndLog(err, http.StatusInternalServerError) + } + return nil } -// GetJoinToken generate a join token for the trust domain - (POST /trust-domain/{trustDomainName}/join-token) -func (h AdminAPIHandlers) GetJoinToken(echoCtx echo.Context, trustDomainName api.TrustDomainName) error { +// GetJoinToken generate a join token for the trust domain - (GET /trust-domain/{trustDomainName}/join-token) +func (h *AdminAPIHandlers) GetJoinToken(echoCtx echo.Context, trustDomainName api.TrustDomainName) error { ctx := echoCtx.Request().Context() tdName, err := spiffeid.TrustDomainFromString(trustDomainName) if err != nil { err = fmt.Errorf("failed parsing trust domain: %v", err) - return h.HandleAndLog(err, http.StatusBadRequest) + return h.handleAndLog(err, http.StatusBadRequest) } td, err := h.Datastore.FindTrustDomainByName(ctx, tdName) if err != nil { err = fmt.Errorf("failed looking up trust domain: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) + } + + if td == nil { + errMsg := fmt.Errorf("trust domain exists: %q", trustDomainName) + return h.handleAndLog(errMsg, http.StatusBadRequest) } token := uuid.New() @@ -174,21 +296,41 @@ func (h AdminAPIHandlers) GetJoinToken(echoCtx echo.Context, trustDomainName api _, err = h.Datastore.CreateJoinToken(ctx, joinToken) if err != nil { err = fmt.Errorf("failed creating join token: %v", err) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } h.Logger.Infof("Created join token for trust domain: %s", tdName) - err = chttp.WriteResponse(echoCtx, token) + response := admin.JoinTokenResult{ + Token: token, + } + + err = chttp.WriteResponse(echoCtx, http.StatusOK, response) if err != nil { err = fmt.Errorf("failed to write join token response: %v", err.Error()) - return h.HandleAndLog(err, http.StatusInternalServerError) + return h.handleAndLog(err, http.StatusInternalServerError) } return nil } -func (h AdminAPIHandlers) populateTrustDomainNames(ctx context.Context, relationships []*entity.Relationship) ([]*entity.Relationship, error) { +func (h *AdminAPIHandlers) findTrustDomainByName(ctx context.Context, trustDomain string) (*entity.TrustDomain, error) { + tdName, err := spiffeid.TrustDomainFromString(trustDomain) + if err != nil { + err = fmt.Errorf("failed parsing trust domain name: %v", err) + return nil, h.handleAndLog(err, http.StatusBadRequest) + } + + td, err := h.Datastore.FindTrustDomainByName(ctx, tdName) + if err != nil { + err = fmt.Errorf("failed getting trust domain: %v", err) + return nil, h.handleAndLog(err, http.StatusInternalServerError) + } + + return td, nil +} + +func (h *AdminAPIHandlers) populateTrustDomainNames(ctx context.Context, relationships []*entity.Relationship) ([]*entity.Relationship, error) { for _, r := range relationships { tda, err := h.Datastore.FindTrustDomainByID(ctx, r.TrustDomainAID) if err != nil { @@ -205,6 +347,70 @@ func (h AdminAPIHandlers) populateTrustDomainNames(ctx context.Context, relation return relationships, nil } +func (h *AdminAPIHandlers) lookupTrustDomain(ctx context.Context, trustDomainID uuid.UUID, code int) (*entity.TrustDomain, error) { + td, err := h.Datastore.FindTrustDomainByID(ctx, trustDomainID) + if err != nil { + msg := errors.New("error looking up trust domain") + errMsg := fmt.Errorf("%s: %w", msg, err) + return nil, h.handleAndLog(errMsg, http.StatusInternalServerError) + } + + if td == nil { + errMsg := fmt.Errorf("trust domain exists: %q", trustDomainID) + return nil, h.handleAndLog(errMsg, code) + } + + return td, nil +} + +func (h *AdminAPIHandlers) adminFilterRelationshipsByConsentStatus( + relationships []*entity.Relationship, + status api.ConsentStatus, +) ([]*entity.Relationship, error) { + filtered := make([]*entity.Relationship, 0) + + var checkConsentF func(api.ConsentStatus, api.ConsentStatus) bool + switch status { + case api.Denied: + checkConsentF = denied + case api.Accepted: + checkConsentF = accepted + case api.Pending: + checkConsentF = pending + case "": + checkConsentF = pending + default: + err := fmt.Errorf( + "status filter [`%v`] is not supported, accepted values [%v, %v, %v]", + status, api.Accepted, api.Denied, api.Pending, + ) + return nil, h.handleAndLog(err, http.StatusBadRequest) + } + + for _, relationship := range relationships { + trustDomainAConsent := api.ConsentStatus(relationship.TrustDomainAConsent) + trustDomainBConsent := api.ConsentStatus(relationship.TrustDomainBConsent) + + if checkConsentF(trustDomainAConsent, trustDomainBConsent) { + filtered = append(filtered, relationship) + } + } + + return filtered, nil +} + +func denied(ca api.ConsentStatus, cb api.ConsentStatus) bool { + return ca == api.Denied || cb == api.Denied +} + +func accepted(ca api.ConsentStatus, cb api.ConsentStatus) bool { + return ca == api.Accepted && cb == api.Accepted +} + +func pending(ca api.ConsentStatus, cb api.ConsentStatus) bool { + return (ca == api.Pending || cb == api.Pending) && ca != api.Denied && cb != api.Denied +} + func mapRelationships(relationships []*entity.Relationship) []*api.Relationship { cRelationships := []*api.Relationship{} @@ -216,7 +422,7 @@ func mapRelationships(relationships []*entity.Relationship) []*api.Relationship return cRelationships } -func (h AdminAPIHandlers) HandleAndLog(err error, code int) error { +func (h *AdminAPIHandlers) handleAndLog(err error, code int) error { errMsg := util.LogSanitize(err.Error()) h.Logger.Errorf(errMsg) return echo.NewHTTPError(code, err.Error()) diff --git a/pkg/server/endpoints/management_test.go b/pkg/server/endpoints/management_test.go index 0cc941d2a..095dc0a00 100644 --- a/pkg/server/endpoints/management_test.go +++ b/pkg/server/endpoints/management_test.go @@ -1,31 +1,565 @@ package endpoints -import "testing" +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/HewlettPackard/galadriel/pkg/common/api" + "github.com/HewlettPackard/galadriel/pkg/common/entity" + "github.com/HewlettPackard/galadriel/pkg/server/api/admin" + "github.com/HewlettPackard/galadriel/test/fakes/fakedatastore" + "github.com/google/uuid" + "github.com/labstack/echo/v4" + "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/stretchr/testify/assert" +) + +const ( + // Trust Domains + td1 = "test1.com" + td2 = "test2.com" + td3 = "test3.com" +) + +var ( + // Relationships ID's + r1ID = NewNullableID() + r2ID = NewNullableID() + r3ID = NewNullableID() + r4ID = NewNullableID() + r5ID = NewNullableID() + + // Trust Domains ID's + tdUUID1 = NewNullableID() + tdUUID2 = NewNullableID() + tdUUID3 = NewNullableID() +) + +type ManagementTestSetup struct { + EchoCtx echo.Context + Handler *AdminAPIHandlers + Recorder *httptest.ResponseRecorder + FakeDatabase *fakedatastore.FakeDatabase + + // Helpers + bodyReader io.Reader + + url string + method string +} + +func NewManagementTestSetup(t *testing.T, method, url string, body interface{}) *ManagementTestSetup { + var bodyReader io.Reader = nil + if body != nil { + bodyStr, err := json.Marshal(body) + assert.NoError(t, err) + bodyReader = strings.NewReader(string(bodyStr)) + } + + e := echo.New() + req := httptest.NewRequest(method, url, bodyReader) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + fakeDB := fakedatastore.NewFakeDB() + logger := logrus.New() + + return &ManagementTestSetup{ + EchoCtx: e.NewContext(req, rec), + Recorder: rec, + Handler: NewAdminAPIHandlers(logger, fakeDB), + FakeDatabase: fakeDB, + // Helpers + url: url, + method: method, + bodyReader: bodyReader, + } +} + +func (setup *ManagementTestSetup) Refresh() { + e := echo.New() + req := httptest.NewRequest(setup.method, setup.url, setup.bodyReader) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + + // Refreshing Request context and Recorder + setup.EchoCtx = e.NewContext(req, rec) + setup.Recorder = rec +} func TestUDSGetRelationships(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") + relationshipsPath := "/relationships" + + t.Run("Successfully filter by trust domain", func(t *testing.T) { + // Setup + managementTestSetup := NewManagementTestSetup(t, http.MethodGet, relationshipsPath, nil) + echoCtx := managementTestSetup.EchoCtx + + td1Name := NewTrustDomain(t, td1) + + fakeTrustDomains := []*entity.TrustDomain{ + {ID: tdUUID1, Name: td1Name}, + {ID: tdUUID2, Name: NewTrustDomain(t, td2)}, + {ID: tdUUID3, Name: NewTrustDomain(t, td3)}, + } + + fakeRelationships := []*entity.Relationship{ + {ID: r1ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID2.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + {ID: r2ID, TrustDomainBID: tdUUID1.UUID, TrustDomainAID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + {ID: NewNullableID(), TrustDomainAID: uuid.New(), TrustDomainBID: uuid.New(), TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Denied)}, + {ID: NewNullableID(), TrustDomainAID: uuid.New(), TrustDomainBID: uuid.New(), TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Denied)}, + {ID: NewNullableID(), TrustDomainAID: uuid.New(), TrustDomainBID: uuid.New(), TrustDomainAConsent: entity.ConsentStatus(api.Pending), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + } + + managementTestSetup.FakeDatabase.WithTrustDomains(fakeTrustDomains...) + managementTestSetup.FakeDatabase.WithRelationships(fakeRelationships...) + + tdName := td1 + params := admin.GetRelationshipsParams{ + TrustDomainName: &tdName, + } + + err := managementTestSetup.Handler.GetRelationships(echoCtx, params) + assert.NoError(t, err) + + recorder := managementTestSetup.Recorder + assert.Equal(t, http.StatusOK, recorder.Code) + assert.NotEmpty(t, recorder.Body) + + relationships := []*api.Relationship{} + err = json.Unmarshal(recorder.Body.Bytes(), &relationships) + assert.NoError(t, err) + + assert.Len(t, relationships, 2) + + apiRelations := mapRelationships([]*entity.Relationship{ + {ID: r1ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID2.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + {ID: r2ID, TrustDomainBID: tdUUID1.UUID, TrustDomainAID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + }) + + assert.ElementsMatch(t, relationships, apiRelations, "trust domain name filter does not work properly") + }) + + t.Run("Successfully filter by status", func(t *testing.T) { + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, relationshipsPath, nil) + + td1Name := NewTrustDomain(t, td1) + + fakeTrustDomains := []*entity.TrustDomain{ + {ID: tdUUID1, Name: td1Name}, + {ID: tdUUID2, Name: NewTrustDomain(t, td2)}, + {ID: tdUUID3, Name: NewTrustDomain(t, td3)}, + } + + fakeRelationships := []*entity.Relationship{ + {ID: r1ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + {ID: r2ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID2.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Pending), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + {ID: r3ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + {ID: r4ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Denied)}, + {ID: r5ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + } + + setup.FakeDatabase.WithTrustDomains(fakeTrustDomains...) + setup.FakeDatabase.WithRelationships(fakeRelationships...) + + t.Run("Accepted Filter", func(t *testing.T) { + expectedRelations := mapRelationships([]*entity.Relationship{ + {ID: r1ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Accepted)}, + }) + + assertFilter(t, setup, expectedRelations, api.Accepted) + }) + + t.Run("Denied Filter", func(t *testing.T) { + expectedRelations := mapRelationships([]*entity.Relationship{ + {ID: r3ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + {ID: r4ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Denied), TrustDomainBConsent: entity.ConsentStatus(api.Denied)}, + }) + + assertFilter(t, setup, expectedRelations, api.Denied) + }) + + t.Run("Pending Filter", func(t *testing.T) { + expectedRelations := mapRelationships([]*entity.Relationship{ + {ID: r2ID, TrustDomainAID: tdUUID1.UUID, TrustDomainBID: tdUUID2.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Pending), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + {ID: r5ID, TrustDomainAID: tdUUID2.UUID, TrustDomainBID: tdUUID3.UUID, TrustDomainAConsent: entity.ConsentStatus(api.Accepted), TrustDomainBConsent: entity.ConsentStatus(api.Pending)}, + }) + + assertFilter(t, setup, expectedRelations, api.Pending) + }) + }) + + t.Run("Should raise a bad request when receiving undefined status filter", func(t *testing.T) { + + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, relationshipsPath, nil) + + // Approved filter + var randomFilter api.ConsentStatus = "a random filter" + params := admin.GetRelationshipsParams{ + Status: &randomFilter, + } + + err := setup.Handler.GetRelationships(setup.EchoCtx, params) + assert.Error(t, err) + + httpErr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusBadRequest, httpErr.Code) + assert.Empty(t, setup.Recorder.Body) + + expectedMsg := fmt.Sprintf( + "status filter [`%v`] is not supported, accepted values [%v, %v, %v]", + randomFilter, api.Accepted, api.Denied, api.Pending, + ) + + assert.ErrorContains(t, err, expectedMsg) + }) +} + +func assertFilter( + t *testing.T, + setup *ManagementTestSetup, + expectedRelations []*api.Relationship, + status api.ConsentStatus, +) { + setup.Refresh() + + strAddress := status + params := admin.GetRelationshipsParams{ + Status: &strAddress, + } + + err := setup.Handler.GetRelationships(setup.EchoCtx, params) + assert.NoError(t, err) + + assert.Equal(t, http.StatusOK, setup.Recorder.Code) + assert.NotEmpty(t, setup.Recorder.Body) + + relationships := []*api.Relationship{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &relationships) + assert.NoError(t, err) + + assert.Len(t, relationships, len(expectedRelations)) + + assert.ElementsMatchf(t, relationships, expectedRelations, "%v status filter does not work properly", status) } func TestUDSPutRelationships(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") + relationshipsPath := "/relationships" + + t.Run("Successfully create a new relationship request", func(t *testing.T) { + + fakeTrustDomains := []*entity.TrustDomain{ + {ID: tdUUID1, Name: NewTrustDomain(t, td1)}, + {ID: tdUUID2, Name: NewTrustDomain(t, td2)}, + } + + reqBody := &admin.PutRelationshipJSONRequestBody{ + TrustDomainAId: tdUUID1.UUID, + TrustDomainBId: tdUUID2.UUID, + } + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, relationshipsPath, reqBody) + setup.FakeDatabase.WithTrustDomains(fakeTrustDomains...) + + err := setup.Handler.PutRelationship(setup.EchoCtx) + assert.NoError(t, err) + + assert.Equal(t, http.StatusCreated, setup.Recorder.Code) + + apiRelation := api.Relationship{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiRelation) + assert.NoError(t, err) + + assert.NotNil(t, apiRelation) + assert.Equal(t, tdUUID1.UUID, apiRelation.TrustDomainAId) + assert.Equal(t, tdUUID2.UUID, apiRelation.TrustDomainBId) + }) + + t.Run("Should not allow relationships request between inexistent trust domains", func(t *testing.T) { + + fakeTrustDomains := []*entity.TrustDomain{ + {ID: tdUUID1, Name: NewTrustDomain(t, td1)}, + } + + reqBody := &admin.PutRelationshipJSONRequestBody{ + TrustDomainAId: tdUUID1.UUID, + TrustDomainBId: tdUUID2.UUID, + } + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, relationshipsPath, reqBody) + setup.FakeDatabase.WithTrustDomains(fakeTrustDomains...) + + err := setup.Handler.PutRelationship(setup.EchoCtx) + assert.Error(t, err) + assert.Empty(t, setup.Recorder.Body.Bytes()) + + echoHTTPErr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusBadRequest, echoHTTPErr.Code) + + expectedErrorMsg := fmt.Sprintf("trust domain exists: %q", tdUUID2.UUID) + assert.Equal(t, expectedErrorMsg, echoHTTPErr.Message) + }) + + // Should we test sending wrong body formats ? } -func TestUDSGetRelationshipsRelationshipID(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") +func TestUDSGetRelationshipsByID(t *testing.T) { + relationshipsPath := "/relationships/%v" + + t.Run("Successfully get relationship information", func(t *testing.T) { + + fakeTrustDomains := []*entity.TrustDomain{ + {ID: tdUUID1, Name: NewTrustDomain(t, td1)}, + {ID: tdUUID2, Name: NewTrustDomain(t, td2)}, + } + + r1ID := NewNullableID() + fakeRelationship := &entity.Relationship{ + ID: r1ID, + TrustDomainAID: tdUUID1.UUID, + TrustDomainBID: tdUUID2.UUID, + } + + completePath := fmt.Sprintf(relationshipsPath, r1ID.UUID) + + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, completePath, nil) + setup.FakeDatabase.WithTrustDomains(fakeTrustDomains...) + setup.FakeDatabase.WithRelationships(fakeRelationship) + + err := setup.Handler.GetRelationshipByID(setup.EchoCtx, r1ID.UUID) + assert.NoError(t, err) + + assert.Equal(t, http.StatusOK, setup.Recorder.Code) + + apiRelation := api.Relationship{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiRelation) + assert.NoError(t, err) + + assert.NotNil(t, apiRelation) + assert.Equal(t, tdUUID1.UUID, apiRelation.TrustDomainAId) + assert.Equal(t, tdUUID2.UUID, apiRelation.TrustDomainBId) + }) + + t.Run("Should raise a not found request when try to get information about a relationship that doesn't exists", func(t *testing.T) { + completePath := fmt.Sprintf(relationshipsPath, r1ID.UUID) + + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, completePath, nil) + + err := setup.Handler.GetRelationshipByID(setup.EchoCtx, r1ID.UUID) + assert.Error(t, err) + assert.Empty(t, setup.Recorder.Body.Bytes()) + + echoHTTPerr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusNotFound, echoHTTPerr.Code) + assert.Equal(t, "relationship not found", echoHTTPerr.Message) + }) } func TestUDSPutTrustDomain(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") + trustDomainPath := "/trust-domain" + t.Run("Successfully create a new trust domain", func(t *testing.T) { + description := "A test trust domain" + reqBody := &admin.TrustDomainPut{ + Name: td1, + Description: &description, + } + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, trustDomainPath, reqBody) + + err := setup.Handler.PutTrustDomain(setup.EchoCtx) + assert.NoError(t, err) + + assert.Equal(t, http.StatusCreated, setup.Recorder.Code) + + apiTrustDomain := api.TrustDomain{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiTrustDomain) + assert.NoError(t, err) + + assert.NotNil(t, apiTrustDomain) + assert.Equal(t, td1, apiTrustDomain.Name) + assert.Equal(t, description, *apiTrustDomain.Description) + + }) + + t.Run("Should not allow creating trust domain with the same name of one already created", func(t *testing.T) { + reqBody := &admin.TrustDomainPut{ + Name: td1, + } + + fakeTrustDomains := entity.TrustDomain{ID: NewNullableID(), Name: NewTrustDomain(t, td1)} + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, trustDomainPath, reqBody) + setup.FakeDatabase.WithTrustDomains(&fakeTrustDomains) + + err := setup.Handler.PutTrustDomain(setup.EchoCtx) + assert.Error(t, err) + + echoHttpErr := err.(*echo.HTTPError) + + assert.Equal(t, http.StatusBadRequest, echoHttpErr.Code) + assert.ErrorContains(t, echoHttpErr, "trust domain already exists") + }) } -func TestUDSGetTrustDomainTrustDomainName(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") +func TestUDSGetTrustDomainByName(t *testing.T) { + trustDomainPath := "/trust-domain/%v" + + t.Run("Successfully retrieve trust domain information", func(t *testing.T) { + fakeTrustDomains := entity.TrustDomain{ID: tdUUID1, Name: NewTrustDomain(t, td1)} + + completePath := fmt.Sprintf(trustDomainPath, tdUUID1.UUID) + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, completePath, nil) + setup.FakeDatabase.WithTrustDomains(&fakeTrustDomains) + + err := setup.Handler.GetTrustDomainByName(setup.EchoCtx, td1) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, setup.Recorder.Code) + + apiTrustDomain := api.TrustDomain{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiTrustDomain) + assert.NoError(t, err) + + assert.Equal(t, td1, apiTrustDomain.Name) + assert.Equal(t, tdUUID1.UUID, apiTrustDomain.Id) + }) + + t.Run("Raise a not found when trying to retrieve a trust domain that does not exists", func(t *testing.T) { + completePath := fmt.Sprintf(trustDomainPath, tdUUID1.UUID) + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, completePath, nil) + + err := setup.Handler.GetTrustDomainByName(setup.EchoCtx, td1) + assert.Error(t, err) + + echoHttpErr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusNotFound, echoHttpErr.Code) + assert.Equal(t, "trust domain does not exists", echoHttpErr.Message) + }) +} + +func TestUDSPutTrustDomainByName(t *testing.T) { + trustDomainPath := "/trust-domain/%v" + + t.Run("Successfully updated a trust domain", func(t *testing.T) { + fakeTrustDomains := entity.TrustDomain{ID: tdUUID1, Name: NewTrustDomain(t, td1)} + + completePath := fmt.Sprintf(trustDomainPath, tdUUID1.UUID) + + description := "I am being updated" + reqBody := &admin.PutTrustDomainByNameJSONRequestBody{ + Id: tdUUID1.UUID, + Name: td1, + Description: &description, + } + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, completePath, reqBody) + setup.FakeDatabase.WithTrustDomains(&fakeTrustDomains) + + err := setup.Handler.PutTrustDomainByName(setup.EchoCtx, tdUUID1.UUID) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, setup.Recorder.Code) + + apiTrustDomain := api.TrustDomain{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiTrustDomain) + assert.NoError(t, err) + + assert.Equal(t, td1, apiTrustDomain.Name) + assert.Equal(t, tdUUID1.UUID, apiTrustDomain.Id) + assert.Equal(t, description, *apiTrustDomain.Description) + }) + + t.Run("Raise a not found when trying to updated a trust domain that does not exists", func(t *testing.T) { + completePath := fmt.Sprintf(trustDomainPath, tdUUID1.UUID) + + // Fake Request body + description := "I am being updated" + reqBody := &admin.PutTrustDomainByNameJSONRequestBody{ + Id: tdUUID1.UUID, + Name: td1, + Description: &description, + } + + // Setup + setup := NewManagementTestSetup(t, http.MethodPut, completePath, reqBody) + + err := setup.Handler.PutTrustDomainByName(setup.EchoCtx, tdUUID1.UUID) + assert.Error(t, err) + assert.Empty(t, setup.Recorder.Body.Bytes()) + + echoHTTPErr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusNotFound, echoHTTPErr.Code) + expectedErrorMsg := fmt.Sprintf("trust domain exists: %q", tdUUID1.UUID) + assert.Equal(t, expectedErrorMsg, echoHTTPErr.Message) + }) +} + +func TestUDSGetJoinToken(t *testing.T) { + trustDomainPath := "/trust-domain/%v/join-token" + + t.Run("Successfully generates a join token for the trust domain", func(t *testing.T) { + td1ID := NewNullableID() + fakeTrustDomains := entity.TrustDomain{ID: td1ID, Name: NewTrustDomain(t, td1)} + + completePath := fmt.Sprintf(trustDomainPath, td1) + + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, completePath, nil) + setup.FakeDatabase.WithTrustDomains(&fakeTrustDomains) + + err := setup.Handler.GetJoinToken(setup.EchoCtx, td1) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, setup.Recorder.Code) + + apiJToken := admin.JoinTokenResult{} + err = json.Unmarshal(setup.Recorder.Body.Bytes(), &apiJToken) + assert.NoError(t, err) + + assert.NotEmpty(t, apiJToken) + }) + + t.Run("Raise a bad request when trying to generates a join token for the trust domain that does not exists", func(t *testing.T) { + completePath := fmt.Sprintf(trustDomainPath, td1) + + // Setup + setup := NewManagementTestSetup(t, http.MethodGet, completePath, nil) + + err := setup.Handler.GetJoinToken(setup.EchoCtx, td1) + assert.Error(t, err) + + echoHttpErr := err.(*echo.HTTPError) + assert.Equal(t, http.StatusBadRequest, echoHttpErr.Code) + + expectedMsg := fmt.Errorf("trust domain exists: %q", td1) + assert.Equal(t, expectedMsg.Error(), echoHttpErr.Message) + }) } -func TestUDSPutTrustDomainTrustDomainName(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") +func NewNullableID() uuid.NullUUID { + return uuid.NullUUID{ + Valid: true, + UUID: uuid.New(), + } } -func TestUDSPostTrustDomainTrustDomainNameJoinToken(t *testing.T) { - t.Skip("Missing tests will be added when the API be implemented") +func NewTrustDomain(t *testing.T, tdName string) spiffeid.TrustDomain { + td, err := spiffeid.TrustDomainFromString(tdName) + assert.NoError(t, err) + return td } diff --git a/pkg/server/endpoints/run.go b/pkg/server/endpoints/run.go index 4611d9935..bd83fcd5b 100644 --- a/pkg/server/endpoints/run.go +++ b/pkg/server/endpoints/run.go @@ -8,6 +8,7 @@ import ( "crypto/x509/pkix" "errors" "fmt" + "github.com/HewlettPackard/galadriel/pkg/server/db" "net" "net/http" "strings" @@ -22,7 +23,6 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/x509ca" adminapi "github.com/HewlettPackard/galadriel/pkg/server/api/admin" harvesterapi "github.com/HewlettPackard/galadriel/pkg/server/api/harvester" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/sirupsen/logrus" @@ -43,7 +43,7 @@ type Endpoints struct { // TODO: unexport these fields TCPAddress *net.TCPAddr LocalAddr net.Addr - Datastore datastore.Datastore + Datastore db.Datastore Logger logrus.FieldLogger x509CA x509ca.X509CA @@ -70,7 +70,7 @@ func New(c *Config) (*Endpoints, error) { return &Endpoints{ TCPAddress: c.TCPAddress, LocalAddr: c.LocalAddress, - Datastore: c.Datastore, + Datastore: c.Catalog.GetDatastore(), Logger: c.Logger, x509CA: c.Catalog.GetX509CA(), jwtIssuer: c.JWTIssuer, diff --git a/pkg/server/endpoints/run_test.go b/pkg/server/endpoints/run_test.go index ba26d5e3e..41f925931 100644 --- a/pkg/server/endpoints/run_test.go +++ b/pkg/server/endpoints/run_test.go @@ -10,6 +10,7 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/keymanager" "github.com/HewlettPackard/galadriel/pkg/common/x509ca" "github.com/HewlettPackard/galadriel/pkg/common/x509ca/disk" + "github.com/HewlettPackard/galadriel/pkg/server/db" "github.com/HewlettPackard/galadriel/test/certtest" "github.com/jmhodges/clock" "github.com/sirupsen/logrus/hooks/test" @@ -18,6 +19,7 @@ import ( ) type fakeCatalog struct { + ds db.Datastore x509ca x509ca.X509CA keyManager keymanager.KeyManager } @@ -30,6 +32,10 @@ func (c fakeCatalog) GetKeyManager() keymanager.KeyManager { return c.keyManager } +func (c fakeCatalog) GetDatastore() db.Datastore { + return c.ds +} + func TestListenAndServe(t *testing.T) { config := newEndpointTestConfig(t) diff --git a/pkg/server/server.go b/pkg/server/server.go index beed416f3..5040274a8 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -12,7 +12,6 @@ import ( "github.com/HewlettPackard/galadriel/pkg/common/telemetry" "github.com/HewlettPackard/galadriel/pkg/common/util" "github.com/HewlettPackard/galadriel/pkg/server/catalog" - "github.com/HewlettPackard/galadriel/pkg/server/datastore" "github.com/HewlettPackard/galadriel/pkg/server/endpoints" "github.com/google/uuid" ) @@ -46,12 +45,6 @@ func (s *Server) run(ctx context.Context) error { return fmt.Errorf("failed to load catalogs from providers config: %w", err) } - // TODO: consider moving the datastore to the catalog? - ds, err := datastore.NewSQLDatastore(s.config.Logger, s.config.DBConnString) - if err != nil { - return fmt.Errorf("failed to create datastore: %w", err) - } - jwtIssuer, err := s.createJWTIssuer(ctx, cat.GetKeyManager()) if err != nil { return fmt.Errorf("failed to create JWT issuer: %w", err) @@ -63,7 +56,7 @@ func (s *Server) run(ctx context.Context) error { } jwtValidator := jwt.NewDefaultJWTValidator(c) - endpointsServer, err := s.newEndpointsServer(cat, ds, jwtIssuer, jwtValidator) + endpointsServer, err := s.newEndpointsServer(cat, jwtIssuer, jwtValidator) if err != nil { return fmt.Errorf("failed to create endpoints server: %w", err) } @@ -75,12 +68,11 @@ func (s *Server) run(ctx context.Context) error { return err } -func (s *Server) newEndpointsServer(catalog catalog.Catalog, ds datastore.Datastore, jwtIssuer jwt.Issuer, jwtValidator jwt.Validator) (endpoints.Server, error) { +func (s *Server) newEndpointsServer(catalog catalog.Catalog, jwtIssuer jwt.Issuer, jwtValidator jwt.Validator) (endpoints.Server, error) { config := &endpoints.Config{ TCPAddress: s.config.TCPAddress, LocalAddress: s.config.LocalAddress, Logger: s.config.Logger.WithField(telemetry.SubsystemName, telemetry.Endpoints), - Datastore: ds, Catalog: catalog, JWTIssuer: jwtIssuer, JWTValidator: jwtValidator, diff --git a/pkg/server/datastore/fakedatabase.go b/test/fakes/fakedatastore/fakedatabase.go similarity index 96% rename from pkg/server/datastore/fakedatabase.go rename to test/fakes/fakedatastore/fakedatabase.go index a8fee06cc..541f62391 100644 --- a/pkg/server/datastore/fakedatabase.go +++ b/test/fakes/fakedatastore/fakedatabase.go @@ -1,5 +1,4 @@ -// TODO: move to folder test/fakes/fakedatastpre -package datastore +package fakedatastore import ( "context" @@ -74,14 +73,15 @@ func (db *FakeDatabase) CreateOrUpdateTrustDomain(ctx context.Context, req *enti return nil, err } - req.ID = uuid.NullUUID{ - UUID: uuid.New(), - Valid: true, + if !req.ID.Valid { + req.ID = uuid.NullUUID{ + UUID: uuid.New(), + Valid: true, + } + req.CreatedAt = time.Now() } - req.CreatedAt = time.Now() req.UpdatedAt = time.Now() - db.trustDomains[req.ID.UUID] = req return req, nil @@ -174,9 +174,7 @@ func (db *FakeDatabase) CreateOrUpdateBundle(ctx context.Context, req *entity.Bu } } - req.CreatedAt = time.Now() req.UpdatedAt = time.Now() - db.bundles[req.ID.UUID] = req return req, nil @@ -390,7 +388,18 @@ func (db *FakeDatabase) CreateOrUpdateRelationship(ctx context.Context, req *ent return nil, err } - return nil, nil + if !req.ID.Valid { + req.ID = uuid.NullUUID{ + Valid: true, + UUID: uuid.New(), + } + req.CreatedAt = time.Now() + } + + req.UpdatedAt = time.Now() + db.relationships[req.ID.UUID] = req + + return req, nil } func (db *FakeDatabase) FindRelationshipByID(ctx context.Context, relationshipID uuid.UUID) (*entity.Relationship, error) {