Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e8b7669
Define protos for simple namespaces CRUD
jakedoublev Jan 19, 2024
a36c14a
add generated namespaces sdk files
jakedoublev Jan 19, 2024
722a1ce
add grpcurl namespaces examples
jakedoublev Jan 19, 2024
a4b2db2
feat: implement attributes
jrschumacher Jan 19, 2024
3665174
add db layer for namespaces and add the serviceclient to the SDK afte…
jakedoublev Jan 19, 2024
d44cb49
merging in latest work
jakedoublev Jan 19, 2024
f8fbb90
provide namespace back in response when creating/updating and add ser…
jakedoublev Jan 20, 2024
3817b5a
make sure to register namespaces service on start
jakedoublev Jan 20, 2024
44505c0
namespaces cleanup
jakedoublev Jan 22, 2024
7f3d571
namespaces test suite boilerplate
jakedoublev Jan 22, 2024
17130db
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 22, 2024
493a999
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 23, 2024
2ffca7a
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 23, 2024
00bbaac
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 23, 2024
8d3a621
move all row scanning to db layer
jakedoublev Jan 23, 2024
2ac05e5
service work for namespaces
jakedoublev Jan 23, 2024
c0b7de3
use tableField func in attributes
jakedoublev Jan 23, 2024
49e3a7e
use proper namespace table name
jakedoublev Jan 23, 2024
3939449
require name and id, but id only once on update, and require only nam…
jakedoublev Jan 23, 2024
81cbd0b
ensure working crud of namespaces
jakedoublev Jan 23, 2024
9ee0cb2
lint fix
jakedoublev Jan 23, 2024
6ef08cb
fix grpcurl update example
jakedoublev Jan 23, 2024
4eacdee
add helper for checking constraint violations
jakedoublev Jan 23, 2024
624b006
improve error handling
jakedoublev Jan 23, 2024
6b541a3
consume error handling functions
jakedoublev Jan 23, 2024
c733264
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 24, 2024
ecea196
update to define and test more types of postgres 'bad request' type e…
jakedoublev Jan 24, 2024
03f27f9
consume latest error helper updates
jakedoublev Jan 24, 2024
0df765c
validate working error handling with logs and messages in namespaces
jakedoublev Jan 24, 2024
35b1b44
fix deletion
jakedoublev Jan 24, 2024
f4925e2
improve error wrapping by moving it down into the query and exec leve…
jakedoublev Jan 24, 2024
9b2efb4
consume latest db error changes
jakedoublev Jan 24, 2024
8f9804f
avoid nil pointer dereference
jakedoublev Jan 25, 2024
6a8d55d
Merge branch 'policy-config-changes' into feat/namespaces
jakedoublev Jan 25, 2024
86f55ff
declutter diff with varied lint settings
jakedoublev Jan 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/opentdf/opentdf-v2-poc/services/kasregistry"
"github.com/opentdf/opentdf-v2-poc/services/subjectmapping"

"github.com/opentdf/opentdf-v2-poc/services/namespaces"
// "github.com/opentdf/opentdf-v2-poc/services/keyaccessgrants"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -130,9 +131,7 @@ func createDatabaseClient(conf db.Config) (*db.Client, error) {

//nolint:revive // the opa engine will be used in the future
func RegisterServices(_ config.Config, otdf *server.OpenTDFServer, dbClient *db.Client, eng *opa.Engine) error {
var (
err error
)
var err error
slog.Info("registering acre server")
err = resourcemapping.NewResourceMappingServer(dbClient, otdf.GrpcServer, otdf.Mux)
if err != nil {
Expand All @@ -157,5 +156,11 @@ func RegisterServices(_ config.Config, otdf *server.OpenTDFServer, dbClient *db.
return fmt.Errorf("could not register key access grants service: %w", err)
}

slog.Info("registering namespaces server")
err = namespaces.NewNamespacesServer(dbClient, otdf.GrpcServer, otdf.Mux)
if err != nil {
return fmt.Errorf("could not register namespaces service: %w", err)
}

return nil
}
12 changes: 7 additions & 5 deletions internal/db/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
"google.golang.org/protobuf/encoding/protojson"
)

