spicegen

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2024 License: MIT

README

spicegen

Generate strongly typed clients from spicedb schemas. See _examples/ for a sample generated client.

Use at your own discretion! PRs welcome.

Usage of spicegen:
  -client-name string
        Optional. The name of the client impl created by spicegen. (default "Client")
  -ignore-prefix string
        Optional. A prefix string to match against permission/relation names to ignore. Used to avoid exposing implicit permissions.
  -import-path string
        Required. The fully qualified module path for importing the generated client. e.x. github.com/ben-mays/spicegen/example
  -interface-name string
        Optional. The name of the client interface created by spicegen. (default "SpiceGenClient")
  -output-package string
        Optional. The package name of the generated client. This will default to the output directory name if not given.
  -output-path string
        Optional. The file or directory to which the generated client will be written. If a directory is given, the output filename will be client.go. If no output is given, current directory is used.
  -schema-file string
        Optional. Path to schema file for generation. If none given, the tool will look for schema.text in the current directory. (default "schema.text")
  -skip-client
        Optional. If present, will skip client generation and only generate types and permissions.

spicegen will generate a top-level Resource enum type that captures all object definitions in the schema.

type ResourceType string

const (
	Organization ResourceType = "organization"
	Document     ResourceType = "document"
	User         ResourceType = "user"
)

type Resource interface {
	ResourceType() ResourceType
	ID() string
}

type DocumentResource struct {
	rid string
}

func (r DocumentResource) ID() string {
	return r.rid
}

func (r DocumentResource) ResourceType() ResourceType {
	return Document
}

func NewDocumentResource(ID string) DocumentResource {
	return DocumentResource{rid: ID}
}

For each resource type, we generate a set of enums for both permissions and relations (i.e. DocPermission and DocRelation) at permissions/$resource_type/$resource_type.go (i.e. permissions/doc/doc.go):

type DocumentPermission string

const (
	ViewPermission DocumentPermission = "view"
)

type DocumentRelation string

const (
	DocorgRelation DocumentRelation = "docorg"
	ReaderRelation DocumentRelation = "reader"
	WriterRelation DocumentRelation = "writer"
)

These resource-specific types are then used by the top-level generated client to force inputs that match your schema:

AddDocRelationship(ctx context.Context, 
   resource DocResource, 
   relation document.DocRelation, 
   subject Resource, 
   opts *AddRelationshipOptions) (bool, error)

And can be used with by wrapping inputs in the right resource types (in practice you would do this mapping in your datastore layer):

// Add doc:readme to organization:foo
svc.AddDocRelationship(ctx, authz.NewDocResource("readme"), doc.DocorgRelation, authz.NewOrganizationResource("foo"), nil)

// Can org admin Ben view doc:readme? Expectation: yes
svc.CheckDocPermission(ctx, authz.NewDocResource("readme"), doc.ViewPermission, authz.NewUserResource("ben"), nil)

Renaming generated relations

spicegen allows renaming a permission or relation using the //spicegen:rename=$new_name tag in a comment. This will only change the generated enum value, not the underlying schema string.

Subject Types

The parser today is unable to determine subject types for indirect relations nor generate a union type to fit multiple subjects (i.e. user | team). Spicegen will enforce allowed types at runtime though. It will enforce optional subject relations as well.

You can override the spicegen inferred types by specifying //spicegen:subject_type=$resource comment(s) on the relation:

definition document {
  ...
  /** view indicates whether the user can view the document */
  /** //spicegen:subject_type=user */
  permission view = reader + writer + docorg->view_all_documents
}

The above tag will result in the generator using ["user"] as the allowed subject resource. If only one allowed subject type is present for an entire resource, spicegen will use that concrete subject resource type in the resource API.

Example

go run cmd/spicegen/main.go -import-path github.com/ben-mays/spicegen/_examples -schema-file _examples/schema.text -output-path _examples -output-package authz

TODO

  • Support caveat types
  • Auto mapping allowed types [Done?]
  • Auto-add optional relations [Done]
  • Functional opts

Directories

Path Synopsis
Code generated by spicegen.
Code generated by spicegen.
permissions/document
Code generated by spicegen.
Code generated by spicegen.
permissions/organization
Code generated by spicegen.
Code generated by spicegen.
permissions/team
Code generated by spicegen.
Code generated by spicegen.
permissions/user
Code generated by spicegen.
Code generated by spicegen.
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL