Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(permission): support permission setting, sharing public, sharing by code(link) #256

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ database:
host: pg-sql
port: 5432
name: pipeline
version: 4
version: 5
timezone: Etc/UTC
pool:
idleconnections: 5
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
github.com/iancoleman/strcase v0.2.0
github.com/influxdata/influxdb-client-go/v2 v2.12.3
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230914101327-aa4d53e6c5fc
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230925031115-0d2b2294c423
github.com/instill-ai/usage-client v0.2.4-alpha.0.20230814155646-874e57a1e4b0
github.com/instill-ai/x v0.3.0-alpha
github.com/knadh/koanf v1.5.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1076,8 +1076,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.12.3 h1:28nRlNMRIV4QbtIUvxhWqaxn0
github.com/influxdata/influxdb-client-go/v2 v2.12.3/go.mod h1:IrrLUbCjjfkmRuaCiGQg4m2GbkaeJDcuWoxiWdQEbA0=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230914101327-aa4d53e6c5fc h1:RGrUkr9dnUxQs74/x1lWdLhIODnr6m6dZ/6UY+n08qw=
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230914101327-aa4d53e6c5fc/go.mod h1:z/L84htamlJ4QOR4jtJOaa+y3Hihu7WEqOipW0LEkmc=
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230925031115-0d2b2294c423 h1:xS/TVO8C4emley5/E6wkbzl69GlVTd2EBNbLIqIqSbI=
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20230925031115-0d2b2294c423/go.mod h1:z/L84htamlJ4QOR4jtJOaa+y3Hihu7WEqOipW0LEkmc=
github.com/instill-ai/usage-client v0.2.4-alpha.0.20230814155646-874e57a1e4b0 h1:9QoCxaktvqGJYGjN8KhkWsv1DVfwbt5G1d/Ycx1kJxo=
github.com/instill-ai/usage-client v0.2.4-alpha.0.20230814155646-874e57a1e4b0/go.mod h1:SELFgirs+28Wfnh0kGw02zttit4pUeKLKp17zGsTu6g=
github.com/instill-ai/x v0.3.0-alpha h1:z9fedROOG2dVHhswBfVwU/hzHuq8/JKSUON7inF+FH8=
Expand Down
1 change: 1 addition & 0 deletions pkg/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const MaxPayloadSize = 1024 * 1024 * 32
// Constants for resource owner
const DefaultUserID string = "admin"
const HeaderUserUIDKey = "jwt-sub"
const HeaderInstillCodeKey = "instill-code"
const StartConnectorId = "start-operator"
const EndConnectorId = "end-operator"
const ReturnTracesKey = "instill-return-traces"
96 changes: 87 additions & 9 deletions pkg/datamodel/datamodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ type Pipeline struct {
Description sql.NullString
Recipe *Recipe `gorm:"type:jsonb"`
DefaultReleaseUID uuid.UUID
Visibility PipelineVisibility `sql:"type:valid_visibility"`
Permission *Permission `gorm:"type:jsonb"`
ShareCode string
}

// PipelineRelease is the data model of the pipeline release table
Expand All @@ -50,8 +51,7 @@ type PipelineRelease struct {
ID string
PipelineUID uuid.UUID
Description sql.NullString
Recipe *Recipe `gorm:"type:jsonb"`
Visibility PipelineVisibility `sql:"type:valid_visibility"`
Recipe *Recipe `gorm:"type:jsonb"`
}

// Recipe is the data model of the pipeline recipe
Expand All @@ -67,8 +67,26 @@ type Component struct {
Configuration *structpb.Struct `json:"configuration"`
}

// PipelineVisibility is an alias type for Protobuf enum ConnectorType
type PipelineVisibility pipelinePB.Visibility
type Permission struct {
Users map[string]*PermissionUser `json:"users,omitempty"`
ShareCode *PermissionCode `json:"share_code,omitempty"`
}

// Permission
type PermissionUser struct {
Enabled bool `json:"enabled,omitempty"`
Role string `json:"role,omitempty"`
}

type PermissionCode struct {
User string `json:"user"`
Code string `json:"code"`
Enabled bool `json:"enabled,omitempty"`
Role string `json:"role,omitempty"`
}

// PipelineRole is an alias type for Protobuf enum
type PipelineRole pipelinePB.Role

// Scan function for custom GORM type Recipe
func (r *Recipe) Scan(value interface{}) error {
Expand All @@ -90,13 +108,73 @@ func (r *Recipe) Value() (driver.Value, error) {
return string(valueString), err
}

// Scan function for custom GORM type Recipe
func (p *Permission) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal value:", value))
}

if err := json.Unmarshal(bytes, &p); err != nil {
return err
}

return nil
}

// Value function for custom GORM type Recipe
func (p *Permission) Value() (driver.Value, error) {
valueString, err := json.Marshal(p)
return string(valueString), err
}

// Scan function for custom GORM type Recipe
func (p *PermissionUser) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal value:", value))
}

if err := json.Unmarshal(bytes, &p); err != nil {
return err
}

return nil
}

// Value function for custom GORM type Recipe
func (p *PermissionUser) Value() (driver.Value, error) {
valueString, err := json.Marshal(p)
return string(valueString), err
}

// Scan function for custom GORM type Recipe
func (p *PermissionCode) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal value:", value))
}

if err := json.Unmarshal(bytes, &p); err != nil {
return err
}

return nil
}

// Value function for custom GORM type Recipe
func (p *PermissionCode) Value() (driver.Value, error) {
valueString, err := json.Marshal(p)
return string(valueString), err
}

// Scan function for custom GORM type ReleaseStage
func (p *PipelineVisibility) Scan(value interface{}) error {
*p = PipelineVisibility(pipelinePB.Visibility_value[value.(string)])
func (p *PipelineRole) Scan(value interface{}) error {
*p = PipelineRole(pipelinePB.Role_value[value.(string)])
return nil
}

// Value function for custom GORM type ReleaseStage
func (p PipelineVisibility) Value() (driver.Value, error) {
return pipelinePB.Visibility(p).String(), nil
func (p PipelineRole) Value() (driver.Value, error) {
return pipelinePB.Role(p).String(), nil
}
Empty file.
6 changes: 6 additions & 0 deletions pkg/db/migration/000005_init.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
BEGIN;

ALTER TABLE public.pipeline ADD COLUMN "permission" JSONB DEFAULT NULL;
ALTER TABLE public.pipeline ADD COLUMN "share_code" VARCHAR(255) DEFAULT '' NOT NULL;

COMMIT;
2 changes: 1 addition & 1 deletion pkg/middleware/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func CustomMatcher(key string) (string, bool) {
switch key {
case "request-id":
return key, true
case "Instill-Return-Traces":
case "Instill-Return-Traces", "Instill-Code":
return key, true
case "X-B3-Traceid", "X-B3-Spanid", "X-B3-Sampled":
return key, true
Expand Down
28 changes: 12 additions & 16 deletions pkg/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import (
"github.com/instill-ai/pipeline-backend/pkg/logger"
"github.com/instill-ai/x/paginate"
"github.com/instill-ai/x/sterr"

pipelinePB "github.com/instill-ai/protogen-go/vdp/pipeline/v1alpha"
)

// TODO: in the repository, we'd better use uid as our function params
Expand All @@ -31,16 +29,14 @@ const DefaultPageSize = 10
// MaxPageSize is the maximum pagination page size if the assigned value is over this number
const MaxPageSize = 100

const VisibilityPublic = datamodel.PipelineVisibility(pipelinePB.Visibility_VISIBILITY_PUBLIC)

// Repository interface
type Repository interface {
ListPipelines(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error)
GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool) (*datamodel.Pipeline, error)
GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool, code string) (*datamodel.Pipeline, error)

CreateUserPipeline(ctx context.Context, ownerPermalink string, userPermalink string, pipeline *datamodel.Pipeline) error
ListUserPipelines(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error)
GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool) (*datamodel.Pipeline, error)
GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error)

UpdateUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, pipeline *datamodel.Pipeline) error
DeleteUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string) error
Expand Down Expand Up @@ -215,14 +211,14 @@ func (r *repository) listPipelines(ctx context.Context, where string, whereArgs

func (r *repository) ListPipelines(ctx context.Context, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) {
return r.listPipelines(ctx,
"(owner = ? OR visibility = ?)",
[]interface{}{userPermalink, VisibilityPublic},
"(owner = ? OR (permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}'))",
[]interface{}{userPermalink},
pageSize, pageToken, isBasicView, filter, showDeleted)
}
func (r *repository) ListUserPipelines(ctx context.Context, ownerPermalink string, userPermalink string, pageSize int64, pageToken string, isBasicView bool, filter filtering.Filter, showDeleted bool) ([]*datamodel.Pipeline, int64, string, error) {
return r.listPipelines(ctx,
"(owner = ? AND (visibility = ? OR ? = ?))",
[]interface{}{ownerPermalink, VisibilityPublic, ownerPermalink, userPermalink},
"(owner = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR ? = ?))",
[]interface{}{ownerPermalink, ownerPermalink, userPermalink},
pageSize, pageToken, isBasicView, filter, showDeleted)
}

Expand Down Expand Up @@ -258,18 +254,18 @@ func (r *repository) getUserPipeline(ctx context.Context, where string, whereArg
return &pipeline, nil
}

func (r *repository) GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool) (*datamodel.Pipeline, error) {
func (r *repository) GetUserPipelineByID(ctx context.Context, ownerPermalink string, userPermalink string, id string, isBasicView bool, code string) (*datamodel.Pipeline, error) {
return r.getUserPipeline(ctx,
"(id = ? AND (owner = ? AND (visibility = ? OR ? = ?)))",
[]interface{}{id, ownerPermalink, VisibilityPublic, ownerPermalink, userPermalink},
"(id = ? AND owner = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR (permission @> '{\"share_code\":{\"user\":\"users/*\", \"role\": \"ROLE_VIEWER\", \"enabled\": true}}' AND share_code = ?) OR ? = ?))",
[]interface{}{id, ownerPermalink, code, ownerPermalink, userPermalink},
isBasicView)
}

func (r *repository) GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool) (*datamodel.Pipeline, error) {
func (r *repository) GetPipelineByUID(ctx context.Context, userPermalink string, uid uuid.UUID, isBasicView bool, code string) (*datamodel.Pipeline, error) {
// TODO: ACL
return r.getUserPipeline(ctx,
"(uid = ? AND (visibility = ? OR owner = ?))",
[]interface{}{uid, VisibilityPublic, userPermalink},
"(uid = ? AND ((permission @> '{\"users\":{\"users/*\":{\"role\": \"ROLE_VIEWER\", \"enabled\": true}}}') OR (permission @> '{\"share_code\":{\"user\":\"users/*\", \"role\": \"ROLE_VIEWER\", \"enabled\": true}}' AND share_code = ?) OR owner = ?))",
[]interface{}{uid, code, userPermalink},
isBasicView)
}

Expand Down
38 changes: 34 additions & 4 deletions pkg/service/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,23 @@ func (s *service) PBToDBPipeline(ctx context.Context, userUid uuid.UUID, pbPipel

}

dbPermission := &datamodel.Permission{}
if pbPipeline.GetPermission() != nil {

if err != nil {
return nil, err
}

b, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(pbPipeline.GetPermission())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &dbPermission); err != nil {
return nil, err
}

}

return &datamodel.Pipeline{
Owner: owner,
ID: pbPipeline.GetId(),
Expand Down Expand Up @@ -407,7 +424,7 @@ func (s *service) PBToDBPipeline(ctx context.Context, userUid uuid.UUID, pbPipel
},

Recipe: recipe,
Visibility: datamodel.PipelineVisibility(pbPipeline.Visibility),
Permission: dbPermission,
}, nil
}

Expand Down Expand Up @@ -475,6 +492,21 @@ func (s *service) DBToPBPipeline(ctx context.Context, dbPipeline *datamodel.Pipe
}
}

pbPermission := &pipelinePB.Permission{}

b, err := json.Marshal(dbPipeline.Permission)
if err != nil {
return nil, err
}

err = protojson.Unmarshal(b, pbPermission)
if err != nil {
return nil, err
}
if pbPermission != nil && pbPermission.ShareCode != nil {
pbPermission.ShareCode.Code = dbPipeline.ShareCode
}

pbPipeline := pipelinePB.Pipeline{
Name: fmt.Sprintf("%s/pipelines/%s", owner, dbPipeline.ID),
Uid: dbPipeline.BaseDynamic.UID.String(),
Expand All @@ -489,8 +521,8 @@ func (s *service) DBToPBPipeline(ctx context.Context, dbPipeline *datamodel.Pipe
}
}(),
Description: &dbPipeline.Description.String,
Visibility: pipelinePB.Visibility(dbPipeline.Visibility),
Recipe: pbRecipe,
Permission: pbPermission,
}

if pbRecipe != nil && view == pipelinePB.View_VIEW_FULL && startComp != nil && endComp != nil {
Expand Down Expand Up @@ -584,7 +616,6 @@ func (s *service) PBToDBPipelineRelease(ctx context.Context, userUid uuid.UUID,

Recipe: recipe,
PipelineUID: pipelineUid,
Visibility: datamodel.PipelineVisibility(pbPipelineRelease.Visibility),
}, nil
}

Expand Down Expand Up @@ -656,7 +687,6 @@ func (s *service) DBToPBPipelineRelease(ctx context.Context, dbPipelineRelease *
}
}(),
Description: &dbPipelineRelease.Description.String,
Visibility: pipelinePB.Visibility(dbPipeline.Visibility),
Recipe: pbRecipe,
}

Expand Down
Loading