var AttributeTable = tableName(TableAttributes)
var AttributeRuleTypeEnumPrefix = "ATTRIBUTE_RULE_TYPE_ENUM_"
var (
AttributeTable = tableName(TableAttributes)
AttributeRuleTypeEnumPrefix = "ATTRIBUTE_RULE_TYPE_ENUM_"
)

func attributesRuleTypeEnumTransformIn(value string) string {
return strings.TrimPrefix(value, AttributeRuleTypeEnumPrefix)
Expand Down Expand Up @@ -197,7 +199,7 @@ func (c Client) GetAttribute(ctx context.Context, id string) (*attributes.Attrib

func getAttributesByNamespaceSql(namespaceId string) (string, []interface{}, error) {
return attributesSelect().
Where(sq.Eq{"namespace_id": namespaceId}).
Where(sq.Eq{tableField(AttributeTable, "namespace_id"): namespaceId}).
From(AttributeTable).
ToSql()
}
Expand Down Expand Up @@ -266,7 +268,7 @@ func updateAttributeSql(id string, name string, rule string, metadata []byte) (s
}

return sb.Set("metadata", metadata).
Where(sq.Eq{"id": id}).
Where(sq.Eq{tableField(AttributeTable, "id"): id}).
ToSql()
}
func (c Client) UpdateAttribute(ctx context.Context, id string, attr *attributes.AttributeCreateUpdate) (*attributes.Attribute, error) {
Expand Down Expand Up @@ -294,7 +296,7 @@ func (c Client) UpdateAttribute(ctx context.Context, id string, attr *attributes
func deleteAttributeSql(id string) (string, []interface{}, error) {
return newStatementBuilder().
Delete(AttributeTable).
Where(sq.Eq{"id": id}).
Where(sq.Eq{tableField(AttributeTable, "id"): id}).
ToSql()
}
func (c Client) DeleteAttribute(ctx context.Context, id string) (*attributes.Attribute, error) {
Expand Down
157 changes: 157 additions & 0 deletions internal/db/namespaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package db

import (
"context"
"errors"
"log/slog"

sq "github.com/Masterminds/squirrel"
"github.com/opentdf/opentdf-v2-poc/sdk/namespaces"
"github.com/opentdf/opentdf-v2-poc/services"
)

var NamespacesTable = tableName(TableNamespaces)

func getNamespaceSql(id string) (string, []interface{}, error) {
return newStatementBuilder().
Select("*").
From(NamespacesTable).
Where(sq.Eq{tableField(NamespacesTable, "id"): id}).
ToSql()
}

func (c Client) GetNamespace(ctx context.Context, id string) (*namespaces.Namespace, error) {
sql, args, err := getNamespaceSql(id)
if err != nil {
slog.Error(services.ErrGettingResource, slog.String("error", err.Error()))
return nil, err
}

row, err := c.queryRow(ctx, sql, args, err)
if err != nil {
slog.Error(services.ErrGettingResource, slog.String("error", err.Error()))
return nil, err
}

namespace := namespaces.Namespace{Id: "", Name: ""}
if err := row.Scan(&namespace.Id, &namespace.Name); err != nil {
if e := WrapIfKnownInvalidQueryErr(err); e != nil {
slog.Error(services.ErrNotFound, slog.String("error", e.Error()))
return nil, e
}

slog.Error(services.ErrGettingResource, slog.String("error", err.Error()))
return nil, err
}

return &namespace, nil
}

func listNamespacesSql() (string, []interface{}, error) {
return newStatementBuilder().
Select("*").
From(NamespacesTable).
ToSql()
}

func (c Client) ListNamespaces(ctx context.Context) ([]*namespaces.Namespace, error) {
namespacesList := []*namespaces.Namespace{}

sql, args, err := listNamespacesSql()
if err != nil {
slog.Error(services.ErrListingResource, slog.String("error", err.Error()))
return nil, err
}

rows, err := c.query(ctx, sql, args, err)
if err != nil {
slog.Error(services.ErrListingResource, slog.String("error", err.Error()))
return nil, err
}

for rows.Next() {
var namespace namespaces.Namespace
if err := rows.Scan(&namespace.Id, &namespace.Name); err != nil {
slog.Error(services.ErrListingResource, slog.String("error", err.Error()))
return nil, err
}
namespacesList = append(namespacesList, &namespace)
}

return namespacesList, nil
}

func createNamespaceSql(name string) (string, []interface{}, error) {
return newStatementBuilder().
Insert(NamespacesTable).
Columns("name").
Values(name).
Suffix("RETURNING \"id\"").
ToSql()
}

func (c Client) CreateNamespace(ctx context.Context, name string) (string, error) {
sql, args, err := createNamespaceSql(name)
var id string

if r, e := c.queryRow(ctx, sql, args, err); e != nil {
slog.Error(services.ErrCreatingResource, slog.String("error", e.Error()))
return "", e
} else if e := r.Scan(&id); e != nil {
if IsConstraintViolationForColumnVal(e, TableNamespaces, "name") {
e = errors.Join(NewUniqueAlreadyExistsError(name), e)
slog.Error(services.ErrConflict, slog.String("error", e.Error()))
return "", e
}

slog.Error(services.ErrCreatingResource, slog.String("error", e.Error()))
return "", e
}
return id, nil
}

func updateNamespaceSql(id string, name string) (string, []interface{}, error) {
return newStatementBuilder().
Update(NamespacesTable).
Set("name", name).
Where(sq.Eq{tableField(NamespacesTable, "id"): id}).
ToSql()
}

func (c Client) UpdateNamespace(ctx context.Context, id string, name string) (*namespaces.Namespace, error) {
sql, args, err := updateNamespaceSql(id, name)

if e := c.exec(ctx, sql, args, err); e != nil {
if IsConstraintViolationForColumnVal(e, TableNamespaces, "name") {
e = errors.Join(NewUniqueAlreadyExistsError(name), e)
slog.Error(services.ErrConflict, slog.String("error", e.Error()))
return nil, e
}

if err := WrapIfKnownInvalidQueryErr(e); err != nil {
if errors.Is(err, ErrNotFound) {
slog.Error(services.ErrNotFound, slog.String("error", err.Error()))
}
return nil, err
}

slog.Error(services.ErrUpdatingResource, slog.String("error", e.Error()))
return nil, e
}

return c.GetNamespace(ctx, id)
}

func deleteNamespaceSql(id string) (string, []interface{}, error) {
return newStatementBuilder().
Delete(NamespacesTable).
Where(sq.Eq{"id": id}).
Suffix("RETURNING \"id\"").
ToSql()
}

func (c Client) DeleteNamespace(ctx context.Context, id string) error {
sql, args, err := deleteNamespaceSql(id)

return c.exec(ctx, sql, args, err)
}
6 changes: 3 additions & 3 deletions migrations/20240118000000_create_new_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CREATE SCHEMA IF NOT EXISTS opentdf;
CREATE TYPE attribute_definition_rule AS ENUM ('UNSPECIFIED', 'ALL_OF', 'ANY_OF', 'HIERARCHY');
CREATE TYPE subject_mappings_operator AS ENUM ('UNSPECIFIED', 'IN', 'NOT_IN');

CREATE TABLE IF NOT EXISTS opentdf.namespaces
CREATE TABLE IF NOT EXISTS opentdf.attribute_namespaces
(
-- generate on create
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
Expand All @@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS opentdf.namespaces
CREATE TABLE IF NOT EXISTS opentdf.attribute_definitions
(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
namespace_id UUID NOT NULL REFERENCES opentdf.namespaces(id),
namespace_id UUID NOT NULL REFERENCES opentdf.attribute_namespaces(id),
name VARCHAR NOT NULL,
rule attribute_definition_rule NOT NULL,
metadata JSONB,
Expand Down Expand Up @@ -82,7 +82,7 @@ DROP TABLE IF EXISTS opentdf.attribute_definition_key_access_grants;
DROP TABLE IF EXISTS opentdf.key_access_servers;
DROP TABLE IF EXISTS opentdf.attribute_values;
DROP TABLE IF EXISTS opentdf.attribute_definitions;
DROP TABLE IF EXISTS opentdf.namespaces;
DROP TABLE IF EXISTS opentdf.attribute_namespaces;

DROP TYPE attribute_definition_rule;
DROP TYPE subject_mappings_operator;
Expand Down
Loading