diff --git a/internal/relationships/validation.go b/internal/relationships/validation.go index 611f805c7..649c633b8 100644 --- a/internal/relationships/validation.go +++ b/internal/relationships/validation.go @@ -4,6 +4,7 @@ import ( "context" "github.com/authzed/spicedb/internal/namespace" + "github.com/authzed/spicedb/internal/services/shared" "github.com/authzed/spicedb/pkg/caveats" caveattypes "github.com/authzed/spicedb/pkg/caveats/types" "github.com/authzed/spicedb/pkg/datastore" @@ -28,8 +29,9 @@ func ValidateRelationshipUpdates( return item.Relationship }) + ts := schema.NewTypeSystem(schema.ResolverForDatastoreReader(reader)) // Load namespaces and caveats. - referencedNamespaceMap, referencedCaveatMap, err := loadNamespacesAndCaveats(ctx, rels, reader) + referencedNamespaceMap, referencedCaveatMap, err := loadNamespacesAndCaveats(ctx, rels, reader, ts) if err != nil { return err } @@ -52,6 +54,17 @@ func ValidateRelationshipUpdates( } } + // check if the relation is deprecated for create or touch operations + relsToCheck := make([]tuple.Relationship, 0, len(updates)) + for _, update := range updates { + if update.Operation == tuple.UpdateOperationTouch || update.Operation == tuple.UpdateOperationCreate { + relsToCheck = append(relsToCheck, update.Relationship) + } + } + if err := CheckDeprecationsOnRelationships(ctx, relsToCheck, ts); err != nil { + return err + } + return nil } @@ -65,8 +78,10 @@ func ValidateRelationshipsForCreateOrTouch( caveatTypeSet *caveattypes.TypeSet, rels ...tuple.Relationship, ) error { + ts := schema.NewTypeSystem(schema.ResolverForDatastoreReader(reader)) + // Load namespaces and caveats. - referencedNamespaceMap, referencedCaveatMap, err := loadNamespacesAndCaveats(ctx, rels, reader) + referencedNamespaceMap, referencedCaveatMap, err := loadNamespacesAndCaveats(ctx, rels, reader, ts) if err != nil { return err } @@ -84,10 +99,15 @@ func ValidateRelationshipsForCreateOrTouch( } } + // Validate if the resource, relation or subject is deprecated + if err := CheckDeprecationsOnRelationships(ctx, rels, ts); err != nil { + return err + } + return nil } -func loadNamespacesAndCaveats(ctx context.Context, rels []tuple.Relationship, reader datastore.Reader) (map[string]*schema.Definition, map[string]*core.CaveatDefinition, error) { +func loadNamespacesAndCaveats(ctx context.Context, rels []tuple.Relationship, reader datastore.Reader, ts *schema.TypeSystem) (map[string]*schema.Definition, map[string]*core.CaveatDefinition, error) { referencedNamespaceNames := mapz.NewSet[string]() referencedCaveatNamesWithContext := mapz.NewSet[string]() for _, rel := range rels { @@ -106,7 +126,6 @@ func loadNamespacesAndCaveats(ctx context.Context, rels []tuple.Relationship, re if err != nil { return nil, nil, err } - ts := schema.NewTypeSystem(schema.ResolverForDatastoreReader(reader)) referencedNamespaceMap = make(map[string]*schema.Definition, len(foundNamespaces)) for _, nsDef := range foundNamespaces { @@ -277,3 +296,24 @@ func hasNonEmptyCaveatContext(relationship tuple.Relationship) bool { relationship.OptionalCaveat.Context != nil && len(relationship.OptionalCaveat.Context.GetFields()) > 0 } + +// CheckDeprecationsOnRelationships checks the provided relationships for any deprecations, returning an error if applicable +func CheckDeprecationsOnRelationships( + ctx context.Context, + relationships []tuple.Relationship, + ts *schema.TypeSystem, +) error { + for _, rel := range relationships { + if err := checkForDeprecatedRelationsAndObjects(ctx, rel, ts); err != nil { + return err + } + } + return nil +} + +func checkForDeprecatedRelationsAndObjects(ctx context.Context, rel tuple.Relationship, ts *schema.TypeSystem) error { + if err := ts.CheckRelationshipDeprecation(ctx, rel); err != nil { + return shared.NewDeprecationError(err) + } + return nil +} diff --git a/internal/relationships/validation_test.go b/internal/relationships/validation_test.go index 8efcc91a5..1712cef62 100644 --- a/internal/relationships/validation_test.go +++ b/internal/relationships/validation_test.go @@ -306,6 +306,214 @@ func TestValidateRelationshipOperations(t *testing.T) { core.RelationTupleUpdate_CREATE, "subjects of type `user with somecaveat and expiration` are not allowed on relation `resource#viewer`", }, + { + "deprecation relation test", + `use deprecation + definition testuser {} + definition user {} + + definition document { + @deprecated(error,"deprecated, migrate away") + relation editor: testuser + relation viewer: user + }`, + "document:foo#editor@testuser:tom", + core.RelationTupleUpdate_CREATE, + "relation document#editor is deprecated: deprecated, migrate away", + }, + { + "deprecated namespace test", + `use deprecation + @deprecated(error, "deprecated, migrate away") + definition testuser {} + definition user {} + + definition document { + relation editor: testuser + }`, + "document:foo#editor@testuser:tom", + core.RelationTupleUpdate_CREATE, + "resource_type testuser is deprecated: deprecated, migrate away", + }, + { + "deprecated relation subject type", + `use deprecation + definition user {} + definition testuser {} + + definition platform { + relation viewer: user | @deprecated(warn, "comments") testuser + relation auditor: user | @deprecated(error, "test") testuser + }`, + "platform:foo#auditor@testuser:test", + core.RelationTupleUpdate_CREATE, + "resource_type testuser is deprecated: test", + }, + { + "deprecated relation same subject type with wildcard", + `use deprecation + definition user {} + definition testuser {} + + definition platform { + relation viewer: user | @deprecated(warn, "comments") testuser + relation auditor: testuser | @deprecated(error, "no wildcard please") testuser:* + }`, + "platform:foo#auditor@testuser:*", + core.RelationTupleUpdate_CREATE, + "wildcard allowed type testuser:* is deprecated: no wildcard please", + }, + { + "deprecated relation same subject type with write on non-wildcard relation", + `use deprecation + definition user {} + definition testuser {} + + definition platform { + relation viewer: user | @deprecated(warn, "comments") testuser + relation auditor: testuser | @deprecated(error, "no wildcard please") testuser:* + }`, + "platform:foo#auditor@testuser:test1", + core.RelationTupleUpdate_CREATE, + "", + }, + { + "deprecated subject without expiration when expiration required", + `use expiration + use deprecation + + @deprecated(error, "do not use testuser") + definition testuser {} + + definition document { + relation viewer: testuser with expiration + }`, + "document:foo#viewer@testuser:tom", + core.RelationTupleUpdate_CREATE, + "subjects of type `testuser` are not allowed on relation `document#viewer`; did you mean `testuser with expiration`?", + }, + { + "deprecated subject with expiration", + `use expiration + use deprecation + + @deprecated(error, "do not use testuser") + definition testuser {} + + definition document { + relation viewer: testuser with expiration + }`, + "document:foo#viewer@testuser:tom[expiration:2021-01-01T00:00:00Z]", + core.RelationTupleUpdate_CREATE, + "resource_type testuser is deprecated: do not use testuser", + }, + { + "deprecated subject with wrong caveat", + `use deprecation + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + caveat anothercaveat(somecondition int) { + somecondition == 42 + } + + @deprecated(error, "do not use testuser") + definition testuser {} + + definition document { + relation viewer: testuser with somecaveat + }`, + "document:foo#viewer@testuser:tom[anothercaveat]", + core.RelationTupleUpdate_CREATE, + "subjects of type `testuser with anothercaveat` are not allowed on relation `document#viewer`", + }, + { + "deprecated subject with correct caveat", + `use deprecation + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + @deprecated(error, "do not use testuser") + definition testuser {} + + definition document { + relation viewer: testuser with somecaveat + }`, + "document:foo#viewer@testuser:tom[somecaveat]", + core.RelationTupleUpdate_CREATE, + "resource_type testuser is deprecated: do not use testuser", + }, + { + "deprecated subject without caveat when required", + `use deprecation + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + @deprecated(error, "do not use testuser") + definition testuser {} + + definition document { + relation viewer: testuser with somecaveat + }`, + "document:foo#viewer@testuser:tom", + core.RelationTupleUpdate_CREATE, + "subjects of type `testuser` are not allowed on relation `document#viewer` without one of the following caveats: somecaveat", + }, + { + "deprecated user with caveat and expiration", + `use expiration + use deprecation + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + definition user {} + + definition document { + relation viewer: user | @deprecated(error, "don't use this") user with somecaveat and expiration + }`, + "document:foo#viewer@user:tom[somecaveat][expiration:2021-01-01T00:00:00Z]", + core.RelationTupleUpdate_CREATE, + "resource_type user with caveat `somecaveat` and expiration is deprecated: don't use this", + }, + { + "deprecated user with caveat only", + `use deprecation + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + definition user {} + + definition document { + relation viewer: user | @deprecated(error, "caveated access deprecated") user with somecaveat + }`, + "document:foo#viewer@user:tom[somecaveat]", + core.RelationTupleUpdate_CREATE, + "resource_type user with caveat `somecaveat` is deprecated: caveated access deprecated", + }, + { + "deprecated user with expiration only", + `use expiration + use deprecation + + definition user {} + + definition document { + relation viewer: user | @deprecated(error, "expiring access deprecated") user with expiration + }`, + "document:foo#viewer@user:tom[expiration:2021-01-01T00:00:00Z]", + core.RelationTupleUpdate_CREATE, + "resource_type user with expiration is deprecated: expiring access deprecated", + }, } for _, tc := range tcs { @@ -325,7 +533,7 @@ func TestValidateRelationshipOperations(t *testing.T) { op = tuple.Delete } - // Validate update. + // Validate update for delete. err = ValidateRelationshipUpdates(t.Context(), reader, caveattypes.Default.TypeSet, []tuple.RelationshipUpdate{ op(tuple.MustParse(tc.relationship)), }) diff --git a/internal/services/server.go b/internal/services/server.go index d003235b5..473cee54a 100644 --- a/internal/services/server.go +++ b/internal/services/server.go @@ -73,6 +73,7 @@ func RegisterGrpcServices( CaveatTypeSet: permSysConfig.CaveatTypeSet, AdditiveOnly: schemaServiceOption == V1SchemaServiceAdditiveOnly, ExpiringRelsEnabled: permSysConfig.ExpiringRelationshipsEnabled, + FeatureDeprecationEnabled: permSysConfig.DeprecatedRelationshipsAndObjectsEnabled, PerformanceInsightMetricsEnabled: permSysConfig.PerformanceInsightMetricsEnabled, } v1.RegisterSchemaServiceServer(srv, v1svc.NewSchemaServer(schemaConfig)) diff --git a/internal/services/shared/errors.go b/internal/services/shared/errors.go index 27b1e4d05..800a9ce74 100644 --- a/internal/services/shared/errors.go +++ b/internal/services/shared/errors.go @@ -47,6 +47,30 @@ func NewSchemaWriteDataValidationError(message string, args []any, metadata map[ } } +// DeprecationError is an error returned when a schema object or relation is deprecated. +type DeprecationError struct { + error +} + +func (err DeprecationError) GRPCStatus() *status.Status { + return spiceerrors.WithCodeAndDetails( + err, + codes.Aborted, + spiceerrors.ForReason( + // TODO: replace with a deprecation type error reason + v1.ErrorReason_ERROR_REASON_SCHEMA_TYPE_ERROR, + map[string]string{}, + ), + ) +} + +// NewDeprecationError wraps an error to indicate an attempted write to a deprecated object type, subject or allowed relation type. +func NewDeprecationError(err error) DeprecationError { + return DeprecationError{ + error: err, + } +} + // SchemaWriteDataValidationError occurs when a schema cannot be applied due to leaving data unreferenced. type SchemaWriteDataValidationError struct { error diff --git a/internal/services/v1/relationships.go b/internal/services/v1/relationships.go index 030742cd9..ff4179715 100644 --- a/internal/services/v1/relationships.go +++ b/internal/services/v1/relationships.go @@ -106,6 +106,9 @@ type PermissionsServerConfig struct { // ExpiringRelationshipsEnabled defines whether or not expiring relationships are enabled. ExpiringRelationshipsEnabled bool + // DeprecatedRelationshipsEnabled defines whether or not deprecated relationships are enabled. + DeprecatedRelationshipsAndObjectsEnabled bool + // CaveatTypeSet is the set of caveat types to use for caveats. If not specified, // the default type set is used. CaveatTypeSet *caveattypes.TypeSet @@ -126,24 +129,25 @@ func NewPermissionsServer( config PermissionsServerConfig, ) v1.PermissionsServiceServer { configWithDefaults := PermissionsServerConfig{ - MaxPreconditionsCount: defaultIfZero(config.MaxPreconditionsCount, 1000), - MaxUpdatesPerWrite: defaultIfZero(config.MaxUpdatesPerWrite, 1000), - MaximumAPIDepth: defaultIfZero(config.MaximumAPIDepth, 50), - StreamingAPITimeout: defaultIfZero(config.StreamingAPITimeout, 30*time.Second), - MaxCaveatContextSize: defaultIfZero(config.MaxCaveatContextSize, 4096), - MaxRelationshipContextSize: defaultIfZero(config.MaxRelationshipContextSize, 25_000), - MaxDatastoreReadPageSize: defaultIfZero(config.MaxDatastoreReadPageSize, 1_000), - MaxReadRelationshipsLimit: defaultIfZero(config.MaxReadRelationshipsLimit, 1_000), - MaxDeleteRelationshipsLimit: defaultIfZero(config.MaxDeleteRelationshipsLimit, 1_000), - MaxLookupResourcesLimit: defaultIfZero(config.MaxLookupResourcesLimit, 1_000), - MaxBulkExportRelationshipsLimit: defaultIfZero(config.MaxBulkExportRelationshipsLimit, 100_000), - DispatchChunkSize: defaultIfZero(config.DispatchChunkSize, 100), - MaxCheckBulkConcurrency: defaultIfZero(config.MaxCheckBulkConcurrency, 50), - CaveatTypeSet: caveattypes.TypeSetOrDefault(config.CaveatTypeSet), - ExpiringRelationshipsEnabled: config.ExpiringRelationshipsEnabled, - PerformanceInsightMetricsEnabled: config.PerformanceInsightMetricsEnabled, - EnableExperimentalLookupResources3: config.EnableExperimentalLookupResources3, - ExperimentalQueryPlan: config.ExperimentalQueryPlan, + MaxPreconditionsCount: defaultIfZero(config.MaxPreconditionsCount, 1000), + MaxUpdatesPerWrite: defaultIfZero(config.MaxUpdatesPerWrite, 1000), + MaximumAPIDepth: defaultIfZero(config.MaximumAPIDepth, 50), + StreamingAPITimeout: defaultIfZero(config.StreamingAPITimeout, 30*time.Second), + MaxCaveatContextSize: defaultIfZero(config.MaxCaveatContextSize, 4096), + MaxRelationshipContextSize: defaultIfZero(config.MaxRelationshipContextSize, 25_000), + MaxDatastoreReadPageSize: defaultIfZero(config.MaxDatastoreReadPageSize, 1_000), + MaxReadRelationshipsLimit: defaultIfZero(config.MaxReadRelationshipsLimit, 1_000), + MaxDeleteRelationshipsLimit: defaultIfZero(config.MaxDeleteRelationshipsLimit, 1_000), + MaxLookupResourcesLimit: defaultIfZero(config.MaxLookupResourcesLimit, 1_000), + MaxBulkExportRelationshipsLimit: defaultIfZero(config.MaxBulkExportRelationshipsLimit, 100_000), + DispatchChunkSize: defaultIfZero(config.DispatchChunkSize, 100), + MaxCheckBulkConcurrency: defaultIfZero(config.MaxCheckBulkConcurrency, 50), + CaveatTypeSet: caveattypes.TypeSetOrDefault(config.CaveatTypeSet), + ExpiringRelationshipsEnabled: config.ExpiringRelationshipsEnabled, + PerformanceInsightMetricsEnabled: config.PerformanceInsightMetricsEnabled, + EnableExperimentalLookupResources3: config.EnableExperimentalLookupResources3, + ExperimentalQueryPlan: config.ExperimentalQueryPlan, + DeprecatedRelationshipsAndObjectsEnabled: config.DeprecatedRelationshipsAndObjectsEnabled, } return &permissionServer{ @@ -346,6 +350,7 @@ func (ps *permissionServer) WriteRelationships(ctx context.Context, req *v1.Writ updateRelationshipSet := mapz.NewSet[string]() for _, update := range req.Updates { // TODO(jschorr): Change to struct-based keys. + tupleStr := tuple.V1StringRelationshipWithoutCaveatOrExpiration(update.Relationship) if !updateRelationshipSet.Add(tupleStr) { return nil, ps.rewriteError( diff --git a/internal/services/v1/schema.go b/internal/services/v1/schema.go index cc045df42..b204b4a78 100644 --- a/internal/services/v1/schema.go +++ b/internal/services/v1/schema.go @@ -43,6 +43,9 @@ type SchemaServerConfig struct { // PerformanceInsightMetricsEnabled indicates whether performance insight metrics are enabled. PerformanceInsightMetricsEnabled bool + + // DeprecatedRelsEnabled indicates whether deprecated relations are enabled. + FeatureDeprecationEnabled bool } // NewSchemaServer creates a SchemaServiceServer instance. @@ -61,9 +64,10 @@ func NewSchemaServer(config SchemaServerConfig) v1.SchemaServiceServer { perfinsights.StreamServerInterceptor(config.PerformanceInsightMetricsEnabled), ), }, - additiveOnly: config.AdditiveOnly, - expiringRelsEnabled: config.ExpiringRelsEnabled, - caveatTypeSet: cts, + additiveOnly: config.AdditiveOnly, + expiringRelsEnabled: config.ExpiringRelsEnabled, + featureDeprecationEnabled: config.FeatureDeprecationEnabled, + caveatTypeSet: cts, } } @@ -71,9 +75,10 @@ type schemaServer struct { v1.UnimplementedSchemaServiceServer shared.WithServiceSpecificInterceptors - caveatTypeSet *caveattypes.TypeSet - additiveOnly bool - expiringRelsEnabled bool + caveatTypeSet *caveattypes.TypeSet + additiveOnly bool + expiringRelsEnabled bool + featureDeprecationEnabled bool } func (ss *schemaServer) rewriteError(ctx context.Context, err error) error { @@ -152,6 +157,9 @@ func (ss *schemaServer) WriteSchema(ctx context.Context, in *v1.WriteSchemaReque if !ss.expiringRelsEnabled { opts = append(opts, compiler.DisallowExpirationFlag()) } + if !ss.featureDeprecationEnabled { + opts = append(opts, compiler.DisallowDeprecationFlag()) + } opts = append(opts, compiler.CaveatTypeSet(ss.caveatTypeSet)) diff --git a/internal/services/v1/schema_test.go b/internal/services/v1/schema_test.go index 648e2335d..d8040ef93 100644 --- a/internal/services/v1/schema_test.go +++ b/internal/services/v1/schema_test.go @@ -1642,3 +1642,71 @@ func TestComputablePermissions(t *testing.T) { }) } } + +func TestSchemaChangeRelationDeprecation(t *testing.T) { + conn, cleanup, _, _ := testserver.NewTestServer(require.New(t), 0, memdb.DisableGC, true, tf.EmptyDatastore) + t.Cleanup(cleanup) + client := v1.NewSchemaServiceClient(conn) + v1client := v1.NewPermissionsServiceClient(conn) + + // Write a basic schema with deprecations. + originalSchema := ` + use deprecation + + definition user {} + + @deprecated(error, "super deprecated") + definition testuser {} + + definition document { + relation somerelation: user + + @deprecated(warn) + relation otherelation: testuser + } + ` + _, err := client.WriteSchema(t.Context(), &v1.WriteSchemaRequest{ + Schema: originalSchema, + }) + require.NoError(t, err) + + // Write the relationship referencing the relation. + toWrite := tuple.MustParse("document:somedoc#somerelation@user:tom") + _, err = v1client.WriteRelationships(t.Context(), &v1.WriteRelationshipsRequest{ + Updates: []*v1.RelationshipUpdate{tuple.MustUpdateToV1RelationshipUpdate(tuple.Create( + toWrite, + ))}, + }) + require.Nil(t, err) + + // Attempt to write to a deprecated object which should fail. + toWrite = tuple.MustParse("document:somedoc#otherelation@testuser:jerry") + _, err = v1client.WriteRelationships(t.Context(), &v1.WriteRelationshipsRequest{ + Updates: []*v1.RelationshipUpdate{tuple.MustUpdateToV1RelationshipUpdate(tuple.Create( + toWrite, + ))}, + }) + require.Equal(t, "rpc error: code = Aborted desc = resource_type testuser is deprecated: super deprecated", err.Error()) + + // Change the schema to remove the deprecation type. + newSchema := ` + use deprecation + definition user {} + definition testuser {} + definition document { + relation somerelation: user + relation otherelation: testuser + }` + _, err = client.WriteSchema(t.Context(), &v1.WriteSchemaRequest{ + Schema: newSchema, + }) + require.NoError(t, err) + + // Again attempt to write to the relation, which should now succeed. + _, err = v1client.WriteRelationships(t.Context(), &v1.WriteRelationshipsRequest{ + Updates: []*v1.RelationshipUpdate{tuple.MustUpdateToV1RelationshipUpdate(tuple.Create( + toWrite, + ))}, + }) + require.NoError(t, err) +} diff --git a/internal/testserver/server.go b/internal/testserver/server.go index 6747f6127..abb3bc22f 100644 --- a/internal/testserver/server.go +++ b/internal/testserver/server.go @@ -91,6 +91,7 @@ func NewTestServerWithConfigAndDatastore(require *require.Assertions, require.NoError(err) srv, err := server.NewConfigWithOptionsAndDefaults( + server.WithEnableExperimentalRelationshipDeprecation(true), server.WithDatastore(ds), server.WithDispatcher(dispatcher), server.WithDispatchMaxDepth(50), diff --git a/pkg/cmd/serve.go b/pkg/cmd/serve.go index de8b6975b..ceff2668b 100644 --- a/pkg/cmd/serve.go +++ b/pkg/cmd/serve.go @@ -179,6 +179,8 @@ func RegisterServeFlags(cmd *cobra.Command, config *server.Config) error { if err := experimentalFlags.MarkDeprecated("enable-experimental-relationship-expiration", "it is enabled by default and no longer needs to be set."); err != nil { return fmt.Errorf("failed to mark flag as deprecated: %w", err) } + + experimentalFlags.BoolVar(&config.EnableExperimentalRelationshipDeprecation, "enable-experimental-deprecation", false, "enables experimental support for deprecating relations and objects") experimentalFlags.BoolVar(&config.EnableExperimentalWatchableSchemaCache, "enable-experimental-watchable-schema-cache", false, "enables the experimental schema cache, which uses the Watch API to keep the schema up to date") // TODO: these two could reasonably be put in either the Dispatch group or the Experimental group. Is there a preference? experimentalFlags.StringToStringVar(&config.DispatchSecondaryUpstreamAddrs, "experimental-dispatch-secondary-upstream-addrs", nil, "secondary upstream addresses for dispatches, each with a name") diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index ab9d31230..2a34b6c35 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -115,24 +115,25 @@ type Config struct { LR3ResourceChunkCacheConfig CacheConfig `debugmap:"visible"` // API Behavior - DisableV1SchemaAPI bool `debugmap:"visible"` - V1SchemaAdditiveOnly bool `debugmap:"visible"` - MaximumUpdatesPerWrite uint16 `debugmap:"visible"` - MaximumPreconditionCount uint16 `debugmap:"visible"` - MaxDatastoreReadPageSize uint64 `debugmap:"visible"` - StreamingAPITimeout time.Duration `debugmap:"visible"` - WatchHeartbeat time.Duration `debugmap:"visible"` - MaxReadRelationshipsLimit uint32 `debugmap:"visible"` - MaxDeleteRelationshipsLimit uint32 `debugmap:"visible"` - MaxLookupResourcesLimit uint32 `debugmap:"visible"` - MaxBulkExportRelationshipsLimit uint32 `debugmap:"visible"` - EnableExperimentalLookupResources bool `debugmap:"visible"` - ExperimentalLookupResourcesVersion string `debugmap:"visible"` - ExperimentalQueryPlan string `debugmap:"visible"` - EnableRelationshipExpiration bool `debugmap:"visible" default:"true"` - EnableRevisionHeartbeat bool `debugmap:"visible"` - EnablePerformanceInsightMetrics bool `debugmap:"visible"` - MismatchZedTokenBehavior string `debugmap:"visible"` + DisableV1SchemaAPI bool `debugmap:"visible"` + V1SchemaAdditiveOnly bool `debugmap:"visible"` + MaximumUpdatesPerWrite uint16 `debugmap:"visible"` + MaximumPreconditionCount uint16 `debugmap:"visible"` + MaxDatastoreReadPageSize uint64 `debugmap:"visible"` + StreamingAPITimeout time.Duration `debugmap:"visible"` + WatchHeartbeat time.Duration `debugmap:"visible"` + MaxReadRelationshipsLimit uint32 `debugmap:"visible"` + MaxDeleteRelationshipsLimit uint32 `debugmap:"visible"` + MaxLookupResourcesLimit uint32 `debugmap:"visible"` + MaxBulkExportRelationshipsLimit uint32 `debugmap:"visible"` + EnableExperimentalLookupResources bool `debugmap:"visible"` + ExperimentalLookupResourcesVersion string `debugmap:"visible"` + ExperimentalQueryPlan string `debugmap:"visible"` + EnableRelationshipExpiration bool `debugmap:"visible" default:"true"` + EnableRevisionHeartbeat bool `debugmap:"visible"` + EnablePerformanceInsightMetrics bool `debugmap:"visible"` + MismatchZedTokenBehavior string `debugmap:"visible"` + EnableExperimentalRelationshipDeprecation bool `debugmap:"visible"` // Additional Services MetricsAPI util.HTTPServerConfig `debugmap:"visible"` @@ -483,23 +484,24 @@ func (c *Config) Complete(ctx context.Context) (RunnableServer, error) { } permSysConfig := v1svc.PermissionsServerConfig{ - MaxPreconditionsCount: maxPreconditionCount, - MaxUpdatesPerWrite: c.MaximumUpdatesPerWrite, - MaximumAPIDepth: c.DispatchMaxDepth, - MaxCaveatContextSize: c.MaxCaveatContextSize, - MaxRelationshipContextSize: c.MaxRelationshipContextSize, - MaxDatastoreReadPageSize: c.MaxDatastoreReadPageSize, - StreamingAPITimeout: c.StreamingAPITimeout, - MaxReadRelationshipsLimit: c.MaxReadRelationshipsLimit, - MaxDeleteRelationshipsLimit: c.MaxDeleteRelationshipsLimit, - MaxLookupResourcesLimit: c.MaxLookupResourcesLimit, - MaxBulkExportRelationshipsLimit: c.MaxBulkExportRelationshipsLimit, - DispatchChunkSize: c.DispatchChunkSize, - ExpiringRelationshipsEnabled: c.EnableRelationshipExpiration, - CaveatTypeSet: c.DatastoreConfig.CaveatTypeSet, - PerformanceInsightMetricsEnabled: c.EnablePerformanceInsightMetrics, - EnableExperimentalLookupResources3: c.ExperimentalLookupResourcesVersion == "lr3", - ExperimentalQueryPlan: c.ExperimentalQueryPlan == "check", + MaxPreconditionsCount: maxPreconditionCount, + MaxUpdatesPerWrite: c.MaximumUpdatesPerWrite, + MaximumAPIDepth: c.DispatchMaxDepth, + MaxCaveatContextSize: c.MaxCaveatContextSize, + MaxRelationshipContextSize: c.MaxRelationshipContextSize, + MaxDatastoreReadPageSize: c.MaxDatastoreReadPageSize, + StreamingAPITimeout: c.StreamingAPITimeout, + MaxReadRelationshipsLimit: c.MaxReadRelationshipsLimit, + MaxDeleteRelationshipsLimit: c.MaxDeleteRelationshipsLimit, + MaxLookupResourcesLimit: c.MaxLookupResourcesLimit, + MaxBulkExportRelationshipsLimit: c.MaxBulkExportRelationshipsLimit, + DispatchChunkSize: c.DispatchChunkSize, + ExpiringRelationshipsEnabled: c.EnableRelationshipExpiration, + CaveatTypeSet: c.DatastoreConfig.CaveatTypeSet, + PerformanceInsightMetricsEnabled: c.EnablePerformanceInsightMetrics, + EnableExperimentalLookupResources3: c.ExperimentalLookupResourcesVersion == "lr3", + ExperimentalQueryPlan: c.ExperimentalQueryPlan == "check", + DeprecatedRelationshipsAndObjectsEnabled: c.EnableExperimentalRelationshipDeprecation, } healthManager := health.NewHealthManager(dispatcher, ds) diff --git a/pkg/cmd/server/zz_generated.options.go b/pkg/cmd/server/zz_generated.options.go index fd2c777a1..204d5b93d 100644 --- a/pkg/cmd/server/zz_generated.options.go +++ b/pkg/cmd/server/zz_generated.options.go @@ -97,6 +97,7 @@ func (c *Config) ToOption() ConfigOption { to.EnableRevisionHeartbeat = c.EnableRevisionHeartbeat to.EnablePerformanceInsightMetrics = c.EnablePerformanceInsightMetrics to.MismatchZedTokenBehavior = c.MismatchZedTokenBehavior + to.EnableExperimentalRelationshipDeprecation = c.EnableExperimentalRelationshipDeprecation to.MetricsAPI = c.MetricsAPI to.UnaryMiddlewareModification = c.UnaryMiddlewareModification to.StreamingMiddlewareModification = c.StreamingMiddlewareModification @@ -173,6 +174,7 @@ func (c Config) DebugMap() map[string]any { debugMap["EnableRevisionHeartbeat"] = helpers.DebugValue(c.EnableRevisionHeartbeat, false) debugMap["EnablePerformanceInsightMetrics"] = helpers.DebugValue(c.EnablePerformanceInsightMetrics, false) debugMap["MismatchZedTokenBehavior"] = helpers.DebugValue(c.MismatchZedTokenBehavior, false) + debugMap["EnableExperimentalRelationshipDeprecation"] = helpers.DebugValue(c.EnableExperimentalRelationshipDeprecation, false) debugMap["MetricsAPI"] = helpers.DebugValue(c.MetricsAPI, false) debugMap["SilentlyDisableTelemetry"] = helpers.DebugValue(c.SilentlyDisableTelemetry, false) debugMap["TelemetryCAOverridePath"] = helpers.DebugValue(c.TelemetryCAOverridePath, false) @@ -648,6 +650,13 @@ func WithMismatchZedTokenBehavior(mismatchZedTokenBehavior string) ConfigOption } } +// WithEnableExperimentalRelationshipDeprecation returns an option that can set EnableExperimentalRelationshipDeprecation on a Config +func WithEnableExperimentalRelationshipDeprecation(enableExperimentalRelationshipDeprecation bool) ConfigOption { + return func(c *Config) { + c.EnableExperimentalRelationshipDeprecation = enableExperimentalRelationshipDeprecation + } +} + // WithMetricsAPI returns an option that can set MetricsAPI on a Config func WithMetricsAPI(metricsAPI util.HTTPServerConfig) ConfigOption { return func(c *Config) { diff --git a/pkg/development/devcontext.go b/pkg/development/devcontext.go index 951348973..71d993304 100644 --- a/pkg/development/devcontext.go +++ b/pkg/development/devcontext.go @@ -175,18 +175,20 @@ func (dc *DevContext) RunV1InMemoryService() (*grpc.ClientConn, func(), error) { ), ) ps := v1svc.NewPermissionsServer(dc.Dispatcher, v1svc.PermissionsServerConfig{ - MaxUpdatesPerWrite: 50, - MaxPreconditionsCount: 50, - MaximumAPIDepth: 50, - MaxCaveatContextSize: 0, - ExpiringRelationshipsEnabled: true, - CaveatTypeSet: caveattypes.Default.TypeSet, - PerformanceInsightMetricsEnabled: false, + MaxUpdatesPerWrite: 50, + MaxPreconditionsCount: 50, + MaximumAPIDepth: 50, + MaxCaveatContextSize: 0, + ExpiringRelationshipsEnabled: true, + DeprecatedRelationshipsAndObjectsEnabled: true, + CaveatTypeSet: caveattypes.Default.TypeSet, + PerformanceInsightMetricsEnabled: false, }) ss := v1svc.NewSchemaServer(v1svc.SchemaServerConfig{ CaveatTypeSet: caveattypes.Default.TypeSet, AdditiveOnly: false, ExpiringRelsEnabled: true, + FeatureDeprecationEnabled: true, PerformanceInsightMetricsEnabled: false, }) diff --git a/pkg/diff/namespace/diff.go b/pkg/diff/namespace/diff.go index af50f0fb5..b20975e5a 100644 --- a/pkg/diff/namespace/diff.go +++ b/pkg/diff/namespace/diff.go @@ -60,6 +60,9 @@ const ( // ChangedRelationComment indicates that the comment of the relation has changed in some way. ChangedRelationComment DeltaType = "changed-relation-comment" + + // ChangedDeprecation indicates that the deprecation status of the relation has changed. + ChangedDeprecation DeltaType = "changed-deprecation" ) // Diff holds the diff between two namespaces. @@ -120,6 +123,12 @@ func DiffNamespaces(existing *core.NamespaceDefinition, updated *core.NamespaceD deltas := []Delta{} + if existing.Deprecation != updated.Deprecation { + deltas = append(deltas, Delta{ + Type: ChangedDeprecation, + }) + } + // Check the namespace's comments. existingComments := nspkg.GetComments(existing.Metadata) updatedComments := nspkg.GetComments(updated.Metadata) @@ -240,6 +249,14 @@ func DiffNamespaces(existing *core.NamespaceDefinition, updated *core.NamespaceD }) } + // Compare deprecation status + if existingRel.Deprecation != updatedRel.Deprecation { + deltas = append(deltas, Delta{ + Type: ChangedDeprecation, + RelationName: shared, + }) + } + // Compare comments. existingComments := nspkg.GetComments(existingRel.Metadata) updatedComments := nspkg.GetComments(updatedRel.Metadata) diff --git a/pkg/diff/namespace/diff_test.go b/pkg/diff/namespace/diff_test.go index b93f8592a..bf806b071 100644 --- a/pkg/diff/namespace/diff_test.go +++ b/pkg/diff/namespace/diff_test.go @@ -571,6 +571,42 @@ func TestNamespaceDiff(t *testing.T) { ), []Delta{}, }, + { + "deprecate relation with an error type", + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("somerel", &core.Deprecation{ + DeprecationType: core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED, + }, nil), + ), + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("somerel", &core.Deprecation{ + DeprecationType: core.DeprecationType_DEPRECATED_TYPE_ERROR, + }, nil), + ), + []Delta{ + {Type: ChangedDeprecation, RelationName: "somerel"}, + }, + }, + { + "remove deprecation", + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("somerel", &core.Deprecation{ + DeprecationType: core.DeprecationType_DEPRECATED_TYPE_ERROR, + }, nil), + ), + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("somerel", &core.Deprecation{ + DeprecationType: core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED, + }, nil), + ), + []Delta{ + {Type: ChangedDeprecation, RelationName: "somerel"}, + }, + }, } for _, tc := range testCases { diff --git a/pkg/namespace/builder.go b/pkg/namespace/builder.go index cf4c745b4..220fca3d8 100644 --- a/pkg/namespace/builder.go +++ b/pkg/namespace/builder.go @@ -15,6 +15,12 @@ func Namespace(name string, relations ...*core.Relation) *core.NamespaceDefiniti } } +func WithDeprecation(name string, deprecation *core.Deprecation, relations ...*core.Relation) *core.NamespaceDefinition { + nd := Namespace(name, relations...) + nd.Deprecation = deprecation + return nd +} + // WithComment creates a namespace definition with one or more defined relations. func WithComment(name string, comment string, relations ...*core.Relation) *core.NamespaceDefinition { nd := Namespace(name, relations...) @@ -73,6 +79,13 @@ func MustRelationWithComment(name string, comment string, rewrite *core.UsersetR return rel } +// MustRelationWithDeprecation creates a relation definition with an optional rewrite definition. +func MustRelationWithDeprecation(name string, deprecation *core.Deprecation, rewrite *core.UsersetRewrite, allowedDirectRelations ...*core.AllowedRelation) *core.Relation { + rel := MustRelation(name, rewrite, allowedDirectRelations...) + rel.Deprecation = deprecation + return rel +} + // AllowedRelation creates a relation reference to an allowed relation. func AllowedRelation(namespaceName string, relationName string) *core.AllowedRelation { return &core.AllowedRelation{ @@ -115,6 +128,23 @@ func AllowedRelationWithExpiration(namespaceName string, relationName string) *c } } +// AllowedRelationWithDeprecation creates a relation reference to an allowed relation. +func AllowedRelationWithDeprecation(allowedRel *core.AllowedRelation, deprecation *core.Deprecation) *core.AllowedRelation { + allowedRel.Deprecation = deprecation + return allowedRel +} + +// AllowedPublicNamespaceWithDeprecation creates a relation reference to an allowed public namespace. +func AllowedPublicNamespaceWithDeprecation(namespaceName string, deprecation *core.Deprecation) *core.AllowedRelation { + return &core.AllowedRelation{ + Namespace: namespaceName, + RelationOrWildcard: &core.AllowedRelation_PublicWildcard_{ + PublicWildcard: &core.AllowedRelation_PublicWildcard{}, + }, + Deprecation: deprecation, + } +} + // AllowedRelationWithCaveatAndExpiration creates a relation reference to an allowed relation. func AllowedRelationWithCaveatAndExpiration(namespaceName string, relationName string, withCaveat *core.AllowedCaveat) *core.AllowedRelation { return &core.AllowedRelation{ @@ -208,6 +238,14 @@ func RelationReference(namespaceName string, relationName string) *core.Relation } } +// Deprecation creates a deprecation definition. +func Deprecation(deprecationType core.DeprecationType, message string) *core.Deprecation { + return &core.Deprecation{ + DeprecationType: deprecationType, + Comments: message, + } +} + // Union creates a rewrite definition that combines/considers usersets in all children. func Union(firstChild *core.SetOperation_Child, rest ...*core.SetOperation_Child) *core.UsersetRewrite { return &core.UsersetRewrite{ diff --git a/pkg/proto/core/v1/core.pb.go b/pkg/proto/core/v1/core.pb.go index c8646684f..e4a06209c 100644 --- a/pkg/proto/core/v1/core.pb.go +++ b/pkg/proto/core/v1/core.pb.go @@ -25,6 +25,57 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// * +// DeprecationType is the type of deprecation for a relation. +type DeprecationType int32 + +const ( + DeprecationType_DEPRECATED_TYPE_UNSPECIFIED DeprecationType = 0 + DeprecationType_DEPRECATED_TYPE_WARNING DeprecationType = 1 + DeprecationType_DEPRECATED_TYPE_ERROR DeprecationType = 2 +) + +// Enum value maps for DeprecationType. +var ( + DeprecationType_name = map[int32]string{ + 0: "DEPRECATED_TYPE_UNSPECIFIED", + 1: "DEPRECATED_TYPE_WARNING", + 2: "DEPRECATED_TYPE_ERROR", + } + DeprecationType_value = map[string]int32{ + "DEPRECATED_TYPE_UNSPECIFIED": 0, + "DEPRECATED_TYPE_WARNING": 1, + "DEPRECATED_TYPE_ERROR": 2, + } +) + +func (x DeprecationType) Enum() *DeprecationType { + p := new(DeprecationType) + *p = x + return p +} + +func (x DeprecationType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DeprecationType) Descriptor() protoreflect.EnumDescriptor { + return file_core_v1_core_proto_enumTypes[0].Descriptor() +} + +func (DeprecationType) Type() protoreflect.EnumType { + return &file_core_v1_core_proto_enumTypes[0] +} + +func (x DeprecationType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DeprecationType.Descriptor instead. +func (DeprecationType) EnumDescriptor() ([]byte, []int) { + return file_core_v1_core_proto_rawDescGZIP(), []int{0} +} + type RelationTupleUpdate_Operation int32 const ( @@ -61,11 +112,11 @@ func (x RelationTupleUpdate_Operation) String() string { } func (RelationTupleUpdate_Operation) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[0].Descriptor() + return file_core_v1_core_proto_enumTypes[1].Descriptor() } func (RelationTupleUpdate_Operation) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[0] + return &file_core_v1_core_proto_enumTypes[1] } func (x RelationTupleUpdate_Operation) Number() protoreflect.EnumNumber { @@ -113,11 +164,11 @@ func (x SetOperationUserset_Operation) String() string { } func (SetOperationUserset_Operation) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[1].Descriptor() + return file_core_v1_core_proto_enumTypes[2].Descriptor() } func (SetOperationUserset_Operation) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[1] + return &file_core_v1_core_proto_enumTypes[2] } func (x SetOperationUserset_Operation) Number() protoreflect.EnumNumber { @@ -171,11 +222,11 @@ func (x ReachabilityEntrypoint_ReachabilityEntrypointKind) String() string { } func (ReachabilityEntrypoint_ReachabilityEntrypointKind) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[2].Descriptor() + return file_core_v1_core_proto_enumTypes[3].Descriptor() } func (ReachabilityEntrypoint_ReachabilityEntrypointKind) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[2] + return &file_core_v1_core_proto_enumTypes[3] } func (x ReachabilityEntrypoint_ReachabilityEntrypointKind) Number() protoreflect.EnumNumber { @@ -184,7 +235,7 @@ func (x ReachabilityEntrypoint_ReachabilityEntrypointKind) Number() protoreflect // Deprecated: Use ReachabilityEntrypoint_ReachabilityEntrypointKind.Descriptor instead. func (ReachabilityEntrypoint_ReachabilityEntrypointKind) EnumDescriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{18, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{19, 0} } type ReachabilityEntrypoint_EntrypointResultStatus int32 @@ -224,11 +275,11 @@ func (x ReachabilityEntrypoint_EntrypointResultStatus) String() string { } func (ReachabilityEntrypoint_EntrypointResultStatus) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[3].Descriptor() + return file_core_v1_core_proto_enumTypes[4].Descriptor() } func (ReachabilityEntrypoint_EntrypointResultStatus) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[3] + return &file_core_v1_core_proto_enumTypes[4] } func (x ReachabilityEntrypoint_EntrypointResultStatus) Number() protoreflect.EnumNumber { @@ -237,7 +288,7 @@ func (x ReachabilityEntrypoint_EntrypointResultStatus) Number() protoreflect.Enu // Deprecated: Use ReachabilityEntrypoint_EntrypointResultStatus.Descriptor instead. func (ReachabilityEntrypoint_EntrypointResultStatus) EnumDescriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{18, 1} + return file_core_v1_core_proto_rawDescGZIP(), []int{19, 1} } type FunctionedTupleToUserset_Function int32 @@ -273,11 +324,11 @@ func (x FunctionedTupleToUserset_Function) String() string { } func (FunctionedTupleToUserset_Function) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[4].Descriptor() + return file_core_v1_core_proto_enumTypes[5].Descriptor() } func (FunctionedTupleToUserset_Function) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[4] + return &file_core_v1_core_proto_enumTypes[5] } func (x FunctionedTupleToUserset_Function) Number() protoreflect.EnumNumber { @@ -286,7 +337,7 @@ func (x FunctionedTupleToUserset_Function) Number() protoreflect.EnumNumber { // Deprecated: Use FunctionedTupleToUserset_Function.Descriptor instead. func (FunctionedTupleToUserset_Function) EnumDescriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{26, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{27, 0} } type ComputedUserset_Object int32 @@ -319,11 +370,11 @@ func (x ComputedUserset_Object) String() string { } func (ComputedUserset_Object) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[5].Descriptor() + return file_core_v1_core_proto_enumTypes[6].Descriptor() } func (ComputedUserset_Object) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[5] + return &file_core_v1_core_proto_enumTypes[6] } func (x ComputedUserset_Object) Number() protoreflect.EnumNumber { @@ -332,7 +383,7 @@ func (x ComputedUserset_Object) Number() protoreflect.EnumNumber { // Deprecated: Use ComputedUserset_Object.Descriptor instead. func (ComputedUserset_Object) EnumDescriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{27, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{28, 0} } type CaveatOperation_Operation int32 @@ -371,11 +422,11 @@ func (x CaveatOperation_Operation) String() string { } func (CaveatOperation_Operation) Descriptor() protoreflect.EnumDescriptor { - return file_core_v1_core_proto_enumTypes[6].Descriptor() + return file_core_v1_core_proto_enumTypes[7].Descriptor() } func (CaveatOperation_Operation) Type() protoreflect.EnumType { - return &file_core_v1_core_proto_enumTypes[6] + return &file_core_v1_core_proto_enumTypes[7] } func (x CaveatOperation_Operation) Number() protoreflect.EnumNumber { @@ -384,7 +435,7 @@ func (x CaveatOperation_Operation) Number() protoreflect.EnumNumber { // Deprecated: Use CaveatOperation_Operation.Descriptor instead. func (CaveatOperation_Operation) EnumDescriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{30, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{31, 0} } type RelationTuple struct { @@ -1239,8 +1290,10 @@ type NamespaceDefinition struct { Metadata *Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` // * source_position contains the position of the namespace in the source schema, if any SourcePosition *SourcePosition `protobuf:"bytes,4,opt,name=source_position,json=sourcePosition,proto3" json:"source_position,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // * deprecation contains the deprecation information for the namespace, if any + Deprecation *Deprecation `protobuf:"bytes,5,opt,name=deprecation,proto3" json:"deprecation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NamespaceDefinition) Reset() { @@ -1301,6 +1354,69 @@ func (x *NamespaceDefinition) GetSourcePosition() *SourcePosition { return nil } +func (x *NamespaceDefinition) GetDeprecation() *Deprecation { + if x != nil { + return x.Deprecation + } + return nil +} + +type Deprecation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // * + // deprecation_type is the type of deprecation for the relation. + // It can be either a warning or an error, defaults to unspecified. + DeprecationType DeprecationType `protobuf:"varint,1,opt,name=deprecation_type,json=deprecationType,proto3,enum=core.v1.DeprecationType" json:"deprecation_type,omitempty"` + // * comments are the comments to show when the relation is used + Comments string `protobuf:"bytes,2,opt,name=comments,proto3" json:"comments,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Deprecation) Reset() { + *x = Deprecation{} + mi := &file_core_v1_core_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Deprecation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Deprecation) ProtoMessage() {} + +func (x *Deprecation) ProtoReflect() protoreflect.Message { + mi := &file_core_v1_core_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Deprecation.ProtoReflect.Descriptor instead. +func (*Deprecation) Descriptor() ([]byte, []int) { + return file_core_v1_core_proto_rawDescGZIP(), []int{15} +} + +func (x *Deprecation) GetDeprecationType() DeprecationType { + if x != nil { + return x.DeprecationType + } + return DeprecationType_DEPRECATED_TYPE_UNSPECIFIED +} + +func (x *Deprecation) GetComments() string { + if x != nil { + return x.Comments + } + return "" +} + // * // Relation represents the definition of a relation or permission under a namespace. type Relation struct { @@ -1319,13 +1435,16 @@ type Relation struct { SourcePosition *SourcePosition `protobuf:"bytes,5,opt,name=source_position,json=sourcePosition,proto3" json:"source_position,omitempty"` AliasingRelation string `protobuf:"bytes,6,opt,name=aliasing_relation,json=aliasingRelation,proto3" json:"aliasing_relation,omitempty"` CanonicalCacheKey string `protobuf:"bytes,7,opt,name=canonical_cache_key,json=canonicalCacheKey,proto3" json:"canonical_cache_key,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // * + // deprecation contains the deprecation information for the relation, if any + Deprecation *Deprecation `protobuf:"bytes,8,opt,name=deprecation,proto3" json:"deprecation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Relation) Reset() { *x = Relation{} - mi := &file_core_v1_core_proto_msgTypes[15] + mi := &file_core_v1_core_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1337,7 +1456,7 @@ func (x *Relation) String() string { func (*Relation) ProtoMessage() {} func (x *Relation) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[15] + mi := &file_core_v1_core_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1350,7 +1469,7 @@ func (x *Relation) ProtoReflect() protoreflect.Message { // Deprecated: Use Relation.ProtoReflect.Descriptor instead. func (*Relation) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{15} + return file_core_v1_core_proto_rawDescGZIP(), []int{16} } func (x *Relation) GetName() string { @@ -1402,6 +1521,13 @@ func (x *Relation) GetCanonicalCacheKey() string { return "" } +func (x *Relation) GetDeprecation() *Deprecation { + if x != nil { + return x.Deprecation + } + return nil +} + // * // ReachabilityGraph is a serialized form of a reachability graph, representing how a relation can // be reached from one or more subject types. @@ -1450,7 +1576,7 @@ type ReachabilityGraph struct { func (x *ReachabilityGraph) Reset() { *x = ReachabilityGraph{} - mi := &file_core_v1_core_proto_msgTypes[16] + mi := &file_core_v1_core_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1462,7 +1588,7 @@ func (x *ReachabilityGraph) String() string { func (*ReachabilityGraph) ProtoMessage() {} func (x *ReachabilityGraph) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[16] + mi := &file_core_v1_core_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1475,7 +1601,7 @@ func (x *ReachabilityGraph) ProtoReflect() protoreflect.Message { // Deprecated: Use ReachabilityGraph.ProtoReflect.Descriptor instead. func (*ReachabilityGraph) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{16} + return file_core_v1_core_proto_rawDescGZIP(), []int{17} } func (x *ReachabilityGraph) GetEntrypointsBySubjectType() map[string]*ReachabilityEntrypoints { @@ -1514,7 +1640,7 @@ type ReachabilityEntrypoints struct { func (x *ReachabilityEntrypoints) Reset() { *x = ReachabilityEntrypoints{} - mi := &file_core_v1_core_proto_msgTypes[17] + mi := &file_core_v1_core_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1526,7 +1652,7 @@ func (x *ReachabilityEntrypoints) String() string { func (*ReachabilityEntrypoints) ProtoMessage() {} func (x *ReachabilityEntrypoints) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[17] + mi := &file_core_v1_core_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1539,7 +1665,7 @@ func (x *ReachabilityEntrypoints) ProtoReflect() protoreflect.Message { // Deprecated: Use ReachabilityEntrypoints.ProtoReflect.Descriptor instead. func (*ReachabilityEntrypoints) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{17} + return file_core_v1_core_proto_rawDescGZIP(), []int{18} } func (x *ReachabilityEntrypoints) GetEntrypoints() []*ReachabilityEntrypoint { @@ -1592,7 +1718,7 @@ type ReachabilityEntrypoint struct { func (x *ReachabilityEntrypoint) Reset() { *x = ReachabilityEntrypoint{} - mi := &file_core_v1_core_proto_msgTypes[18] + mi := &file_core_v1_core_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1604,7 +1730,7 @@ func (x *ReachabilityEntrypoint) String() string { func (*ReachabilityEntrypoint) ProtoMessage() {} func (x *ReachabilityEntrypoint) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[18] + mi := &file_core_v1_core_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1617,7 +1743,7 @@ func (x *ReachabilityEntrypoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ReachabilityEntrypoint.ProtoReflect.Descriptor instead. func (*ReachabilityEntrypoint) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{18} + return file_core_v1_core_proto_rawDescGZIP(), []int{19} } func (x *ReachabilityEntrypoint) GetKind() ReachabilityEntrypoint_ReachabilityEntrypointKind { @@ -1669,7 +1795,7 @@ type TypeInformation struct { func (x *TypeInformation) Reset() { *x = TypeInformation{} - mi := &file_core_v1_core_proto_msgTypes[19] + mi := &file_core_v1_core_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1681,7 +1807,7 @@ func (x *TypeInformation) String() string { func (*TypeInformation) ProtoMessage() {} func (x *TypeInformation) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[19] + mi := &file_core_v1_core_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1694,7 +1820,7 @@ func (x *TypeInformation) ProtoReflect() protoreflect.Message { // Deprecated: Use TypeInformation.ProtoReflect.Descriptor instead. func (*TypeInformation) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{19} + return file_core_v1_core_proto_rawDescGZIP(), []int{20} } func (x *TypeInformation) GetAllowedDirectRelations() []*AllowedRelation { @@ -1726,13 +1852,16 @@ type AllowedRelation struct { // * // required_expiration defines the required expiration on this relation. RequiredExpiration *ExpirationTrait `protobuf:"bytes,7,opt,name=required_expiration,json=requiredExpiration,proto3" json:"required_expiration,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // * + // deprecation contains the deprecation for the relation. + Deprecation *Deprecation `protobuf:"bytes,8,opt,name=deprecation,proto3" json:"deprecation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AllowedRelation) Reset() { *x = AllowedRelation{} - mi := &file_core_v1_core_proto_msgTypes[20] + mi := &file_core_v1_core_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1744,7 +1873,7 @@ func (x *AllowedRelation) String() string { func (*AllowedRelation) ProtoMessage() {} func (x *AllowedRelation) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[20] + mi := &file_core_v1_core_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1757,7 +1886,7 @@ func (x *AllowedRelation) ProtoReflect() protoreflect.Message { // Deprecated: Use AllowedRelation.ProtoReflect.Descriptor instead. func (*AllowedRelation) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{20} + return file_core_v1_core_proto_rawDescGZIP(), []int{21} } func (x *AllowedRelation) GetNamespace() string { @@ -1813,6 +1942,13 @@ func (x *AllowedRelation) GetRequiredExpiration() *ExpirationTrait { return nil } +func (x *AllowedRelation) GetDeprecation() *Deprecation { + if x != nil { + return x.Deprecation + } + return nil +} + type isAllowedRelation_RelationOrWildcard interface { isAllowedRelation_RelationOrWildcard() } @@ -1839,7 +1975,7 @@ type ExpirationTrait struct { func (x *ExpirationTrait) Reset() { *x = ExpirationTrait{} - mi := &file_core_v1_core_proto_msgTypes[21] + mi := &file_core_v1_core_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1851,7 +1987,7 @@ func (x *ExpirationTrait) String() string { func (*ExpirationTrait) ProtoMessage() {} func (x *ExpirationTrait) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[21] + mi := &file_core_v1_core_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1864,7 +2000,7 @@ func (x *ExpirationTrait) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpirationTrait.ProtoReflect.Descriptor instead. func (*ExpirationTrait) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{21} + return file_core_v1_core_proto_rawDescGZIP(), []int{22} } // * @@ -1880,7 +2016,7 @@ type AllowedCaveat struct { func (x *AllowedCaveat) Reset() { *x = AllowedCaveat{} - mi := &file_core_v1_core_proto_msgTypes[22] + mi := &file_core_v1_core_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1892,7 +2028,7 @@ func (x *AllowedCaveat) String() string { func (*AllowedCaveat) ProtoMessage() {} func (x *AllowedCaveat) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[22] + mi := &file_core_v1_core_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1905,7 +2041,7 @@ func (x *AllowedCaveat) ProtoReflect() protoreflect.Message { // Deprecated: Use AllowedCaveat.ProtoReflect.Descriptor instead. func (*AllowedCaveat) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{22} + return file_core_v1_core_proto_rawDescGZIP(), []int{23} } func (x *AllowedCaveat) GetCaveatName() string { @@ -1930,7 +2066,7 @@ type UsersetRewrite struct { func (x *UsersetRewrite) Reset() { *x = UsersetRewrite{} - mi := &file_core_v1_core_proto_msgTypes[23] + mi := &file_core_v1_core_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1942,7 +2078,7 @@ func (x *UsersetRewrite) String() string { func (*UsersetRewrite) ProtoMessage() {} func (x *UsersetRewrite) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[23] + mi := &file_core_v1_core_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1955,7 +2091,7 @@ func (x *UsersetRewrite) ProtoReflect() protoreflect.Message { // Deprecated: Use UsersetRewrite.ProtoReflect.Descriptor instead. func (*UsersetRewrite) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{23} + return file_core_v1_core_proto_rawDescGZIP(), []int{24} } func (x *UsersetRewrite) GetRewriteOperation() isUsersetRewrite_RewriteOperation { @@ -2030,7 +2166,7 @@ type SetOperation struct { func (x *SetOperation) Reset() { *x = SetOperation{} - mi := &file_core_v1_core_proto_msgTypes[24] + mi := &file_core_v1_core_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2042,7 +2178,7 @@ func (x *SetOperation) String() string { func (*SetOperation) ProtoMessage() {} func (x *SetOperation) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[24] + mi := &file_core_v1_core_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2055,7 +2191,7 @@ func (x *SetOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use SetOperation.ProtoReflect.Descriptor instead. func (*SetOperation) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{24} + return file_core_v1_core_proto_rawDescGZIP(), []int{25} } func (x *SetOperation) GetChild() []*SetOperation_Child { @@ -2076,7 +2212,7 @@ type TupleToUserset struct { func (x *TupleToUserset) Reset() { *x = TupleToUserset{} - mi := &file_core_v1_core_proto_msgTypes[25] + mi := &file_core_v1_core_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2088,7 +2224,7 @@ func (x *TupleToUserset) String() string { func (*TupleToUserset) ProtoMessage() {} func (x *TupleToUserset) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[25] + mi := &file_core_v1_core_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2101,7 +2237,7 @@ func (x *TupleToUserset) ProtoReflect() protoreflect.Message { // Deprecated: Use TupleToUserset.ProtoReflect.Descriptor instead. func (*TupleToUserset) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{25} + return file_core_v1_core_proto_rawDescGZIP(), []int{26} } func (x *TupleToUserset) GetTupleset() *TupleToUserset_Tupleset { @@ -2137,7 +2273,7 @@ type FunctionedTupleToUserset struct { func (x *FunctionedTupleToUserset) Reset() { *x = FunctionedTupleToUserset{} - mi := &file_core_v1_core_proto_msgTypes[26] + mi := &file_core_v1_core_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2149,7 +2285,7 @@ func (x *FunctionedTupleToUserset) String() string { func (*FunctionedTupleToUserset) ProtoMessage() {} func (x *FunctionedTupleToUserset) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[26] + mi := &file_core_v1_core_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2162,7 +2298,7 @@ func (x *FunctionedTupleToUserset) ProtoReflect() protoreflect.Message { // Deprecated: Use FunctionedTupleToUserset.ProtoReflect.Descriptor instead. func (*FunctionedTupleToUserset) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{26} + return file_core_v1_core_proto_rawDescGZIP(), []int{27} } func (x *FunctionedTupleToUserset) GetFunction() FunctionedTupleToUserset_Function { @@ -2204,7 +2340,7 @@ type ComputedUserset struct { func (x *ComputedUserset) Reset() { *x = ComputedUserset{} - mi := &file_core_v1_core_proto_msgTypes[27] + mi := &file_core_v1_core_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2216,7 +2352,7 @@ func (x *ComputedUserset) String() string { func (*ComputedUserset) ProtoMessage() {} func (x *ComputedUserset) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[27] + mi := &file_core_v1_core_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2229,7 +2365,7 @@ func (x *ComputedUserset) ProtoReflect() protoreflect.Message { // Deprecated: Use ComputedUserset.ProtoReflect.Descriptor instead. func (*ComputedUserset) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{27} + return file_core_v1_core_proto_rawDescGZIP(), []int{28} } func (x *ComputedUserset) GetObject() ComputedUserset_Object { @@ -2263,7 +2399,7 @@ type SourcePosition struct { func (x *SourcePosition) Reset() { *x = SourcePosition{} - mi := &file_core_v1_core_proto_msgTypes[28] + mi := &file_core_v1_core_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2275,7 +2411,7 @@ func (x *SourcePosition) String() string { func (*SourcePosition) ProtoMessage() {} func (x *SourcePosition) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[28] + mi := &file_core_v1_core_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2288,7 +2424,7 @@ func (x *SourcePosition) ProtoReflect() protoreflect.Message { // Deprecated: Use SourcePosition.ProtoReflect.Descriptor instead. func (*SourcePosition) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{28} + return file_core_v1_core_proto_rawDescGZIP(), []int{29} } func (x *SourcePosition) GetZeroIndexedLineNumber() uint64 { @@ -2318,7 +2454,7 @@ type CaveatExpression struct { func (x *CaveatExpression) Reset() { *x = CaveatExpression{} - mi := &file_core_v1_core_proto_msgTypes[29] + mi := &file_core_v1_core_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2330,7 +2466,7 @@ func (x *CaveatExpression) String() string { func (*CaveatExpression) ProtoMessage() {} func (x *CaveatExpression) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[29] + mi := &file_core_v1_core_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2343,7 +2479,7 @@ func (x *CaveatExpression) ProtoReflect() protoreflect.Message { // Deprecated: Use CaveatExpression.ProtoReflect.Descriptor instead. func (*CaveatExpression) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{29} + return file_core_v1_core_proto_rawDescGZIP(), []int{30} } func (x *CaveatExpression) GetOperationOrCaveat() isCaveatExpression_OperationOrCaveat { @@ -2397,7 +2533,7 @@ type CaveatOperation struct { func (x *CaveatOperation) Reset() { *x = CaveatOperation{} - mi := &file_core_v1_core_proto_msgTypes[30] + mi := &file_core_v1_core_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2409,7 +2545,7 @@ func (x *CaveatOperation) String() string { func (*CaveatOperation) ProtoMessage() {} func (x *CaveatOperation) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[30] + mi := &file_core_v1_core_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2422,7 +2558,7 @@ func (x *CaveatOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use CaveatOperation.ProtoReflect.Descriptor instead. func (*CaveatOperation) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{30} + return file_core_v1_core_proto_rawDescGZIP(), []int{31} } func (x *CaveatOperation) GetOp() CaveatOperation_Operation { @@ -2460,7 +2596,7 @@ type RelationshipFilter struct { func (x *RelationshipFilter) Reset() { *x = RelationshipFilter{} - mi := &file_core_v1_core_proto_msgTypes[31] + mi := &file_core_v1_core_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2472,7 +2608,7 @@ func (x *RelationshipFilter) String() string { func (*RelationshipFilter) ProtoMessage() {} func (x *RelationshipFilter) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[31] + mi := &file_core_v1_core_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2485,7 +2621,7 @@ func (x *RelationshipFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use RelationshipFilter.ProtoReflect.Descriptor instead. func (*RelationshipFilter) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{31} + return file_core_v1_core_proto_rawDescGZIP(), []int{32} } func (x *RelationshipFilter) GetResourceType() string { @@ -2538,7 +2674,7 @@ type SubjectFilter struct { func (x *SubjectFilter) Reset() { *x = SubjectFilter{} - mi := &file_core_v1_core_proto_msgTypes[32] + mi := &file_core_v1_core_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2550,7 +2686,7 @@ func (x *SubjectFilter) String() string { func (*SubjectFilter) ProtoMessage() {} func (x *SubjectFilter) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[32] + mi := &file_core_v1_core_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2563,7 +2699,7 @@ func (x *SubjectFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use SubjectFilter.ProtoReflect.Descriptor instead. func (*SubjectFilter) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{32} + return file_core_v1_core_proto_rawDescGZIP(), []int{33} } func (x *SubjectFilter) GetSubjectType() string { @@ -2595,7 +2731,7 @@ type AllowedRelation_PublicWildcard struct { func (x *AllowedRelation_PublicWildcard) Reset() { *x = AllowedRelation_PublicWildcard{} - mi := &file_core_v1_core_proto_msgTypes[36] + mi := &file_core_v1_core_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2607,7 +2743,7 @@ func (x *AllowedRelation_PublicWildcard) String() string { func (*AllowedRelation_PublicWildcard) ProtoMessage() {} func (x *AllowedRelation_PublicWildcard) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[36] + mi := &file_core_v1_core_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2620,7 +2756,7 @@ func (x *AllowedRelation_PublicWildcard) ProtoReflect() protoreflect.Message { // Deprecated: Use AllowedRelation_PublicWildcard.ProtoReflect.Descriptor instead. func (*AllowedRelation_PublicWildcard) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{20, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{21, 0} } type SetOperation_Child struct { @@ -2647,7 +2783,7 @@ type SetOperation_Child struct { func (x *SetOperation_Child) Reset() { *x = SetOperation_Child{} - mi := &file_core_v1_core_proto_msgTypes[37] + mi := &file_core_v1_core_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2659,7 +2795,7 @@ func (x *SetOperation_Child) String() string { func (*SetOperation_Child) ProtoMessage() {} func (x *SetOperation_Child) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[37] + mi := &file_core_v1_core_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2672,7 +2808,7 @@ func (x *SetOperation_Child) ProtoReflect() protoreflect.Message { // Deprecated: Use SetOperation_Child.ProtoReflect.Descriptor instead. func (*SetOperation_Child) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{24, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{25, 0} } func (x *SetOperation_Child) GetChildType() isSetOperation_Child_ChildType { @@ -2798,7 +2934,7 @@ type SetOperation_Child_This struct { func (x *SetOperation_Child_This) Reset() { *x = SetOperation_Child_This{} - mi := &file_core_v1_core_proto_msgTypes[38] + mi := &file_core_v1_core_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2810,7 +2946,7 @@ func (x *SetOperation_Child_This) String() string { func (*SetOperation_Child_This) ProtoMessage() {} func (x *SetOperation_Child_This) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[38] + mi := &file_core_v1_core_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2823,7 +2959,7 @@ func (x *SetOperation_Child_This) ProtoReflect() protoreflect.Message { // Deprecated: Use SetOperation_Child_This.ProtoReflect.Descriptor instead. func (*SetOperation_Child_This) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{24, 0, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{25, 0, 0} } type SetOperation_Child_Nil struct { @@ -2834,7 +2970,7 @@ type SetOperation_Child_Nil struct { func (x *SetOperation_Child_Nil) Reset() { *x = SetOperation_Child_Nil{} - mi := &file_core_v1_core_proto_msgTypes[39] + mi := &file_core_v1_core_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2846,7 +2982,7 @@ func (x *SetOperation_Child_Nil) String() string { func (*SetOperation_Child_Nil) ProtoMessage() {} func (x *SetOperation_Child_Nil) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[39] + mi := &file_core_v1_core_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2859,7 +2995,7 @@ func (x *SetOperation_Child_Nil) ProtoReflect() protoreflect.Message { // Deprecated: Use SetOperation_Child_Nil.ProtoReflect.Descriptor instead. func (*SetOperation_Child_Nil) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{24, 0, 1} + return file_core_v1_core_proto_rawDescGZIP(), []int{25, 0, 1} } type TupleToUserset_Tupleset struct { @@ -2871,7 +3007,7 @@ type TupleToUserset_Tupleset struct { func (x *TupleToUserset_Tupleset) Reset() { *x = TupleToUserset_Tupleset{} - mi := &file_core_v1_core_proto_msgTypes[40] + mi := &file_core_v1_core_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2883,7 +3019,7 @@ func (x *TupleToUserset_Tupleset) String() string { func (*TupleToUserset_Tupleset) ProtoMessage() {} func (x *TupleToUserset_Tupleset) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[40] + mi := &file_core_v1_core_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2896,7 +3032,7 @@ func (x *TupleToUserset_Tupleset) ProtoReflect() protoreflect.Message { // Deprecated: Use TupleToUserset_Tupleset.ProtoReflect.Descriptor instead. func (*TupleToUserset_Tupleset) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{25, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{26, 0} } func (x *TupleToUserset_Tupleset) GetRelation() string { @@ -2915,7 +3051,7 @@ type FunctionedTupleToUserset_Tupleset struct { func (x *FunctionedTupleToUserset_Tupleset) Reset() { *x = FunctionedTupleToUserset_Tupleset{} - mi := &file_core_v1_core_proto_msgTypes[41] + mi := &file_core_v1_core_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2927,7 +3063,7 @@ func (x *FunctionedTupleToUserset_Tupleset) String() string { func (*FunctionedTupleToUserset_Tupleset) ProtoMessage() {} func (x *FunctionedTupleToUserset_Tupleset) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[41] + mi := &file_core_v1_core_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2940,7 +3076,7 @@ func (x *FunctionedTupleToUserset_Tupleset) ProtoReflect() protoreflect.Message // Deprecated: Use FunctionedTupleToUserset_Tupleset.ProtoReflect.Descriptor instead. func (*FunctionedTupleToUserset_Tupleset) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{26, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{27, 0} } func (x *FunctionedTupleToUserset_Tupleset) GetRelation() string { @@ -2959,7 +3095,7 @@ type SubjectFilter_RelationFilter struct { func (x *SubjectFilter_RelationFilter) Reset() { *x = SubjectFilter_RelationFilter{} - mi := &file_core_v1_core_proto_msgTypes[42] + mi := &file_core_v1_core_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2971,7 +3107,7 @@ func (x *SubjectFilter_RelationFilter) String() string { func (*SubjectFilter_RelationFilter) ProtoMessage() {} func (x *SubjectFilter_RelationFilter) ProtoReflect() protoreflect.Message { - mi := &file_core_v1_core_proto_msgTypes[42] + mi := &file_core_v1_core_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2984,7 +3120,7 @@ func (x *SubjectFilter_RelationFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use SubjectFilter_RelationFilter.ProtoReflect.Descriptor instead. func (*SubjectFilter_RelationFilter) Descriptor() ([]byte, []int) { - return file_core_v1_core_proto_rawDescGZIP(), []int{32, 0} + return file_core_v1_core_proto_rawDescGZIP(), []int{33, 0} } func (x *SubjectFilter_RelationFilter) GetRelation() string { @@ -3069,12 +3205,16 @@ const file_core_v1_core_proto_rawDesc = "" + "\x0eDirectSubjects\x122\n" + "\bsubjects\x18\x01 \x03(\v2\x16.core.v1.DirectSubjectR\bsubjects\"\xb8\x01\n" + "\bMetadata\x12\xab\x01\n" + - "\x10metadata_message\x18\x01 \x03(\v2\x14.google.protobuf.AnyBj\xfaBg\x92\x01d\b\x01\"`\x8a\x01\x02\x10\x01\xa2\x01X\b\x01\x12&type.googleapis.com/impl.v1.DocComment\x12,type.googleapis.com/impl.v1.RelationMetadataR\x0fmetadataMessage\"\x93\x02\n" + + "\x10metadata_message\x18\x01 \x03(\v2\x14.google.protobuf.AnyBj\xfaBg\x92\x01d\b\x01\"`\x8a\x01\x02\x10\x01\xa2\x01X\b\x01\x12&type.googleapis.com/impl.v1.DocComment\x12,type.googleapis.com/impl.v1.RelationMetadataR\x0fmetadataMessage\"\xcb\x02\n" + "\x13NamespaceDefinition\x12\\\n" + "\x04name\x18\x01 \x01(\tBH\xfaBErC(\x80\x012>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$R\x04name\x12-\n" + "\brelation\x18\x02 \x03(\v2\x11.core.v1.RelationR\brelation\x12-\n" + "\bmetadata\x18\x03 \x01(\v2\x11.core.v1.MetadataR\bmetadata\x12@\n" + - "\x0fsource_position\x18\x04 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\"\x9c\x03\n" + + "\x0fsource_position\x18\x04 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x126\n" + + "\vdeprecation\x18\x05 \x01(\v2\x14.core.v1.DeprecationR\vdeprecation\"\x82\x01\n" + + "\vDeprecation\x12M\n" + + "\x10deprecation_type\x18\x01 \x01(\x0e2\x18.core.v1.DeprecationTypeB\b\xfaB\x05\x82\x01\x02\x10\x01R\x0fdeprecationType\x12$\n" + + "\bcomments\x18\x02 \x01(\tB\b\xfaB\x05r\x03(\x80\x02R\bcomments\"\xd4\x03\n" + "\bRelation\x12;\n" + "\x04name\x18\x01 \x01(\tB'\xfaB$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$R\x04name\x12@\n" + "\x0fuserset_rewrite\x18\x02 \x01(\v2\x17.core.v1.UsersetRewriteR\x0eusersetRewrite\x12C\n" + @@ -3082,7 +3222,8 @@ const file_core_v1_core_proto_rawDesc = "" + "\bmetadata\x18\x04 \x01(\v2\x11.core.v1.MetadataR\bmetadata\x12@\n" + "\x0fsource_position\x18\x05 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x12+\n" + "\x11aliasing_relation\x18\x06 \x01(\tR\x10aliasingRelation\x12.\n" + - "\x13canonical_cache_key\x18\a \x01(\tR\x11canonicalCacheKey\"\xf4\x03\n" + + "\x13canonical_cache_key\x18\a \x01(\tR\x11canonicalCacheKey\x126\n" + + "\vdeprecation\x18\b \x01(\v2\x14.core.v1.DeprecationR\vdeprecation\"\xf4\x03\n" + "\x11ReachabilityGraph\x12w\n" + "\x1bentrypoints_by_subject_type\x18\x01 \x03(\v28.core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntryR\x18entrypointsBySubjectType\x12\x83\x01\n" + "\x1fentrypoints_by_subject_relation\x18\x02 \x03(\v2<.core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntryR\x1centrypointsBySubjectRelation\x1am\n" + @@ -3110,14 +3251,15 @@ const file_core_v1_core_proto_rawDesc = "" + "\x1cREACHABLE_CONDITIONAL_RESULT\x10\x00\x12\x1b\n" + "\x17DIRECT_OPERATION_RESULT\x10\x01J\x04\b\x03\x10\x04\"e\n" + "\x0fTypeInformation\x12R\n" + - "\x18allowed_direct_relations\x18\x01 \x03(\v2\x18.core.v1.AllowedRelationR\x16allowedDirectRelations\"\x95\x04\n" + + "\x18allowed_direct_relations\x18\x01 \x03(\v2\x18.core.v1.AllowedRelationR\x16allowedDirectRelations\"\xcd\x04\n" + "\x0fAllowedRelation\x12f\n" + "\tnamespace\x18\x01 \x01(\tBH\xfaBErC(\x80\x012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12N\n" + "\brelation\x18\x03 \x01(\tB0\xfaB-r+(@2'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$H\x00R\brelation\x12R\n" + "\x0fpublic_wildcard\x18\x04 \x01(\v2'.core.v1.AllowedRelation.PublicWildcardH\x00R\x0epublicWildcard\x12@\n" + "\x0fsource_position\x18\x05 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x12?\n" + "\x0frequired_caveat\x18\x06 \x01(\v2\x16.core.v1.AllowedCaveatR\x0erequiredCaveat\x12I\n" + - "\x13required_expiration\x18\a \x01(\v2\x18.core.v1.ExpirationTraitR\x12requiredExpiration\x1a\x10\n" + + "\x13required_expiration\x18\a \x01(\v2\x18.core.v1.ExpirationTraitR\x12requiredExpiration\x126\n" + + "\vdeprecation\x18\b \x01(\v2\x14.core.v1.DeprecationR\vdeprecation\x1a\x10\n" + "\x0ePublicWildcardB\x16\n" + "\x14relation_or_wildcard\"\x11\n" + "\x0fExpirationTrait\"0\n" + @@ -3196,7 +3338,11 @@ const file_core_v1_core_proto_rawDesc = "" + "\x13optional_subject_id\x18\x02 \x01(\tB*\xfaB'r%(\x80\b2 ^(([a-zA-Z0-9/_|\\-=+]{1,})|\\*)?$R\x11optionalSubjectId\x12R\n" + "\x11optional_relation\x18\x03 \x01(\v2%.core.v1.SubjectFilter.RelationFilterR\x10optionalRelation\x1aX\n" + "\x0eRelationFilter\x12F\n" + - "\brelation\x18\x01 \x01(\tB*\xfaB'r%(@2!^([a-z][a-z0-9_]{1,62}[a-z0-9])?$R\brelationB\x8a\x01\n" + + "\brelation\x18\x01 \x01(\tB*\xfaB'r%(@2!^([a-z][a-z0-9_]{1,62}[a-z0-9])?$R\brelation*j\n" + + "\x0fDeprecationType\x12\x1f\n" + + "\x1bDEPRECATED_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n" + + "\x17DEPRECATED_TYPE_WARNING\x10\x01\x12\x19\n" + + "\x15DEPRECATED_TYPE_ERROR\x10\x02B\x8a\x01\n" + "\vcom.core.v1B\tCoreProtoP\x01Z3github.com/authzed/spicedb/pkg/proto/core/v1;corev1\xa2\x02\x03CXX\xaa\x02\aCore.V1\xca\x02\aCore\\V1\xe2\x02\x13Core\\V1\\GPBMetadata\xea\x02\bCore::V1b\x06proto3" var ( @@ -3211,141 +3357,147 @@ func file_core_v1_core_proto_rawDescGZIP() []byte { return file_core_v1_core_proto_rawDescData } -var file_core_v1_core_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_core_v1_core_proto_msgTypes = make([]protoimpl.MessageInfo, 43) +var file_core_v1_core_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_core_v1_core_proto_msgTypes = make([]protoimpl.MessageInfo, 44) var file_core_v1_core_proto_goTypes = []any{ - (RelationTupleUpdate_Operation)(0), // 0: core.v1.RelationTupleUpdate.Operation - (SetOperationUserset_Operation)(0), // 1: core.v1.SetOperationUserset.Operation - (ReachabilityEntrypoint_ReachabilityEntrypointKind)(0), // 2: core.v1.ReachabilityEntrypoint.ReachabilityEntrypointKind - (ReachabilityEntrypoint_EntrypointResultStatus)(0), // 3: core.v1.ReachabilityEntrypoint.EntrypointResultStatus - (FunctionedTupleToUserset_Function)(0), // 4: core.v1.FunctionedTupleToUserset.Function - (ComputedUserset_Object)(0), // 5: core.v1.ComputedUserset.Object - (CaveatOperation_Operation)(0), // 6: core.v1.CaveatOperation.Operation - (*RelationTuple)(nil), // 7: core.v1.RelationTuple - (*RelationshipIntegrity)(nil), // 8: core.v1.RelationshipIntegrity - (*ContextualizedCaveat)(nil), // 9: core.v1.ContextualizedCaveat - (*CaveatDefinition)(nil), // 10: core.v1.CaveatDefinition - (*CaveatTypeReference)(nil), // 11: core.v1.CaveatTypeReference - (*ObjectAndRelation)(nil), // 12: core.v1.ObjectAndRelation - (*RelationReference)(nil), // 13: core.v1.RelationReference - (*Zookie)(nil), // 14: core.v1.Zookie - (*RelationTupleUpdate)(nil), // 15: core.v1.RelationTupleUpdate - (*RelationTupleTreeNode)(nil), // 16: core.v1.RelationTupleTreeNode - (*SetOperationUserset)(nil), // 17: core.v1.SetOperationUserset - (*DirectSubject)(nil), // 18: core.v1.DirectSubject - (*DirectSubjects)(nil), // 19: core.v1.DirectSubjects - (*Metadata)(nil), // 20: core.v1.Metadata - (*NamespaceDefinition)(nil), // 21: core.v1.NamespaceDefinition - (*Relation)(nil), // 22: core.v1.Relation - (*ReachabilityGraph)(nil), // 23: core.v1.ReachabilityGraph - (*ReachabilityEntrypoints)(nil), // 24: core.v1.ReachabilityEntrypoints - (*ReachabilityEntrypoint)(nil), // 25: core.v1.ReachabilityEntrypoint - (*TypeInformation)(nil), // 26: core.v1.TypeInformation - (*AllowedRelation)(nil), // 27: core.v1.AllowedRelation - (*ExpirationTrait)(nil), // 28: core.v1.ExpirationTrait - (*AllowedCaveat)(nil), // 29: core.v1.AllowedCaveat - (*UsersetRewrite)(nil), // 30: core.v1.UsersetRewrite - (*SetOperation)(nil), // 31: core.v1.SetOperation - (*TupleToUserset)(nil), // 32: core.v1.TupleToUserset - (*FunctionedTupleToUserset)(nil), // 33: core.v1.FunctionedTupleToUserset - (*ComputedUserset)(nil), // 34: core.v1.ComputedUserset - (*SourcePosition)(nil), // 35: core.v1.SourcePosition - (*CaveatExpression)(nil), // 36: core.v1.CaveatExpression - (*CaveatOperation)(nil), // 37: core.v1.CaveatOperation - (*RelationshipFilter)(nil), // 38: core.v1.RelationshipFilter - (*SubjectFilter)(nil), // 39: core.v1.SubjectFilter - nil, // 40: core.v1.CaveatDefinition.ParameterTypesEntry - nil, // 41: core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry - nil, // 42: core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry - (*AllowedRelation_PublicWildcard)(nil), // 43: core.v1.AllowedRelation.PublicWildcard - (*SetOperation_Child)(nil), // 44: core.v1.SetOperation.Child - (*SetOperation_Child_This)(nil), // 45: core.v1.SetOperation.Child.This - (*SetOperation_Child_Nil)(nil), // 46: core.v1.SetOperation.Child.Nil - (*TupleToUserset_Tupleset)(nil), // 47: core.v1.TupleToUserset.Tupleset - (*FunctionedTupleToUserset_Tupleset)(nil), // 48: core.v1.FunctionedTupleToUserset.Tupleset - (*SubjectFilter_RelationFilter)(nil), // 49: core.v1.SubjectFilter.RelationFilter - (*timestamppb.Timestamp)(nil), // 50: google.protobuf.Timestamp - (*structpb.Struct)(nil), // 51: google.protobuf.Struct - (*anypb.Any)(nil), // 52: google.protobuf.Any + (DeprecationType)(0), // 0: core.v1.DeprecationType + (RelationTupleUpdate_Operation)(0), // 1: core.v1.RelationTupleUpdate.Operation + (SetOperationUserset_Operation)(0), // 2: core.v1.SetOperationUserset.Operation + (ReachabilityEntrypoint_ReachabilityEntrypointKind)(0), // 3: core.v1.ReachabilityEntrypoint.ReachabilityEntrypointKind + (ReachabilityEntrypoint_EntrypointResultStatus)(0), // 4: core.v1.ReachabilityEntrypoint.EntrypointResultStatus + (FunctionedTupleToUserset_Function)(0), // 5: core.v1.FunctionedTupleToUserset.Function + (ComputedUserset_Object)(0), // 6: core.v1.ComputedUserset.Object + (CaveatOperation_Operation)(0), // 7: core.v1.CaveatOperation.Operation + (*RelationTuple)(nil), // 8: core.v1.RelationTuple + (*RelationshipIntegrity)(nil), // 9: core.v1.RelationshipIntegrity + (*ContextualizedCaveat)(nil), // 10: core.v1.ContextualizedCaveat + (*CaveatDefinition)(nil), // 11: core.v1.CaveatDefinition + (*CaveatTypeReference)(nil), // 12: core.v1.CaveatTypeReference + (*ObjectAndRelation)(nil), // 13: core.v1.ObjectAndRelation + (*RelationReference)(nil), // 14: core.v1.RelationReference + (*Zookie)(nil), // 15: core.v1.Zookie + (*RelationTupleUpdate)(nil), // 16: core.v1.RelationTupleUpdate + (*RelationTupleTreeNode)(nil), // 17: core.v1.RelationTupleTreeNode + (*SetOperationUserset)(nil), // 18: core.v1.SetOperationUserset + (*DirectSubject)(nil), // 19: core.v1.DirectSubject + (*DirectSubjects)(nil), // 20: core.v1.DirectSubjects + (*Metadata)(nil), // 21: core.v1.Metadata + (*NamespaceDefinition)(nil), // 22: core.v1.NamespaceDefinition + (*Deprecation)(nil), // 23: core.v1.Deprecation + (*Relation)(nil), // 24: core.v1.Relation + (*ReachabilityGraph)(nil), // 25: core.v1.ReachabilityGraph + (*ReachabilityEntrypoints)(nil), // 26: core.v1.ReachabilityEntrypoints + (*ReachabilityEntrypoint)(nil), // 27: core.v1.ReachabilityEntrypoint + (*TypeInformation)(nil), // 28: core.v1.TypeInformation + (*AllowedRelation)(nil), // 29: core.v1.AllowedRelation + (*ExpirationTrait)(nil), // 30: core.v1.ExpirationTrait + (*AllowedCaveat)(nil), // 31: core.v1.AllowedCaveat + (*UsersetRewrite)(nil), // 32: core.v1.UsersetRewrite + (*SetOperation)(nil), // 33: core.v1.SetOperation + (*TupleToUserset)(nil), // 34: core.v1.TupleToUserset + (*FunctionedTupleToUserset)(nil), // 35: core.v1.FunctionedTupleToUserset + (*ComputedUserset)(nil), // 36: core.v1.ComputedUserset + (*SourcePosition)(nil), // 37: core.v1.SourcePosition + (*CaveatExpression)(nil), // 38: core.v1.CaveatExpression + (*CaveatOperation)(nil), // 39: core.v1.CaveatOperation + (*RelationshipFilter)(nil), // 40: core.v1.RelationshipFilter + (*SubjectFilter)(nil), // 41: core.v1.SubjectFilter + nil, // 42: core.v1.CaveatDefinition.ParameterTypesEntry + nil, // 43: core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry + nil, // 44: core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry + (*AllowedRelation_PublicWildcard)(nil), // 45: core.v1.AllowedRelation.PublicWildcard + (*SetOperation_Child)(nil), // 46: core.v1.SetOperation.Child + (*SetOperation_Child_This)(nil), // 47: core.v1.SetOperation.Child.This + (*SetOperation_Child_Nil)(nil), // 48: core.v1.SetOperation.Child.Nil + (*TupleToUserset_Tupleset)(nil), // 49: core.v1.TupleToUserset.Tupleset + (*FunctionedTupleToUserset_Tupleset)(nil), // 50: core.v1.FunctionedTupleToUserset.Tupleset + (*SubjectFilter_RelationFilter)(nil), // 51: core.v1.SubjectFilter.RelationFilter + (*timestamppb.Timestamp)(nil), // 52: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 53: google.protobuf.Struct + (*anypb.Any)(nil), // 54: google.protobuf.Any } var file_core_v1_core_proto_depIdxs = []int32{ - 12, // 0: core.v1.RelationTuple.resource_and_relation:type_name -> core.v1.ObjectAndRelation - 12, // 1: core.v1.RelationTuple.subject:type_name -> core.v1.ObjectAndRelation - 9, // 2: core.v1.RelationTuple.caveat:type_name -> core.v1.ContextualizedCaveat - 8, // 3: core.v1.RelationTuple.integrity:type_name -> core.v1.RelationshipIntegrity - 50, // 4: core.v1.RelationTuple.optional_expiration_time:type_name -> google.protobuf.Timestamp - 50, // 5: core.v1.RelationshipIntegrity.hashed_at:type_name -> google.protobuf.Timestamp - 51, // 6: core.v1.ContextualizedCaveat.context:type_name -> google.protobuf.Struct - 40, // 7: core.v1.CaveatDefinition.parameter_types:type_name -> core.v1.CaveatDefinition.ParameterTypesEntry - 20, // 8: core.v1.CaveatDefinition.metadata:type_name -> core.v1.Metadata - 35, // 9: core.v1.CaveatDefinition.source_position:type_name -> core.v1.SourcePosition - 11, // 10: core.v1.CaveatTypeReference.child_types:type_name -> core.v1.CaveatTypeReference - 0, // 11: core.v1.RelationTupleUpdate.operation:type_name -> core.v1.RelationTupleUpdate.Operation - 7, // 12: core.v1.RelationTupleUpdate.tuple:type_name -> core.v1.RelationTuple - 17, // 13: core.v1.RelationTupleTreeNode.intermediate_node:type_name -> core.v1.SetOperationUserset - 19, // 14: core.v1.RelationTupleTreeNode.leaf_node:type_name -> core.v1.DirectSubjects - 12, // 15: core.v1.RelationTupleTreeNode.expanded:type_name -> core.v1.ObjectAndRelation - 36, // 16: core.v1.RelationTupleTreeNode.caveat_expression:type_name -> core.v1.CaveatExpression - 1, // 17: core.v1.SetOperationUserset.operation:type_name -> core.v1.SetOperationUserset.Operation - 16, // 18: core.v1.SetOperationUserset.child_nodes:type_name -> core.v1.RelationTupleTreeNode - 12, // 19: core.v1.DirectSubject.subject:type_name -> core.v1.ObjectAndRelation - 36, // 20: core.v1.DirectSubject.caveat_expression:type_name -> core.v1.CaveatExpression - 18, // 21: core.v1.DirectSubjects.subjects:type_name -> core.v1.DirectSubject - 52, // 22: core.v1.Metadata.metadata_message:type_name -> google.protobuf.Any - 22, // 23: core.v1.NamespaceDefinition.relation:type_name -> core.v1.Relation - 20, // 24: core.v1.NamespaceDefinition.metadata:type_name -> core.v1.Metadata - 35, // 25: core.v1.NamespaceDefinition.source_position:type_name -> core.v1.SourcePosition - 30, // 26: core.v1.Relation.userset_rewrite:type_name -> core.v1.UsersetRewrite - 26, // 27: core.v1.Relation.type_information:type_name -> core.v1.TypeInformation - 20, // 28: core.v1.Relation.metadata:type_name -> core.v1.Metadata - 35, // 29: core.v1.Relation.source_position:type_name -> core.v1.SourcePosition - 41, // 30: core.v1.ReachabilityGraph.entrypoints_by_subject_type:type_name -> core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry - 42, // 31: core.v1.ReachabilityGraph.entrypoints_by_subject_relation:type_name -> core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry - 25, // 32: core.v1.ReachabilityEntrypoints.entrypoints:type_name -> core.v1.ReachabilityEntrypoint - 13, // 33: core.v1.ReachabilityEntrypoints.subject_relation:type_name -> core.v1.RelationReference - 2, // 34: core.v1.ReachabilityEntrypoint.kind:type_name -> core.v1.ReachabilityEntrypoint.ReachabilityEntrypointKind - 13, // 35: core.v1.ReachabilityEntrypoint.target_relation:type_name -> core.v1.RelationReference - 3, // 36: core.v1.ReachabilityEntrypoint.result_status:type_name -> core.v1.ReachabilityEntrypoint.EntrypointResultStatus - 27, // 37: core.v1.TypeInformation.allowed_direct_relations:type_name -> core.v1.AllowedRelation - 43, // 38: core.v1.AllowedRelation.public_wildcard:type_name -> core.v1.AllowedRelation.PublicWildcard - 35, // 39: core.v1.AllowedRelation.source_position:type_name -> core.v1.SourcePosition - 29, // 40: core.v1.AllowedRelation.required_caveat:type_name -> core.v1.AllowedCaveat - 28, // 41: core.v1.AllowedRelation.required_expiration:type_name -> core.v1.ExpirationTrait - 31, // 42: core.v1.UsersetRewrite.union:type_name -> core.v1.SetOperation - 31, // 43: core.v1.UsersetRewrite.intersection:type_name -> core.v1.SetOperation - 31, // 44: core.v1.UsersetRewrite.exclusion:type_name -> core.v1.SetOperation - 35, // 45: core.v1.UsersetRewrite.source_position:type_name -> core.v1.SourcePosition - 44, // 46: core.v1.SetOperation.child:type_name -> core.v1.SetOperation.Child - 47, // 47: core.v1.TupleToUserset.tupleset:type_name -> core.v1.TupleToUserset.Tupleset - 34, // 48: core.v1.TupleToUserset.computed_userset:type_name -> core.v1.ComputedUserset - 35, // 49: core.v1.TupleToUserset.source_position:type_name -> core.v1.SourcePosition - 4, // 50: core.v1.FunctionedTupleToUserset.function:type_name -> core.v1.FunctionedTupleToUserset.Function - 48, // 51: core.v1.FunctionedTupleToUserset.tupleset:type_name -> core.v1.FunctionedTupleToUserset.Tupleset - 34, // 52: core.v1.FunctionedTupleToUserset.computed_userset:type_name -> core.v1.ComputedUserset - 35, // 53: core.v1.FunctionedTupleToUserset.source_position:type_name -> core.v1.SourcePosition - 5, // 54: core.v1.ComputedUserset.object:type_name -> core.v1.ComputedUserset.Object - 35, // 55: core.v1.ComputedUserset.source_position:type_name -> core.v1.SourcePosition - 37, // 56: core.v1.CaveatExpression.operation:type_name -> core.v1.CaveatOperation - 9, // 57: core.v1.CaveatExpression.caveat:type_name -> core.v1.ContextualizedCaveat - 6, // 58: core.v1.CaveatOperation.op:type_name -> core.v1.CaveatOperation.Operation - 36, // 59: core.v1.CaveatOperation.children:type_name -> core.v1.CaveatExpression - 39, // 60: core.v1.RelationshipFilter.optional_subject_filter:type_name -> core.v1.SubjectFilter - 49, // 61: core.v1.SubjectFilter.optional_relation:type_name -> core.v1.SubjectFilter.RelationFilter - 11, // 62: core.v1.CaveatDefinition.ParameterTypesEntry.value:type_name -> core.v1.CaveatTypeReference - 24, // 63: core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry.value:type_name -> core.v1.ReachabilityEntrypoints - 24, // 64: core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry.value:type_name -> core.v1.ReachabilityEntrypoints - 45, // 65: core.v1.SetOperation.Child._this:type_name -> core.v1.SetOperation.Child.This - 34, // 66: core.v1.SetOperation.Child.computed_userset:type_name -> core.v1.ComputedUserset - 32, // 67: core.v1.SetOperation.Child.tuple_to_userset:type_name -> core.v1.TupleToUserset - 30, // 68: core.v1.SetOperation.Child.userset_rewrite:type_name -> core.v1.UsersetRewrite - 33, // 69: core.v1.SetOperation.Child.functioned_tuple_to_userset:type_name -> core.v1.FunctionedTupleToUserset - 46, // 70: core.v1.SetOperation.Child._nil:type_name -> core.v1.SetOperation.Child.Nil - 35, // 71: core.v1.SetOperation.Child.source_position:type_name -> core.v1.SourcePosition - 72, // [72:72] is the sub-list for method output_type - 72, // [72:72] is the sub-list for method input_type - 72, // [72:72] is the sub-list for extension type_name - 72, // [72:72] is the sub-list for extension extendee - 0, // [0:72] is the sub-list for field type_name + 13, // 0: core.v1.RelationTuple.resource_and_relation:type_name -> core.v1.ObjectAndRelation + 13, // 1: core.v1.RelationTuple.subject:type_name -> core.v1.ObjectAndRelation + 10, // 2: core.v1.RelationTuple.caveat:type_name -> core.v1.ContextualizedCaveat + 9, // 3: core.v1.RelationTuple.integrity:type_name -> core.v1.RelationshipIntegrity + 52, // 4: core.v1.RelationTuple.optional_expiration_time:type_name -> google.protobuf.Timestamp + 52, // 5: core.v1.RelationshipIntegrity.hashed_at:type_name -> google.protobuf.Timestamp + 53, // 6: core.v1.ContextualizedCaveat.context:type_name -> google.protobuf.Struct + 42, // 7: core.v1.CaveatDefinition.parameter_types:type_name -> core.v1.CaveatDefinition.ParameterTypesEntry + 21, // 8: core.v1.CaveatDefinition.metadata:type_name -> core.v1.Metadata + 37, // 9: core.v1.CaveatDefinition.source_position:type_name -> core.v1.SourcePosition + 12, // 10: core.v1.CaveatTypeReference.child_types:type_name -> core.v1.CaveatTypeReference + 1, // 11: core.v1.RelationTupleUpdate.operation:type_name -> core.v1.RelationTupleUpdate.Operation + 8, // 12: core.v1.RelationTupleUpdate.tuple:type_name -> core.v1.RelationTuple + 18, // 13: core.v1.RelationTupleTreeNode.intermediate_node:type_name -> core.v1.SetOperationUserset + 20, // 14: core.v1.RelationTupleTreeNode.leaf_node:type_name -> core.v1.DirectSubjects + 13, // 15: core.v1.RelationTupleTreeNode.expanded:type_name -> core.v1.ObjectAndRelation + 38, // 16: core.v1.RelationTupleTreeNode.caveat_expression:type_name -> core.v1.CaveatExpression + 2, // 17: core.v1.SetOperationUserset.operation:type_name -> core.v1.SetOperationUserset.Operation + 17, // 18: core.v1.SetOperationUserset.child_nodes:type_name -> core.v1.RelationTupleTreeNode + 13, // 19: core.v1.DirectSubject.subject:type_name -> core.v1.ObjectAndRelation + 38, // 20: core.v1.DirectSubject.caveat_expression:type_name -> core.v1.CaveatExpression + 19, // 21: core.v1.DirectSubjects.subjects:type_name -> core.v1.DirectSubject + 54, // 22: core.v1.Metadata.metadata_message:type_name -> google.protobuf.Any + 24, // 23: core.v1.NamespaceDefinition.relation:type_name -> core.v1.Relation + 21, // 24: core.v1.NamespaceDefinition.metadata:type_name -> core.v1.Metadata + 37, // 25: core.v1.NamespaceDefinition.source_position:type_name -> core.v1.SourcePosition + 23, // 26: core.v1.NamespaceDefinition.deprecation:type_name -> core.v1.Deprecation + 0, // 27: core.v1.Deprecation.deprecation_type:type_name -> core.v1.DeprecationType + 32, // 28: core.v1.Relation.userset_rewrite:type_name -> core.v1.UsersetRewrite + 28, // 29: core.v1.Relation.type_information:type_name -> core.v1.TypeInformation + 21, // 30: core.v1.Relation.metadata:type_name -> core.v1.Metadata + 37, // 31: core.v1.Relation.source_position:type_name -> core.v1.SourcePosition + 23, // 32: core.v1.Relation.deprecation:type_name -> core.v1.Deprecation + 43, // 33: core.v1.ReachabilityGraph.entrypoints_by_subject_type:type_name -> core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry + 44, // 34: core.v1.ReachabilityGraph.entrypoints_by_subject_relation:type_name -> core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry + 27, // 35: core.v1.ReachabilityEntrypoints.entrypoints:type_name -> core.v1.ReachabilityEntrypoint + 14, // 36: core.v1.ReachabilityEntrypoints.subject_relation:type_name -> core.v1.RelationReference + 3, // 37: core.v1.ReachabilityEntrypoint.kind:type_name -> core.v1.ReachabilityEntrypoint.ReachabilityEntrypointKind + 14, // 38: core.v1.ReachabilityEntrypoint.target_relation:type_name -> core.v1.RelationReference + 4, // 39: core.v1.ReachabilityEntrypoint.result_status:type_name -> core.v1.ReachabilityEntrypoint.EntrypointResultStatus + 29, // 40: core.v1.TypeInformation.allowed_direct_relations:type_name -> core.v1.AllowedRelation + 45, // 41: core.v1.AllowedRelation.public_wildcard:type_name -> core.v1.AllowedRelation.PublicWildcard + 37, // 42: core.v1.AllowedRelation.source_position:type_name -> core.v1.SourcePosition + 31, // 43: core.v1.AllowedRelation.required_caveat:type_name -> core.v1.AllowedCaveat + 30, // 44: core.v1.AllowedRelation.required_expiration:type_name -> core.v1.ExpirationTrait + 23, // 45: core.v1.AllowedRelation.deprecation:type_name -> core.v1.Deprecation + 33, // 46: core.v1.UsersetRewrite.union:type_name -> core.v1.SetOperation + 33, // 47: core.v1.UsersetRewrite.intersection:type_name -> core.v1.SetOperation + 33, // 48: core.v1.UsersetRewrite.exclusion:type_name -> core.v1.SetOperation + 37, // 49: core.v1.UsersetRewrite.source_position:type_name -> core.v1.SourcePosition + 46, // 50: core.v1.SetOperation.child:type_name -> core.v1.SetOperation.Child + 49, // 51: core.v1.TupleToUserset.tupleset:type_name -> core.v1.TupleToUserset.Tupleset + 36, // 52: core.v1.TupleToUserset.computed_userset:type_name -> core.v1.ComputedUserset + 37, // 53: core.v1.TupleToUserset.source_position:type_name -> core.v1.SourcePosition + 5, // 54: core.v1.FunctionedTupleToUserset.function:type_name -> core.v1.FunctionedTupleToUserset.Function + 50, // 55: core.v1.FunctionedTupleToUserset.tupleset:type_name -> core.v1.FunctionedTupleToUserset.Tupleset + 36, // 56: core.v1.FunctionedTupleToUserset.computed_userset:type_name -> core.v1.ComputedUserset + 37, // 57: core.v1.FunctionedTupleToUserset.source_position:type_name -> core.v1.SourcePosition + 6, // 58: core.v1.ComputedUserset.object:type_name -> core.v1.ComputedUserset.Object + 37, // 59: core.v1.ComputedUserset.source_position:type_name -> core.v1.SourcePosition + 39, // 60: core.v1.CaveatExpression.operation:type_name -> core.v1.CaveatOperation + 10, // 61: core.v1.CaveatExpression.caveat:type_name -> core.v1.ContextualizedCaveat + 7, // 62: core.v1.CaveatOperation.op:type_name -> core.v1.CaveatOperation.Operation + 38, // 63: core.v1.CaveatOperation.children:type_name -> core.v1.CaveatExpression + 41, // 64: core.v1.RelationshipFilter.optional_subject_filter:type_name -> core.v1.SubjectFilter + 51, // 65: core.v1.SubjectFilter.optional_relation:type_name -> core.v1.SubjectFilter.RelationFilter + 12, // 66: core.v1.CaveatDefinition.ParameterTypesEntry.value:type_name -> core.v1.CaveatTypeReference + 26, // 67: core.v1.ReachabilityGraph.EntrypointsBySubjectTypeEntry.value:type_name -> core.v1.ReachabilityEntrypoints + 26, // 68: core.v1.ReachabilityGraph.EntrypointsBySubjectRelationEntry.value:type_name -> core.v1.ReachabilityEntrypoints + 47, // 69: core.v1.SetOperation.Child._this:type_name -> core.v1.SetOperation.Child.This + 36, // 70: core.v1.SetOperation.Child.computed_userset:type_name -> core.v1.ComputedUserset + 34, // 71: core.v1.SetOperation.Child.tuple_to_userset:type_name -> core.v1.TupleToUserset + 32, // 72: core.v1.SetOperation.Child.userset_rewrite:type_name -> core.v1.UsersetRewrite + 35, // 73: core.v1.SetOperation.Child.functioned_tuple_to_userset:type_name -> core.v1.FunctionedTupleToUserset + 48, // 74: core.v1.SetOperation.Child._nil:type_name -> core.v1.SetOperation.Child.Nil + 37, // 75: core.v1.SetOperation.Child.source_position:type_name -> core.v1.SourcePosition + 76, // [76:76] is the sub-list for method output_type + 76, // [76:76] is the sub-list for method input_type + 76, // [76:76] is the sub-list for extension type_name + 76, // [76:76] is the sub-list for extension extendee + 0, // [0:76] is the sub-list for field type_name } func init() { file_core_v1_core_proto_init() } @@ -3357,20 +3509,20 @@ func file_core_v1_core_proto_init() { (*RelationTupleTreeNode_IntermediateNode)(nil), (*RelationTupleTreeNode_LeafNode)(nil), } - file_core_v1_core_proto_msgTypes[20].OneofWrappers = []any{ + file_core_v1_core_proto_msgTypes[21].OneofWrappers = []any{ (*AllowedRelation_Relation)(nil), (*AllowedRelation_PublicWildcard_)(nil), } - file_core_v1_core_proto_msgTypes[23].OneofWrappers = []any{ + file_core_v1_core_proto_msgTypes[24].OneofWrappers = []any{ (*UsersetRewrite_Union)(nil), (*UsersetRewrite_Intersection)(nil), (*UsersetRewrite_Exclusion)(nil), } - file_core_v1_core_proto_msgTypes[29].OneofWrappers = []any{ + file_core_v1_core_proto_msgTypes[30].OneofWrappers = []any{ (*CaveatExpression_Operation)(nil), (*CaveatExpression_Caveat)(nil), } - file_core_v1_core_proto_msgTypes[37].OneofWrappers = []any{ + file_core_v1_core_proto_msgTypes[38].OneofWrappers = []any{ (*SetOperation_Child_XThis)(nil), (*SetOperation_Child_ComputedUserset)(nil), (*SetOperation_Child_TupleToUserset)(nil), @@ -3383,8 +3535,8 @@ func file_core_v1_core_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_v1_core_proto_rawDesc), len(file_core_v1_core_proto_rawDesc)), - NumEnums: 7, - NumMessages: 43, + NumEnums: 8, + NumMessages: 44, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/proto/core/v1/core.pb.validate.go b/pkg/proto/core/v1/core.pb.validate.go index 021429241..d8db049ba 100644 --- a/pkg/proto/core/v1/core.pb.validate.go +++ b/pkg/proto/core/v1/core.pb.validate.go @@ -2536,6 +2536,35 @@ func (m *NamespaceDefinition) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetDeprecation()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, NamespaceDefinitionValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, NamespaceDefinitionValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDeprecation()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return NamespaceDefinitionValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + } + } + } + if len(errors) > 0 { return NamespaceDefinitionMultiError(errors) } @@ -2618,6 +2647,127 @@ var _ interface { var _NamespaceDefinition_Name_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$") +// Validate checks the field values on Deprecation with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Deprecation) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Deprecation with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in DeprecationMultiError, or +// nil if none found. +func (m *Deprecation) ValidateAll() error { + return m.validate(true) +} + +func (m *Deprecation) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if _, ok := DeprecationType_name[int32(m.GetDeprecationType())]; !ok { + err := DeprecationValidationError{ + field: "DeprecationType", + reason: "value must be one of the defined enum values", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(m.GetComments()) > 256 { + err := DeprecationValidationError{ + field: "Comments", + reason: "value length must be at most 256 bytes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return DeprecationMultiError(errors) + } + + return nil +} + +// DeprecationMultiError is an error wrapping multiple validation errors +// returned by Deprecation.ValidateAll() if the designated constraints aren't met. +type DeprecationMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeprecationMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeprecationMultiError) AllErrors() []error { return m } + +// DeprecationValidationError is the validation error returned by +// Deprecation.Validate if the designated constraints aren't met. +type DeprecationValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeprecationValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeprecationValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeprecationValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeprecationValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeprecationValidationError) ErrorName() string { return "DeprecationValidationError" } + +// Error satisfies the builtin error interface +func (e DeprecationValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeprecation.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = DeprecationValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeprecationValidationError{} + // Validate checks the field values on Relation with the rules defined in the // proto definition for this message. If any rules are violated, the first // error encountered is returned, or nil if there are no violations. @@ -2782,6 +2932,35 @@ func (m *Relation) validate(all bool) error { // no validation rules for CanonicalCacheKey + if all { + switch v := interface{}(m.GetDeprecation()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, RelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, RelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDeprecation()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return RelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + } + } + } + if len(errors) > 0 { return RelationMultiError(errors) } @@ -3626,6 +3805,35 @@ func (m *AllowedRelation) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetDeprecation()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, AllowedRelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, AllowedRelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDeprecation()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return AllowedRelationValidationError{ + field: "Deprecation", + reason: "embedded message failed validation", + cause: err, + } + } + } + switch v := m.RelationOrWildcard.(type) { case *AllowedRelation_Relation: if v == nil { diff --git a/pkg/proto/core/v1/core_vtproto.pb.go b/pkg/proto/core/v1/core_vtproto.pb.go index 160a1d933..e81e698c2 100644 --- a/pkg/proto/core/v1/core_vtproto.pb.go +++ b/pkg/proto/core/v1/core_vtproto.pb.go @@ -351,6 +351,7 @@ func (m *NamespaceDefinition) CloneVT() *NamespaceDefinition { r.Name = m.Name r.Metadata = m.Metadata.CloneVT() r.SourcePosition = m.SourcePosition.CloneVT() + r.Deprecation = m.Deprecation.CloneVT() if rhs := m.Relation; rhs != nil { tmpContainer := make([]*Relation, len(rhs)) for k, v := range rhs { @@ -369,6 +370,24 @@ func (m *NamespaceDefinition) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *Deprecation) CloneVT() *Deprecation { + if m == nil { + return (*Deprecation)(nil) + } + r := new(Deprecation) + r.DeprecationType = m.DeprecationType + r.Comments = m.Comments + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Deprecation) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *Relation) CloneVT() *Relation { if m == nil { return (*Relation)(nil) @@ -381,6 +400,7 @@ func (m *Relation) CloneVT() *Relation { r.SourcePosition = m.SourcePosition.CloneVT() r.AliasingRelation = m.AliasingRelation r.CanonicalCacheKey = m.CanonicalCacheKey + r.Deprecation = m.Deprecation.CloneVT() if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -516,6 +536,7 @@ func (m *AllowedRelation) CloneVT() *AllowedRelation { r.SourcePosition = m.SourcePosition.CloneVT() r.RequiredCaveat = m.RequiredCaveat.CloneVT() r.RequiredExpiration = m.RequiredExpiration.CloneVT() + r.Deprecation = m.Deprecation.CloneVT() if m.RelationOrWildcard != nil { r.RelationOrWildcard = m.RelationOrWildcard.(interface { CloneVT() isAllowedRelation_RelationOrWildcard @@ -1488,6 +1509,9 @@ func (this *NamespaceDefinition) EqualVT(that *NamespaceDefinition) bool { if !this.SourcePosition.EqualVT(that.SourcePosition) { return false } + if !this.Deprecation.EqualVT(that.Deprecation) { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1498,6 +1522,28 @@ func (this *NamespaceDefinition) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *Deprecation) EqualVT(that *Deprecation) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.DeprecationType != that.DeprecationType { + return false + } + if this.Comments != that.Comments { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Deprecation) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Deprecation) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *Relation) EqualVT(that *Relation) bool { if this == that { return true @@ -1525,6 +1571,9 @@ func (this *Relation) EqualVT(that *Relation) bool { if this.CanonicalCacheKey != that.CanonicalCacheKey { return false } + if !this.Deprecation.EqualVT(that.Deprecation) { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1740,6 +1789,9 @@ func (this *AllowedRelation) EqualVT(that *AllowedRelation) bool { if !this.RequiredExpiration.EqualVT(that.RequiredExpiration) { return false } + if !this.Deprecation.EqualVT(that.Deprecation) { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -3366,6 +3418,16 @@ func (m *NamespaceDefinition) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.Deprecation != nil { + size, err := m.Deprecation.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } if m.SourcePosition != nil { size, err := m.SourcePosition.MarshalToSizedBufferVT(dAtA[:i]) if err != nil { @@ -3408,6 +3470,51 @@ func (m *NamespaceDefinition) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Deprecation) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Deprecation) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Deprecation) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Comments) > 0 { + i -= len(m.Comments) + copy(dAtA[i:], m.Comments) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Comments))) + i-- + dAtA[i] = 0x12 + } + if m.DeprecationType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DeprecationType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *Relation) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -3438,6 +3545,16 @@ func (m *Relation) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.Deprecation != nil { + size, err := m.Deprecation.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } if len(m.CanonicalCacheKey) > 0 { i -= len(m.CanonicalCacheKey) copy(dAtA[i:], m.CanonicalCacheKey) @@ -3825,6 +3942,16 @@ func (m *AllowedRelation) MarshalToSizedBufferVT(dAtA []byte) (int, error) { } i -= size } + if m.Deprecation != nil { + size, err := m.Deprecation.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } if m.RequiredExpiration != nil { size, err := m.RequiredExpiration.MarshalToSizedBufferVT(dAtA[:i]) if err != nil { @@ -5374,6 +5501,27 @@ func (m *NamespaceDefinition) SizeVT() (n int) { l = m.SourcePosition.SizeVT() n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.Deprecation != nil { + l = m.Deprecation.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *Deprecation) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DeprecationType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.DeprecationType)) + } + l = len(m.Comments) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -5412,6 +5560,10 @@ func (m *Relation) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.Deprecation != nil { + l = m.Deprecation.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -5555,6 +5707,10 @@ func (m *AllowedRelation) SizeVT() (n int) { l = m.RequiredExpiration.SizeVT() n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.Deprecation != nil { + l = m.Deprecation.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -8206,6 +8362,144 @@ func (m *NamespaceDefinition) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deprecation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Deprecation == nil { + m.Deprecation = &Deprecation{} + } + if err := m.Deprecation.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Deprecation) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Deprecation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Deprecation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DeprecationType", wireType) + } + m.DeprecationType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DeprecationType |= DeprecationType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Comments", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Comments = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -8497,6 +8791,42 @@ func (m *Relation) UnmarshalVT(dAtA []byte) error { } m.CanonicalCacheKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deprecation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Deprecation == nil { + m.Deprecation = &Deprecation{} + } + if err := m.Deprecation.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -9548,6 +9878,42 @@ func (m *AllowedRelation) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deprecation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Deprecation == nil { + m.Deprecation = &Deprecation{} + } + if err := m.Deprecation.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/pkg/schema/definition.go b/pkg/schema/definition.go index a443a11dd..3ac74ced8 100644 --- a/pkg/schema/definition.go +++ b/pkg/schema/definition.go @@ -354,7 +354,7 @@ func (def *Definition) RelationDoesNotAllowCaveatsOrTraitsForSubject(relationNam return false, err } - return !possibleTraits.AllowsCaveats && !possibleTraits.AllowsExpiration, nil + return !possibleTraits.AllowsCaveats && !possibleTraits.AllowsExpiration && !possibleTraits.AllowsDeprecation, nil } // Traits represents the traits that a relation allows for a subject type. @@ -364,6 +364,9 @@ type Traits struct { // AllowsExpiration indicates whether the relation allows expiration on the subject type. AllowsExpiration bool + + // AllowsDeprecation indicates whether the relation allows deprecation on the subject type. + AllowsDeprecation bool } func (t Traits) union(other Traits) Traits { @@ -399,6 +402,9 @@ func (def *Definition) PossibleTraitsForSubject(relationName string, subjectType if allowedRelation.GetRequiredExpiration() != nil { foundTraits.AllowsExpiration = true } + if allowedRelation.GetDeprecation() != nil { + foundTraits.AllowsDeprecation = true + } } } diff --git a/pkg/schema/definition_test.go b/pkg/schema/definition_test.go index 4f3c05660..cb1698e60 100644 --- a/pkg/schema/definition_test.go +++ b/pkg/schema/definition_test.go @@ -706,11 +706,13 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("viewer", "user") require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) _, err = vts.PossibleTraitsForSubject("unknown", "user") require.Error(t, err) @@ -822,11 +824,13 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("viewer", "user") require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) _, err = vts.PossibleTraitsForSubject("unknown", "user") require.Error(t, err) @@ -937,11 +941,13 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("member", "group") require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("other", "user") require.NoError(t, err) @@ -952,11 +958,13 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("three", "group") require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) _, err = vts.PossibleTraitsForSubject("unknown", "user") require.Error(t, err) @@ -1090,16 +1098,19 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("viewer", "user") require.NoError(t, err) require.True(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("onlycaveated", "user") require.NoError(t, err) require.True(t, traits.AllowsCaveats) require.False(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) _, err = vts.PossibleTraitsForSubject("unknown", "user") require.Error(t, err) @@ -1222,11 +1233,158 @@ func TestTypeSystemAccessors(t *testing.T) { require.NoError(t, err) require.False(t, traits.AllowsCaveats) require.True(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) traits, err = vts.PossibleTraitsForSubject("viewer", "user") require.NoError(t, err) require.True(t, traits.AllowsCaveats) require.True(t, traits.AllowsExpiration) + require.False(t, traits.AllowsDeprecation) + + _, err = vts.PossibleTraitsForSubject("unknown", "user") + require.Error(t, err) + + _, err = vts.PossibleTraitsForSubject("editor", "unknown") + require.Error(t, err) + }) + }, + }, + }, + { + "schema with deprecation and expiration", + `use expiration + use deprecation + + definition user {} + definition testuser {} + + caveat somecaveat(somecondition int) { + somecondition == 42 + } + + @deprecated(warn, "some comments here") + definition resource { + relation editor: user with expiration + relation viewer: user | user with somecaveat | @deprecated(error) user with expiration | user with somecaveat and expiration + relation auditor: @deprecated(warn, "migrate tester") testuser with somecaveat and expiration | @deprecated(error, "can't be expired") testuser with expiration + relation user_pool: @deprecated(warn) user:* + }`, + map[string]tsTester{ + "resource": func(t *testing.T, vts *ValidatedDefinition) { + t.Run("IsPermission", func(t *testing.T) { + require.False(t, vts.IsPermission("editor")) + require.False(t, vts.IsPermission("viewer")) + require.False(t, vts.IsPermission("auditor")) + require.False(t, vts.IsPermission("user_pool")) + }) + + t.Run("RelationDoesNotAllowCaveatsOrTraitsForSubject", func(t *testing.T) { + ok, err := vts.RelationDoesNotAllowCaveatsOrTraitsForSubject("editor", "user") + require.NoError(t, err) + require.False(t, ok) + + ok, err = vts.RelationDoesNotAllowCaveatsOrTraitsForSubject("viewer", "user") + require.NoError(t, err) + require.False(t, ok) + + ok, err = vts.RelationDoesNotAllowCaveatsOrTraitsForSubject("auditor", "testuser") + require.NoError(t, err) + require.False(t, ok) + + ok, err = vts.RelationDoesNotAllowCaveatsOrTraitsForSubject("user_pool", "user") + require.NoError(t, err) + require.False(t, ok) + }) + + t.Run("IsAllowedPublicNamespace", func(t *testing.T) { + require.Equal(t, PublicSubjectNotAllowed, noError(vts.IsAllowedPublicNamespace("editor", "user"))) + require.Equal(t, PublicSubjectNotAllowed, noError(vts.IsAllowedPublicNamespace("viewer", "user"))) + require.Equal(t, PublicSubjectNotAllowed, noError(vts.IsAllowedPublicNamespace("auditor", "testuser"))) + require.Equal(t, PublicSubjectAllowed, noError(vts.IsAllowedPublicNamespace("user_pool", "user"))) + }) + + t.Run("IsAllowedDirectNamespace", func(t *testing.T) { + require.Equal(t, AllowedDefinitionValid, noError(vts.IsAllowedDirectNamespace("editor", "user"))) + require.Equal(t, AllowedDefinitionValid, noError(vts.IsAllowedDirectNamespace("viewer", "user"))) + require.Equal(t, AllowedDefinitionValid, noError(vts.IsAllowedDirectNamespace("auditor", "testuser"))) + require.Equal(t, AllowedDefinitionNotValid, noError(vts.IsAllowedDirectNamespace("user_pool", "user"))) + }) + + t.Run("IsAllowedDirectRelation", func(t *testing.T) { + require.Equal(t, DirectRelationValid, noError(vts.IsAllowedDirectRelation("editor", "user", "..."))) + require.Equal(t, DirectRelationValid, noError(vts.IsAllowedDirectRelation("viewer", "user", "..."))) + require.Equal(t, DirectRelationValid, noError(vts.IsAllowedDirectRelation("auditor", "testuser", "..."))) + require.Equal(t, DirectRelationNotValid, noError(vts.IsAllowedDirectRelation("user_pool", "user", "..."))) + }) + + t.Run("HasAllowedRelation", func(t *testing.T) { + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("editor", ns.AllowedRelationWithExpiration("user", "...")))) + require.Equal(t, AllowedRelationNotValid, noError(vts.HasAllowedRelation("editor", ns.AllowedRelation("user", "...")))) + require.Equal(t, AllowedRelationNotValid, noError(vts.HasAllowedRelation("editor", ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))))) + + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("viewer", ns.AllowedRelation("user", "...")))) + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("viewer", ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))))) + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("viewer", ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithExpiration("user", "..."), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, ""))))) + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("viewer", ns.AllowedRelationWithCaveatAndExpiration("user", "...", ns.AllowedCaveat("somecaveat"))))) + + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("auditor", ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithExpiration("testuser", "..."), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "can't be expired"))))) + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("auditor", ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithCaveatAndExpiration("testuser", "...", ns.AllowedCaveat("somecaveat")), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "migrate tester"))))) + + require.Equal(t, AllowedRelationValid, noError(vts.HasAllowedRelation("user_pool", ns.AllowedPublicNamespaceWithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, ""))))) + }) + + t.Run("AllowedDirectRelationsAndWildcards", func(t *testing.T) { + userDirect := ns.AllowedRelation("user", "...") + caveatedUser := ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat")) + expiringUser := ns.AllowedRelationWithExpiration("user", "...") + expiringCaveatedUser := ns.AllowedRelationWithCaveatAndExpiration("user", "...", ns.AllowedCaveat("somecaveat")) + deprecatedUser := ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithExpiration("user", "..."), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "")) + + deprecatedPublicUser := ns.AllowedPublicNamespaceWithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "")) + + deprecatedCaveatedUser := ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithCaveatAndExpiration("testuser", "...", ns.AllowedCaveat("somecaveat")), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "migrate tester")) + deprecatedExpiredUser := ns.AllowedRelationWithDeprecation(ns.AllowedRelationWithExpiration("testuser", "..."), ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "can't be expired")) + + allowed := noError(vts.AllowedDirectRelationsAndWildcards("editor")) + requireSameAllowedRelations(t, allowed, expiringUser) + + allowed = noError(vts.AllowedDirectRelationsAndWildcards("viewer")) + requireSameAllowedRelations(t, allowed, userDirect, caveatedUser, deprecatedUser, expiringCaveatedUser) + + allowed = noError(vts.AllowedDirectRelationsAndWildcards("auditor")) + requireSameAllowedRelations(t, allowed, deprecatedCaveatedUser, deprecatedExpiredUser) + + allowed = noError(vts.AllowedDirectRelationsAndWildcards("user_pool")) + requireSameAllowedRelations(t, allowed, deprecatedPublicUser) + }) + + t.Run("AllowedSubjectRelations", func(t *testing.T) { + userDirect := ns.RelationReference("user", "...") + + allowed := noError(vts.AllowedSubjectRelations("editor")) + requireSameSubjectRelations(t, allowed, userDirect) + + allowed = noError(vts.AllowedSubjectRelations("viewer")) + requireSameSubjectRelations(t, allowed, userDirect) + }) + + t.Run("PossibleTraitsForSubject", func(t *testing.T) { + traits, err := vts.PossibleTraitsForSubject("editor", "user") + require.NoError(t, err) + require.False(t, traits.AllowsCaveats) + require.True(t, traits.AllowsExpiration) + + traits, err = vts.PossibleTraitsForSubject("viewer", "user") + require.NoError(t, err) + require.True(t, traits.AllowsCaveats) + require.True(t, traits.AllowsExpiration) + require.True(t, traits.AllowsDeprecation) + + traits, err = vts.PossibleTraitsForSubject("auditor", "testuser") + require.NoError(t, err) + require.True(t, traits.AllowsCaveats) + require.True(t, traits.AllowsExpiration) + require.True(t, traits.AllowsDeprecation) _, err = vts.PossibleTraitsForSubject("unknown", "user") require.Error(t, err) diff --git a/pkg/schema/typesystem.go b/pkg/schema/typesystem.go index 3d48ec3fe..1f4ee0356 100644 --- a/pkg/schema/typesystem.go +++ b/pkg/schema/typesystem.go @@ -6,8 +6,11 @@ import ( "fmt" "sync" + log "github.com/authzed/spicedb/internal/logging" "github.com/authzed/spicedb/pkg/datastore" core "github.com/authzed/spicedb/pkg/proto/core/v1" + "github.com/authzed/spicedb/pkg/spiceerrors" + "github.com/authzed/spicedb/pkg/tuple" ) type ( @@ -26,6 +29,17 @@ type TypeSystem struct { wildcardCheckCache map[string]*WildcardTypeReference } +// AllowedRelationTraits represents the characteristics of an allowed relation to be used for checking deprecation status. +type AllowedRelationTraits struct { + ResourceNamespace string + ResourceRelation string + SubjectNamespace string + SubjectRelation string + IsWildcard bool + HasCaveat bool + HasExpiration bool +} + // NewTypeSystem builds a TypeSystem object from a resolver, which can look up the definitions. func NewTypeSystem(resolver Resolver) *TypeSystem { return &TypeSystem{ @@ -41,6 +55,171 @@ func (ts *TypeSystem) GetDefinition(ctx context.Context, definition string) (*De return v, err } +// GetDeprecationForObjectType looks up and returns deprecation attached to a object type. +func (ts *TypeSystem) GetDeprecationForObjectType(ctx context.Context, definition string) (*core.Deprecation, bool, error) { + ns, _, err := ts.resolver.LookupDefinition(ctx, definition) + if err != nil { + return nil, false, err + } + + if ns.Deprecation != nil && ns.Deprecation.DeprecationType != core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED { + return ns.Deprecation, true, nil + } + + return nil, false, nil +} + +// GetDeprecationForRelation returns the deprecation attached to a relation. +func (ts *TypeSystem) GetDeprecationForRelation(ctx context.Context, namespace string, relation string) (*core.Deprecation, bool, error) { + ns, _, err := ts.resolver.LookupDefinition(ctx, namespace) + if err != nil { + return nil, false, err + } + + d, err := NewDefinition(ts, ns) + if err != nil { + return nil, false, err + } + + rel := d.relationMap[relation] + + if rel != nil && rel.Deprecation != nil && rel.Deprecation.DeprecationType != core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED { + return rel.Deprecation, true, nil + } + + return &core.Deprecation{}, false, nil +} + +// GetDeprecationForAllowedRelation returns the deprecation attached to AllowedRelation. +func (ts *TypeSystem) GetDeprecationForAllowedRelation(ctx context.Context, traits AllowedRelationTraits) (*core.Deprecation, bool, error) { + def, _, err := ts.getDefinition(ctx, traits.ResourceNamespace) + if err != nil { + return nil, false, err + } + + rel, ok := def.GetRelation(traits.ResourceRelation) + if !ok { + return nil, false, nil + } + + if rel.TypeInformation == nil || rel.TypeInformation.GetAllowedDirectRelations() == nil { + return nil, false, nil + } + + for _, allowed := range rel.TypeInformation.GetAllowedDirectRelations() { + // check namespace match + if allowed.Namespace != traits.SubjectNamespace { + continue + } + + // check for caveat match + if traits.HasCaveat != (allowed.RequiredCaveat != nil) { + continue + } + + // check for expiration match + if traits.HasExpiration != (allowed.RequiredExpiration != nil) { + continue + } + + switch w := allowed.RelationOrWildcard.(type) { + case *core.AllowedRelation_PublicWildcard_: + if !traits.IsWildcard { + continue + } + case *core.AllowedRelation_Relation: + if traits.IsWildcard || w.Relation != traits.SubjectRelation { + continue + } + default: + return nil, false, spiceerrors.MustBugf("unknown type for RelationOrWildcard: %T", allowed.RelationOrWildcard) + } + + if dep := allowed.Deprecation; dep != nil && + dep.DeprecationType != core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED { + return dep, true, nil + } + } + return nil, false, nil +} + +// CheckRelationshipDeprecation performs a check over the deprecated relationship's resource, relation, subject and allowed relation, if any +func (ts *TypeSystem) CheckRelationshipDeprecation(ctx context.Context, relationship tuple.Relationship) error { + // Validate if the resource relation is deprecated + relDep, ok, err := ts.GetDeprecationForRelation(ctx, relationship.Resource.ObjectType, relationship.Resource.Relation) + if err != nil { + return err + } + if ok { + if err := logOrErrorOnDeprecation(relationship.Resource.ObjectType, relationship.Resource.Relation, relDep, "write to deprecated relation", "", false); err != nil { + return err + } + } + + // Validate if the resource object is deprecated + resDep, ok, err := ts.GetDeprecationForObjectType(ctx, relationship.Resource.ObjectType) + if err != nil { + return err + } + if ok { + if err := logOrErrorOnDeprecation(relationship.Resource.ObjectType, "", resDep, "write to deprecated object", "", false); err != nil { + return err + } + } + + // Validate if the subject object is deprecated + subDep, ok, err := ts.GetDeprecationForObjectType(ctx, relationship.Subject.ObjectType) + if err != nil { + return err + } + if ok { + if err := logOrErrorOnDeprecation(relationship.Subject.ObjectType, "", subDep, "write to deprecated object", "", false); err != nil { + return err + } + } + + hasExpiration := false + hasCaveat := false + if relationship.OptionalExpiration != nil { + hasExpiration = true + } + + if relationship.OptionalCaveat != nil { + hasCaveat = true + } + + traits := AllowedRelationTraits{ + ResourceNamespace: relationship.Resource.ObjectType, + ResourceRelation: relationship.Resource.Relation, + SubjectNamespace: relationship.Subject.ObjectType, + SubjectRelation: relationship.Subject.Relation, + IsWildcard: relationship.Subject.ObjectID == tuple.PublicWildcard, + HasCaveat: hasCaveat, + HasExpiration: hasExpiration, + } + // Check deprecation for allowed relation types + dep, ok, err := ts.GetDeprecationForAllowedRelation(ctx, traits) + if err != nil { + return err + } + + if ok { + caveatName := "" + if hasCaveat && relationship.OptionalCaveat != nil { + caveatName = relationship.OptionalCaveat.CaveatName + } + wildCard := relationship.Subject.ObjectID + if wildCard != tuple.PublicWildcard { + wildCard = "" + } + if err := logOrErrorOnDeprecation(relationship.Subject.ObjectType, wildCard, dep, "write to deprecated relation", caveatName, hasExpiration); err != nil { + return err + } + } + + return nil +} + // getDefinition is an internal helper for GetDefinition and GetValidatedDefinition func (ts *TypeSystem) getDefinition(ctx context.Context, definition string) (*Definition, bool, error) { ts.Lock() @@ -191,3 +370,42 @@ func applyExpirationFilter(traits Traits, expirationOption datastore.ExpirationF return traits, nil } } + +func logOrErrorOnDeprecation(objectType, relation string, dep *core.Deprecation, logMessage string, caveatName string, hasExpiration bool) error { + extra := "" + if caveatName != "" { + extra += " with caveat `" + caveatName + "`" + } + if hasExpiration { + if extra != "" { + extra += " and expiration" + } else { + extra += " with expiration" + } + } + + switch dep.DeprecationType { + case core.DeprecationType_DEPRECATED_TYPE_WARNING: + msg := fmt.Sprintf("%s%s", logMessage, extra) + if relation != "" { + log.Warn().Str("resource_type", objectType).Str("relation", relation).Str("comments", dep.Comments).Msg(msg) + } else { + log.Warn().Str("resource_type", objectType).Str("comments", dep.Comments).Msg(msg) + } + + case core.DeprecationType_DEPRECATED_TYPE_ERROR: + switch { + case relation == "*": + return fmt.Errorf("wildcard allowed type %s:*%s is deprecated: %s", objectType, extra, dep.Comments) + case relation == "" && dep.Comments != "": + return fmt.Errorf("resource_type %s%s is deprecated: %s", objectType, extra, dep.Comments) + case relation == "": + return fmt.Errorf("resource_type %s%s has been marked as deprecated", objectType, extra) + case dep.Comments != "": + return fmt.Errorf("relation %s#%s%s is deprecated: %s", objectType, relation, extra, dep.Comments) + default: + return fmt.Errorf("relation %s#%s%s has been marked as deprecated", objectType, relation, extra) + } + } + return nil +} diff --git a/pkg/schema/typesystem_test.go b/pkg/schema/typesystem_test.go index d8f797775..5a400e5c1 100644 --- a/pkg/schema/typesystem_test.go +++ b/pkg/schema/typesystem_test.go @@ -708,3 +708,339 @@ func TestPossibleTraitsForFilter(t *testing.T) { }) } } + +func TestGetDeprecationForRelation(t *testing.T) { + t.Parallel() + + emptyEnv := caveats.NewEnvironmentWithDefaultTypeSet() + + type deprecationTest struct { + name string + element PredefinedElements + testObject string + testRel string + expectedDeprecation *core.Deprecation + expectedError string + } + + tests := []deprecationTest{ + { + "deprecated relation with a caveat in a object reference", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.WithDeprecation( + "document", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some important error here"), + ns.MustRelationWithDeprecation("viewer", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some error"), + nil, + ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("definedcaveat")), + ), + ), + ns.Namespace("user"), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "document", + "viewer", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some error"), + "", + }, + { + "simple relation deprecation", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("editor", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "testerr"), + nil, + ns.AllowedRelation("user", "..."), + ), + ), + ns.Namespace("user"), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "document", + "editor", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "testerr"), + "", + }, + { + "relation deprecation with caveat and expiration in a object reference", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace( + "document", + ns.MustRelationWithDeprecation("editor", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "testerr"), + nil, + ns.AllowedRelationWithCaveatAndExpiration("user", "...", ns.AllowedCaveat("definedcaveat")), + ), + ), + ns.WithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "caveat test dep err")), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "document", + "editor", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "testerr"), + "", + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + require := require.New(t) + ctx := t.Context() + ts := NewTypeSystem(ResolverForPredefinedDefinitions(test.element)) + dep, _, err := ts.GetDeprecationForRelation(ctx, test.testObject, test.testRel) + if test.expectedError != "" { + require.Equal(err.Error(), test.expectedError) + } + require.Equal(dep, test.expectedDeprecation) + }) + } +} + +func TestGetDeprecationForObjectType(t *testing.T) { + t.Parallel() + + emptyEnv := caveats.NewEnvironmentWithDefaultTypeSet() + + type deprecationTest struct { + name string + element PredefinedElements + testObject string + expectedDeprecation *core.Deprecation + expectedError string + } + + tests := []deprecationTest{ + { + "subject deprecation", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.WithDeprecation( + "document", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some important error here"), + ns.MustRelationWithDeprecation("viewer", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some error"), + nil, + ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("definedcaveat")), + ), + ), + ns.Namespace("user"), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "document", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "some important error here"), + "", + }, + { + "object deprecation", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace( + "document", + ns.MustRelation("viewer", + nil, + ns.AllowedRelation("user", "..."), + ), + ), + ns.WithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "other error here")), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "user", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "other error here"), + "", + }, + { + "deprecation in object reference with a caveat", + PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace( + "document", + ns.MustRelation("viewer", + nil, + ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("definedcaveat")), + ), + ), + ns.WithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "caveat test dep err")), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + "user", + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "caveat test dep err"), + "", + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + require := require.New(t) + ctx := t.Context() + ts := NewTypeSystem(ResolverForPredefinedDefinitions(test.element)) + dep, _, err := ts.GetDeprecationForObjectType(ctx, test.testObject) + if test.expectedError != "" { + require.Equal(err.Error(), test.expectedError) + } + require.Equal(dep, test.expectedDeprecation) + }) + } +} + +func TestGetDeprecationForAllowedRelation(t *testing.T) { + t.Parallel() + + type testCase struct { + name string + element PredefinedElements + args AllowedRelationTraits + expectedDeprecation *core.Deprecation + } + + emptyEnv := caveats.NewEnvironmentWithDefaultTypeSet() + tests := []testCase{ + { + name: "allowed relation with caveat and deprecation", + element: PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace("document", + ns.MustRelation("viewer", nil, + ns.AllowedRelationWithDeprecation( + ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("definedcaveat")), + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "caveat warning"), + ), + ), + ), + ns.Namespace("user"), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "1 == 2"), + }, + }, + args: AllowedRelationTraits{ + ResourceNamespace: "document", + ResourceRelation: "viewer", + SubjectNamespace: "user", + SubjectRelation: "...", + IsWildcard: false, + HasCaveat: true, + HasExpiration: false, + }, + + expectedDeprecation: ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "caveat warning"), + }, + { + name: "allowed relation with expiration and deprecation", + element: PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace("document", + ns.MustRelation("editor", nil, + ns.AllowedRelationWithDeprecation( + ns.AllowedRelationWithExpiration("team", "..."), + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "expired deprecation"), + ), + ), + ), + ns.Namespace("team"), + }, + }, + args: AllowedRelationTraits{ + ResourceNamespace: "document", + ResourceRelation: "editor", + SubjectNamespace: "team", + SubjectRelation: "...", + IsWildcard: false, + HasCaveat: false, + HasExpiration: true, + }, + expectedDeprecation: ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "expired deprecation"), + }, + { + name: "allowed relation with caveat, expiration and deprecation", + element: PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace("document", + ns.MustRelation("viewer", nil, + ns.AllowedRelationWithDeprecation( + ns.AllowedRelationWithCaveatAndExpiration( + "user", + "...", + ns.AllowedCaveat("definedcaveat"), + ), + ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "all features"), + ), + ), + ), + ns.Namespace("user"), + }, + Caveats: []*core.CaveatDefinition{ + ns.MustCaveatDefinition(emptyEnv, "definedcaveat", "true"), + }, + }, + args: AllowedRelationTraits{ + ResourceNamespace: "document", + ResourceRelation: "viewer", + SubjectNamespace: "user", + SubjectRelation: "...", + IsWildcard: false, + HasCaveat: true, + HasExpiration: true, + }, + expectedDeprecation: ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_ERROR, "all features"), + }, + { + name: "allowed relation with wildcard", + element: PredefinedElements{ + Definitions: []*core.NamespaceDefinition{ + ns.Namespace("document", + ns.MustRelation("viewer", nil, + ns.AllowedPublicNamespaceWithDeprecation("user", ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "wildcard")), + ), + ), + ns.Namespace("user"), + }, + }, + args: AllowedRelationTraits{ + ResourceNamespace: "document", + ResourceRelation: "viewer", + SubjectNamespace: "user", + SubjectRelation: "*", + IsWildcard: true, + HasCaveat: false, + HasExpiration: false, + }, + expectedDeprecation: ns.Deprecation(core.DeprecationType_DEPRECATED_TYPE_WARNING, "wildcard"), + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + require := require.New(t) + ctx := t.Context() + ts := NewTypeSystem(ResolverForPredefinedDefinitions(tc.element)) + dep, _, err := ts.GetDeprecationForAllowedRelation(ctx, tc.args) + require.NoError(err) + require.Equal(tc.expectedDeprecation, dep) + }) + } +} diff --git a/pkg/schema/typesystem_validation.go b/pkg/schema/typesystem_validation.go index 908e62f93..af0526b55 100644 --- a/pkg/schema/typesystem_validation.go +++ b/pkg/schema/typesystem_validation.go @@ -201,6 +201,8 @@ func (def *Definition) Validate(ctx context.Context) (*ValidatedDefinition, erro } } + // check if any namespace is deprecated + // Allowed relations verification: // 1) that all allowed relations are not this very relation // 2) that they exist within the referenced namespace diff --git a/pkg/schemadsl/compiler/compiler.go b/pkg/schemadsl/compiler/compiler.go index 996a98a3b..56278eefb 100644 --- a/pkg/schemadsl/compiler/compiler.go +++ b/pkg/schemadsl/compiler/compiler.go @@ -76,7 +76,10 @@ func CaveatTypeSet(cts *caveattypes.TypeSet) Option { return func(cfg *config) { cfg.caveatTypeSet = cts } } -const expirationFlag = "expiration" +const ( + expirationFlag = "expiration" + deprecationFlag = "deprecation" +) func DisallowExpirationFlag() Option { return func(cfg *config) { @@ -86,6 +89,14 @@ func DisallowExpirationFlag() Option { } } +func DisallowDeprecationFlag() Option { + return func(cfg *config) { + cfg.allowedFlags = slicez.Filter(cfg.allowedFlags, func(s string) bool { + return s != deprecationFlag + }) + } +} + type Option func(*config) type ObjectPrefixOption func(*config) @@ -96,8 +107,8 @@ func Compile(schema InputSchema, prefix ObjectPrefixOption, opts ...Option) (*Co allowedFlags: make([]string, 0, 1), } - // Enable `expiration` flag by default. - cfg.allowedFlags = append(cfg.allowedFlags, expirationFlag) + // Enable `expiration` and `deprecation` flag by default. + cfg.allowedFlags = append(cfg.allowedFlags, expirationFlag, deprecationFlag) prefix(cfg) // required option diff --git a/pkg/schemadsl/compiler/translator.go b/pkg/schemadsl/compiler/translator.go index b79bd2190..9c52b7f99 100644 --- a/pkg/schemadsl/compiler/translator.go +++ b/pkg/schemadsl/compiler/translator.go @@ -26,6 +26,7 @@ type translationContext struct { allowedFlags []string enabledFlags []string caveatTypeSet *caveattypes.TypeSet + deprecationCtx *core.Deprecation } func (tctx *translationContext) prefixedPath(definitionName string) (string, error) { @@ -74,6 +75,15 @@ func translate(tctx *translationContext, root *dslNode) (*CompiledSchema, error) definition = def caveatDefinitions = append(caveatDefinitions, def) + case dslshape.NodeTypeDeprecation: + deprecation, err := translateDeprecation(tctx, definitionNode) + if err != nil { + return nil, err + } + + tctx.deprecationCtx = deprecation + continue + case dslshape.NodeTypeDefinition: def, err := translateObjectDefinition(tctx, definitionNode) if err != nil { @@ -226,12 +236,24 @@ func translateObjectDefinition(tctx *translationContext, defNode *dslNode) (*cor return nil, defNode.WithSourceErrorf(definitionName, "invalid definition name: %w", err) } + deprecationForNamespace := checkForDeprecation(tctx) + relationsAndPermissions := []*core.Relation{} for _, relationOrPermissionNode := range defNode.GetChildren() { if relationOrPermissionNode.GetType() == dslshape.NodeTypeComment { continue } + if relationOrPermissionNode.GetType() == dslshape.NodeTypeDeprecation && slices.Contains(tctx.enabledFlags, "deprecation") && slices.Contains(tctx.allowedFlags, "deprecation") { + deprecation, err := translateDeprecation(tctx, relationOrPermissionNode) + if err != nil { + return nil, err + } + + tctx.deprecationCtx = deprecation + continue + } + relationOrPermission, err := translateRelationOrPermission(tctx, relationOrPermissionNode) if err != nil { return nil, err @@ -246,7 +268,12 @@ func translateObjectDefinition(tctx *translationContext, defNode *dslNode) (*cor } if len(relationsAndPermissions) == 0 { - ns := namespace.Namespace(nspath) + var ns *core.NamespaceDefinition + if checkIfDeprecationEnabled(tctx, deprecationForNamespace) { + ns = namespace.WithDeprecation(nspath, deprecationForNamespace) + } else { + ns = namespace.Namespace(nspath) + } ns.Metadata = addComments(ns.Metadata, defNode) ns.SourcePosition = getSourcePosition(defNode, tctx.mapper) @@ -259,7 +286,12 @@ func translateObjectDefinition(tctx *translationContext, defNode *dslNode) (*cor return ns, nil } - ns := namespace.Namespace(nspath, relationsAndPermissions...) + var ns *core.NamespaceDefinition + if checkIfDeprecationEnabled(tctx, deprecationForNamespace) { + ns = namespace.WithDeprecation(nspath, deprecationForNamespace, relationsAndPermissions...) + } else { + ns = namespace.Namespace(nspath, relationsAndPermissions...) + } ns.Metadata = addComments(ns.Metadata, defNode) ns.SourcePosition = getSourcePosition(defNode, tctx.mapper) @@ -272,6 +304,16 @@ func translateObjectDefinition(tctx *translationContext, defNode *dslNode) (*cor return ns, nil } +func checkForDeprecation(tctx *translationContext) *core.Deprecation { + deprecation := &core.Deprecation{} + if tctx.deprecationCtx != nil { + deprecation = tctx.deprecationCtx + tctx.deprecationCtx = nil // Reset for next definition. + } + + return deprecation +} + func getSourcePosition(dslNode *dslNode, mapper input.PositionMapper) *core.SourcePosition { if !dslNode.Has(dslshape.NodePredicateStartRune) { return nil @@ -350,6 +392,8 @@ func translateRelation(tctx *translationContext, relationNode *dslNode) (*core.R return nil, relationNode.Errorf("invalid relation name: %w", err) } + deprecationForRelation := checkForDeprecation(tctx) + allowedDirectTypes := []*core.AllowedRelation{} for _, typeRef := range relationNode.List(dslshape.NodeRelationPredicateAllowedTypes) { allowedRelations, err := translateAllowedRelations(tctx, typeRef) @@ -360,9 +404,14 @@ func translateRelation(tctx *translationContext, relationNode *dslNode) (*core.R allowedDirectTypes = append(allowedDirectTypes, allowedRelations...) } - relation, err := namespace.Relation(relationName, nil, allowedDirectTypes...) - if err != nil { - return nil, err + var relation *core.Relation + if slices.Contains(tctx.enabledFlags, "deprecation") && slices.Contains(tctx.allowedFlags, "deprecation") && (deprecationForRelation != &core.Deprecation{}) { + relation = namespace.MustRelationWithDeprecation(relationName, deprecationForRelation, nil, allowedDirectTypes...) + } else { + relation, err = namespace.Relation(relationName, nil, allowedDirectTypes...) + if err != nil { + return nil, err + } } if !tctx.skipValidate { @@ -374,6 +423,29 @@ func translateRelation(tctx *translationContext, relationNode *dslNode) (*core.R return relation, nil } +// translateDeprecation parses a deprecation directive from a DSL node. +func translateDeprecation(tctx *translationContext, depNode *dslNode) (*core.Deprecation, error) { + if !slices.Contains(tctx.enabledFlags, "deprecation") || !slices.Contains(tctx.allowedFlags, "deprecation") { + return nil, depNode.Errorf("deprecation feature not enabled; add `use deprecation` at the top of the schema and make sure it is enabled") + } + deprecationTypeStr, err := depNode.GetString(dslshape.NodeDeprecatedType) + if err != nil { + return nil, depNode.Errorf("invalid deprecation type: %w", err) + } + + comments, err := depNode.GetString(dslshape.NodeDeprecatedComments) + if err != nil { + comments = "" + } + + deprecation := namespace.Deprecation( + parseDeprecationType(deprecationTypeStr), + comments, + ) + + return deprecation, nil +} + func translatePermission(tctx *translationContext, permissionNode *dslNode) (*core.Relation, error) { permissionName, err := permissionNode.GetString(dslshape.NodePredicateName) if err != nil { @@ -684,6 +756,15 @@ func translateSpecificTypeReference(tctx *translationContext, typeRefNode *dslNo return nil, typeRefNode.Errorf("invalid expiration: %w", err) } + // Add the deprecation, if any. + if depChild, err := typeRefNode.Lookup(dslshape.NodeTypeReferenceDeprecatedType); err == nil && depChild.GetType() == dslshape.NodeTypeDeprecation { + dep, err := translateDeprecation(tctx, depChild) + if err != nil { + return nil, err + } + ref.Deprecation = dep + } + if !tctx.skipValidate { if err := ref.Validate(); err != nil { return nil, typeRefNode.Errorf("invalid type relation: %w", err) @@ -752,3 +833,20 @@ func translateUseFlag(tctx *translationContext, useFlagNode *dslNode) error { tctx.enabledFlags = append(tctx.enabledFlags, flagName) return nil } + +// helper function to convert a string to a deprecation type +func parseDeprecationType(s string) core.DeprecationType { + switch strings.ToLower(s) { + case "warn": + return core.DeprecationType_DEPRECATED_TYPE_WARNING + case "error": + return core.DeprecationType_DEPRECATED_TYPE_ERROR + default: + return core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED + } +} + +// helper function to check whether deprecation is enabled in schema +func checkIfDeprecationEnabled(tctx *translationContext, dep *core.Deprecation) bool { + return slices.Contains(tctx.enabledFlags, "deprecation") && slices.Contains(tctx.allowedFlags, "deprecation") && (dep != &core.Deprecation{}) +} diff --git a/pkg/schemadsl/dslshape/dslshape.go b/pkg/schemadsl/dslshape/dslshape.go index e9b8bd4f7..f415bf02e 100644 --- a/pkg/schemadsl/dslshape/dslshape.go +++ b/pkg/schemadsl/dslshape/dslshape.go @@ -26,6 +26,8 @@ const ( NodeTypeSpecificTypeReference // A reference to a specific type. NodeTypeCaveatReference // A caveat reference under a type. NodeTypeTraitReference // A trait reference under a typr. + NodeTypeDeprecation // A deprecated relation. + NodeTypeDeprecationOptions // Options for a deprecation. NodeTypeUnionExpression NodeTypeIntersectExpression @@ -148,6 +150,12 @@ const ( // A type under a type reference. NodeTypeReferencePredicateType = "type-ref-type" + // + // NodeTypeTypeReference + // + // The type reference for the deprecated type. + NodeTypeReferenceDeprecatedType = "reference-deprecated-type" + // // NodeTypeSpecificTypeReference // @@ -217,4 +225,16 @@ const ( // NodeExpressionPredicateLeftExpr = "left-expr" NodeExpressionPredicateRightExpr = "right-expr" + + // + // NodeTypeDeprecatedOptions + // + // The type of deprecation + NodeDeprecatedType = "deprecation-type" + + // + // NodeTypeDeprecatedOptions + // + // The value of optional comments for the deprecation. + NodeDeprecatedComments = "deprecation-comments" ) diff --git a/pkg/schemadsl/dslshape/zz_generated.nodetype_string.go b/pkg/schemadsl/dslshape/zz_generated.nodetype_string.go index 50fb83714..4764fdf77 100644 --- a/pkg/schemadsl/dslshape/zz_generated.nodetype_string.go +++ b/pkg/schemadsl/dslshape/zz_generated.nodetype_string.go @@ -23,18 +23,20 @@ func _() { _ = x[NodeTypeSpecificTypeReference-12] _ = x[NodeTypeCaveatReference-13] _ = x[NodeTypeTraitReference-14] - _ = x[NodeTypeUnionExpression-15] - _ = x[NodeTypeIntersectExpression-16] - _ = x[NodeTypeExclusionExpression-17] - _ = x[NodeTypeArrowExpression-18] - _ = x[NodeTypeIdentifier-19] - _ = x[NodeTypeNilExpression-20] - _ = x[NodeTypeCaveatTypeReference-21] + _ = x[NodeTypeDeprecation-15] + _ = x[NodeTypeDeprecationOptions-16] + _ = x[NodeTypeUnionExpression-17] + _ = x[NodeTypeIntersectExpression-18] + _ = x[NodeTypeExclusionExpression-19] + _ = x[NodeTypeArrowExpression-20] + _ = x[NodeTypeIdentifier-21] + _ = x[NodeTypeNilExpression-22] + _ = x[NodeTypeCaveatTypeReference-23] } -const _NodeType_name = "NodeTypeErrorNodeTypeFileNodeTypeCommentNodeTypeUseFlagNodeTypeDefinitionNodeTypeCaveatDefinitionNodeTypeCaveatParameterNodeTypeCaveatExpressionNodeTypeRelationNodeTypePermissionNodeTypeTypeAnnotationNodeTypeTypeReferenceNodeTypeSpecificTypeReferenceNodeTypeCaveatReferenceNodeTypeTraitReferenceNodeTypeUnionExpressionNodeTypeIntersectExpressionNodeTypeExclusionExpressionNodeTypeArrowExpressionNodeTypeIdentifierNodeTypeNilExpressionNodeTypeCaveatTypeReference" +const _NodeType_name = "NodeTypeErrorNodeTypeFileNodeTypeCommentNodeTypeUseFlagNodeTypeDefinitionNodeTypeCaveatDefinitionNodeTypeCaveatParameterNodeTypeCaveatExpressionNodeTypeRelationNodeTypePermissionNodeTypeTypeAnnotationNodeTypeTypeReferenceNodeTypeSpecificTypeReferenceNodeTypeCaveatReferenceNodeTypeTraitReferenceNodeTypeDeprecationNodeTypeDeprecationOptionsNodeTypeUnionExpressionNodeTypeIntersectExpressionNodeTypeExclusionExpressionNodeTypeArrowExpressionNodeTypeIdentifierNodeTypeNilExpressionNodeTypeCaveatTypeReference" -var _NodeType_index = [...]uint16{0, 13, 25, 40, 55, 73, 97, 120, 144, 160, 178, 200, 221, 250, 273, 295, 318, 345, 372, 395, 413, 434, 461} +var _NodeType_index = [...]uint16{0, 13, 25, 40, 55, 73, 97, 120, 144, 160, 178, 200, 221, 250, 273, 295, 314, 340, 363, 390, 417, 440, 458, 479, 506} func (i NodeType) String() string { idx := int(i) - 0 diff --git a/pkg/schemadsl/generator/generator.go b/pkg/schemadsl/generator/generator.go index 995b3ecda..a3501bd4a 100644 --- a/pkg/schemadsl/generator/generator.go +++ b/pkg/schemadsl/generator/generator.go @@ -188,6 +188,18 @@ func (sg *sourceGenerator) emitCaveat(caveat *core.CaveatDefinition) error { func (sg *sourceGenerator) emitNamespace(namespace *core.NamespaceDefinition) error { sg.emitComments(namespace.Metadata) + if isDeprecated(namespace.Deprecation) { + sg.flags.Add("deprecation") + sg.append("@deprecated(") + sg.append(deprecationTypeString(namespace.Deprecation.DeprecationType)) + if namespace.Deprecation.Comments != "" { + sg.append(", \"") + sg.append(namespace.Deprecation.Comments) + sg.append("\"") + } + sg.append(")") + sg.ensureBlankLineOrNewScope() + } sg.append("definition ") sg.append(namespace.Name) @@ -202,6 +214,18 @@ func (sg *sourceGenerator) emitNamespace(namespace *core.NamespaceDefinition) er sg.markNewScope() for _, relation := range namespace.Relation { + if isDeprecated(relation.Deprecation) { + sg.flags.Add("deprecation") + sg.append("@deprecated(") + sg.append(deprecationTypeString(relation.Deprecation.DeprecationType)) + if relation.Deprecation.Comments != "" { + sg.append(", \"") + sg.append(relation.Deprecation.Comments) + sg.append("\"") + } + sg.append(")") + sg.ensureBlankLineOrNewScope() + } err := sg.emitRelation(relation) if err != nil { return err @@ -255,6 +279,19 @@ func (sg *sourceGenerator) emitRelation(relation *core.Relation) error { } func (sg *sourceGenerator) emitAllowedRelation(allowedRelation *core.AllowedRelation) { + if isDeprecated(allowedRelation.GetDeprecation()) { + sg.flags.Add("deprecation") + sg.append("@deprecated(") + sg.append(deprecationTypeString(allowedRelation.GetDeprecation().DeprecationType)) + + if allowedRelation.GetDeprecation().Comments != "" { + sg.append(", \"") + sg.append(allowedRelation.GetDeprecation().Comments) + sg.append("\"") + } + sg.append(") ") + } + sg.append(allowedRelation.Namespace) if allowedRelation.GetRelation() != "" && allowedRelation.GetRelation() != Ellipsis { sg.append("#") @@ -428,3 +465,17 @@ func (sg *sourceGenerator) appendComment(comment string) { sg.appendLine() } } + +func isDeprecated(dep *core.Deprecation) bool { + return dep != nil && dep.DeprecationType != core.DeprecationType_DEPRECATED_TYPE_UNSPECIFIED +} + +func deprecationTypeString(depType core.DeprecationType) string { + switch depType { + case core.DeprecationType_DEPRECATED_TYPE_ERROR: + return "error" + case core.DeprecationType_DEPRECATED_TYPE_WARNING: + return "warn" + } + return "" +} diff --git a/pkg/schemadsl/generator/generator_test.go b/pkg/schemadsl/generator/generator_test.go index d5e43cdc6..7ea0b99fc 100644 --- a/pkg/schemadsl/generator/generator_test.go +++ b/pkg/schemadsl/generator/generator_test.go @@ -395,6 +395,63 @@ definition document { relation viewer: user }`, }, + { + "deprecation test", + `use deprecation + + definition user{} + + @deprecated(error, "comments") + definition document { + @deprecated(warn, "comment goes here") + relation viewer: user + + @deprecated(error) + relation editor: user + }`, + `use deprecation + +definition user {} + +@deprecated(error, "comments") +definition document { + @deprecated(warn, "comment goes here") + relation viewer: user + @deprecated(error) + relation editor: user +}`, + }, + { + "allowed relations with deprecation", + `use deprecation + definition testuser{} + definition user{} + definition document { + relation viewer: testuser | @deprecated(warn, "comment") user + relation editor: testuser + }`, + `use deprecation + +definition testuser {} + +definition user {} + +definition document { + relation viewer: testuser | @deprecated(warn, "comment") user + relation editor: testuser +}`, + }, + { + "unused deprecation flag", + `use deprecation + + definition document{ + relation viewer: user + }`, + `definition document { + relation viewer: user +}`, + }, } for _, test := range tests { diff --git a/pkg/schemadsl/lexer/flaggablelexer_test.go b/pkg/schemadsl/lexer/flaggablelexer_test.go index 892c62ac3..75d0b3cb0 100644 --- a/pkg/schemadsl/lexer/flaggablelexer_test.go +++ b/pkg/schemadsl/lexer/flaggablelexer_test.go @@ -48,6 +48,12 @@ var flaggableLexerTests = []lexerTest{ {TokenTypeIdentifier, 0, "expiration", ""}, tEOF, }}, + {"use deprecation", "use deprecation", []Lexeme{ + {TokenTypeIdentifier, 0, "use", ""}, + {TokenTypeWhitespace, 0, " ", ""}, + {TokenTypeKeyword, 0, "deprecation", ""}, + tEOF, + }}, } func TestFlaggableLexer(t *testing.T) { diff --git a/pkg/schemadsl/lexer/flags.go b/pkg/schemadsl/lexer/flags.go index 184e7523a..c006d9714 100644 --- a/pkg/schemadsl/lexer/flags.go +++ b/pkg/schemadsl/lexer/flags.go @@ -13,6 +13,10 @@ const ( // FlagTypeChecking indicates that `typechecking` is supported as a first-class // feature in the schema. FlagTypeChecking = "typechecking" + + // FlagDeprecation indicates that `deprecation` is supported as a first-class + // feature in the schema. + FlagDeprecation = "deprecation" ) var AllUseFlags []string @@ -48,6 +52,14 @@ var Flags = map[string]transformer{ return lexeme, true } + return lexeme, false + }, + FlagDeprecation: func(lexeme Lexeme) (Lexeme, bool) { + if lexeme.Kind == TokenTypeIdentifier && lexeme.Value == "deprecation" { + lexeme.Kind = TokenTypeKeyword + return lexeme, true + } + return lexeme, false }, } diff --git a/pkg/schemadsl/lexer/lex_def.go b/pkg/schemadsl/lexer/lex_def.go index dee0df271..d6bdbc250 100644 --- a/pkg/schemadsl/lexer/lex_def.go +++ b/pkg/schemadsl/lexer/lex_def.go @@ -52,6 +52,7 @@ const ( TokenTypeStar // * // Additional tokens for CEL: https://github.com/google/cel-spec/blob/master/doc/langdef.md#syntax + TokenTypeAt // @ TokenTypeQuestionMark // ? TokenTypeConditionalOr // || TokenTypeConditionalAnd // && @@ -78,6 +79,7 @@ var keywords = map[string]struct{}{ "permission": {}, "nil": {}, "with": {}, + "deprecated": {}, } // IsKeyword returns whether the specified input string is a reserved keyword. @@ -161,6 +163,9 @@ Loop: l.emit(TokenTypeLessThan) } + case r == '@': + l.emit(TokenTypeAt) + case r == '>': if l.acceptString("=") { l.emit(TokenTypeGreaterThanOrEqual) diff --git a/pkg/schemadsl/lexer/lex_test.go b/pkg/schemadsl/lexer/lex_test.go index 0a80d50fd..740e296a3 100644 --- a/pkg/schemadsl/lexer/lex_test.go +++ b/pkg/schemadsl/lexer/lex_test.go @@ -45,6 +45,7 @@ var lexerTests = []lexerTest{ {"hash", "#", []Lexeme{{TokenTypeHash, 0, "#", ""}, tEOF}}, {"ellipsis", "...", []Lexeme{{TokenTypeEllipsis, 0, "...", ""}, tEOF}}, + {"token @", "@", []Lexeme{{TokenTypeAt, 0, "@", ""}, tEOF}}, {"relation reference", "foo#...", []Lexeme{ {TokenTypeIdentifier, 0, "foo", ""}, @@ -257,6 +258,21 @@ var lexerTests = []lexerTest{ {TokenTypeRightParen, 0, ")", ""}, tEOF, }}, + + {"deprecation test with keyword", "@deprecated", []Lexeme{ + {TokenTypeAt, 0, "@", ""}, + {TokenTypeKeyword, 0, "deprecated", ""}, + tEOF, + }}, + + {"deprecation test with keyword and identifier", "@deprecated(something)", []Lexeme{ + {TokenTypeAt, 0, "@", ""}, + {TokenTypeKeyword, 0, "deprecated", ""}, + {TokenTypeLeftParen, 0, "(", ""}, + {TokenTypeIdentifier, 0, "something", ""}, + {TokenTypeRightParen, 0, ")", ""}, + tEOF, + }}, } func TestLexer(t *testing.T) { diff --git a/pkg/schemadsl/lexer/tokentype_string.go b/pkg/schemadsl/lexer/tokentype_string.go index 73c993846..a8c46ca2a 100644 --- a/pkg/schemadsl/lexer/tokentype_string.go +++ b/pkg/schemadsl/lexer/tokentype_string.go @@ -34,27 +34,28 @@ func _() { _ = x[TokenTypeHash-23] _ = x[TokenTypeEllipsis-24] _ = x[TokenTypeStar-25] - _ = x[TokenTypeQuestionMark-26] - _ = x[TokenTypeConditionalOr-27] - _ = x[TokenTypeConditionalAnd-28] - _ = x[TokenTypeExclamationPoint-29] - _ = x[TokenTypeLeftBracket-30] - _ = x[TokenTypeRightBracket-31] - _ = x[TokenTypePeriod-32] - _ = x[TokenTypeComma-33] - _ = x[TokenTypePercent-34] - _ = x[TokenTypeLessThan-35] - _ = x[TokenTypeGreaterThan-36] - _ = x[TokenTypeLessThanOrEqual-37] - _ = x[TokenTypeGreaterThanOrEqual-38] - _ = x[TokenTypeEqualEqual-39] - _ = x[TokenTypeNotEqual-40] - _ = x[TokenTypeString-41] + _ = x[TokenTypeAt-26] + _ = x[TokenTypeQuestionMark-27] + _ = x[TokenTypeConditionalOr-28] + _ = x[TokenTypeConditionalAnd-29] + _ = x[TokenTypeExclamationPoint-30] + _ = x[TokenTypeLeftBracket-31] + _ = x[TokenTypeRightBracket-32] + _ = x[TokenTypePeriod-33] + _ = x[TokenTypeComma-34] + _ = x[TokenTypePercent-35] + _ = x[TokenTypeLessThan-36] + _ = x[TokenTypeGreaterThan-37] + _ = x[TokenTypeLessThanOrEqual-38] + _ = x[TokenTypeGreaterThanOrEqual-39] + _ = x[TokenTypeEqualEqual-40] + _ = x[TokenTypeNotEqual-41] + _ = x[TokenTypeString-42] } -const _TokenType_name = "TokenTypeErrorTokenTypeSyntheticSemicolonTokenTypeEOFTokenTypeWhitespaceTokenTypeSinglelineCommentTokenTypeMultilineCommentTokenTypeNewlineTokenTypeKeywordTokenTypeIdentifierTokenTypeNumberTokenTypeLeftBraceTokenTypeRightBraceTokenTypeLeftParenTokenTypeRightParenTokenTypePipeTokenTypePlusTokenTypeMinusTokenTypeAndTokenTypeDivTokenTypeEqualsTokenTypeColonTokenTypeSemicolonTokenTypeRightArrowTokenTypeHashTokenTypeEllipsisTokenTypeStarTokenTypeQuestionMarkTokenTypeConditionalOrTokenTypeConditionalAndTokenTypeExclamationPointTokenTypeLeftBracketTokenTypeRightBracketTokenTypePeriodTokenTypeCommaTokenTypePercentTokenTypeLessThanTokenTypeGreaterThanTokenTypeLessThanOrEqualTokenTypeGreaterThanOrEqualTokenTypeEqualEqualTokenTypeNotEqualTokenTypeString" +const _TokenType_name = "TokenTypeErrorTokenTypeSyntheticSemicolonTokenTypeEOFTokenTypeWhitespaceTokenTypeSinglelineCommentTokenTypeMultilineCommentTokenTypeNewlineTokenTypeKeywordTokenTypeIdentifierTokenTypeNumberTokenTypeLeftBraceTokenTypeRightBraceTokenTypeLeftParenTokenTypeRightParenTokenTypePipeTokenTypePlusTokenTypeMinusTokenTypeAndTokenTypeDivTokenTypeEqualsTokenTypeColonTokenTypeSemicolonTokenTypeRightArrowTokenTypeHashTokenTypeEllipsisTokenTypeStarTokenTypeAtTokenTypeQuestionMarkTokenTypeConditionalOrTokenTypeConditionalAndTokenTypeExclamationPointTokenTypeLeftBracketTokenTypeRightBracketTokenTypePeriodTokenTypeCommaTokenTypePercentTokenTypeLessThanTokenTypeGreaterThanTokenTypeLessThanOrEqualTokenTypeGreaterThanOrEqualTokenTypeEqualEqualTokenTypeNotEqualTokenTypeString" -var _TokenType_index = [...]uint16{0, 14, 41, 53, 72, 98, 123, 139, 155, 174, 189, 207, 226, 244, 263, 276, 289, 303, 315, 327, 342, 356, 374, 393, 406, 423, 436, 457, 479, 502, 527, 547, 568, 583, 597, 613, 630, 650, 674, 701, 720, 737, 752} +var _TokenType_index = [...]uint16{0, 14, 41, 53, 72, 98, 123, 139, 155, 174, 189, 207, 226, 244, 263, 276, 289, 303, 315, 327, 342, 356, 374, 393, 406, 423, 436, 447, 468, 490, 513, 538, 558, 579, 594, 608, 624, 641, 661, 685, 712, 731, 748, 763} func (i TokenType) String() string { idx := int(i) - 0 diff --git a/pkg/schemadsl/parser/parser.go b/pkg/schemadsl/parser/parser.go index 507188c33..4d7973a02 100644 --- a/pkg/schemadsl/parser/parser.go +++ b/pkg/schemadsl/parser/parser.go @@ -69,6 +69,9 @@ Loop: hasSeenDefinition = true rootNode.Connect(dslshape.NodePredicateChild, p.consumeCaveat()) + case p.isToken(lexer.TokenTypeAt): + rootNode.Connect(dslshape.NodePredicateChild, p.consumeDeprecation()) + default: p.emitErrorf("Unexpected token at root level: %v", p.currentToken.Kind) break Loop @@ -313,6 +316,9 @@ func (p *sourceParser) consumeDefinition() AstNode { case p.isKeyword("permission"): defNode.Connect(dslshape.NodePredicateChild, p.consumePermission()) + + case p.isToken(lexer.TokenTypeAt): + defNode.Connect(dslshape.NodePredicateChild, p.consumeDeprecation()) } ok := p.consumeStatementTerminator() @@ -367,6 +373,58 @@ func (p *sourceParser) consumeTypeReference() AstNode { return refNode } +// consumeDeprecation consumes a deprecation statement +// ```@deprecated(type, relation)``` +func (p *sourceParser) consumeDeprecation() AstNode { + depNode := p.startNode(dslshape.NodeTypeDeprecation) + defer p.mustFinishNode() + + p.consume(lexer.TokenTypeAt) + + ok := p.consumeKeyword("deprecated") + if !ok { + return depNode + } + + _, ok = p.tryConsume(lexer.TokenTypeLeftParen) + if !ok { + p.emitErrorf("Expected '(' after 'deprecated' keyword") + return depNode + } + + // deprecation type + deprecationType, ok := p.tryConsume(lexer.TokenTypeIdentifier) + if !ok { + p.emitErrorf("Expected identifier for deprecation type") + return depNode + } + depNode.MustDecorate(dslshape.NodeDeprecatedType, deprecationType.Value) + + // return early if no comments + if p.isToken(lexer.TokenTypeRightParen) { + p.consume(lexer.TokenTypeRightParen) + return depNode + } + + _, ok = p.tryConsume(lexer.TokenTypeComma) + if !ok { + p.emitErrorf("Expected ',' after deprecation type") + return depNode + } + + // A comment + if p.isToken(lexer.TokenTypeString) { + commentTok, _ := p.tryConsume(lexer.TokenTypeString) + comment := strings.Trim(commentTok.Value, `"`) + depNode.MustDecorate(dslshape.NodeDeprecatedComments, comment) + + p.consume(lexer.TokenTypeRightParen) + return depNode + } + + return depNode +} + // tryConsumeWithCaveat tries to consume a caveat `with` expression. func (p *sourceParser) tryConsumeWithCaveat() (AstNode, bool) { caveatNode := p.startNode(dslshape.NodeTypeCaveatReference) @@ -430,6 +488,10 @@ func (p *sourceParser) consumeExpirationTrait() AstNode { func (p *sourceParser) consumeSpecificTypeWithoutFinish() AstNode { specificNode := p.startNode(dslshape.NodeTypeSpecificTypeReference) + if p.isToken(lexer.TokenTypeAt) { + specificNode.Connect(dslshape.NodeTypeReferenceDeprecatedType, p.consumeDeprecation()) + } + typeName, ok := p.consumeTypePath() if !ok { return specificNode diff --git a/pkg/schemadsl/parser/parser_test.go b/pkg/schemadsl/parser/parser_test.go index cc06045c8..dbc708679 100644 --- a/pkg/schemadsl/parser/parser_test.go +++ b/pkg/schemadsl/parser/parser_test.go @@ -142,6 +142,10 @@ func TestParser(t *testing.T) { {"permission type annotation double colon test", "permission_type_annotation_double_colon"}, {"permission type annotation newline after colon test", "permission_type_annotation_newline_after_colon"}, {"permission type annotation just pipe test", "permission_type_annotation_just_pipe"}, + {"deprecation outside definition test", "deprecation_outside_definition"}, + {"deprecation inside definition test", "deprecation_inside_definition"}, + {"invalid deprecation use", "invalid_deprecation"}, + {"deprecated type reference test", "deprecated_type_ref"}, } for _, test := range parserTests { diff --git a/pkg/schemadsl/parser/tests/deprecated_type_ref.zed b/pkg/schemadsl/parser/tests/deprecated_type_ref.zed new file mode 100644 index 000000000..886918828 --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecated_type_ref.zed @@ -0,0 +1,10 @@ +definition user {} + +definition testuser {} + +definition platform { + relation viewer: user | testuser + relation editor: testuser | @deprecated(error, "some comments") testuser + + relation auditor: user | @deprecated(warn, "comments here") testuser:* +} \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/deprecated_type_ref.zed.expected b/pkg/schemadsl/parser/tests/deprecated_type_ref.zed.expected new file mode 100644 index 000000000..aab7eafc8 --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecated_type_ref.zed.expected @@ -0,0 +1,99 @@ +NodeTypeFile + end-rune = 256 + input-source = deprecated type reference test + start-rune = 0 + child-node => + NodeTypeDefinition + definition-name = user + end-rune = 17 + input-source = deprecated type reference test + start-rune = 0 + NodeTypeDefinition + definition-name = testuser + end-rune = 41 + input-source = deprecated type reference test + start-rune = 20 + NodeTypeDefinition + definition-name = platform + end-rune = 256 + input-source = deprecated type reference test + start-rune = 44 + child-node => + NodeTypeRelation + end-rune = 101 + input-source = deprecated type reference test + relation-name = viewer + start-rune = 70 + allowed-types => + NodeTypeTypeReference + end-rune = 101 + input-source = deprecated type reference test + start-rune = 87 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 90 + input-source = deprecated type reference test + start-rune = 87 + type-name = user + NodeTypeSpecificTypeReference + end-rune = 101 + input-source = deprecated type reference test + start-rune = 94 + type-name = testuser + NodeTypeRelation + end-rune = 178 + input-source = deprecated type reference test + relation-name = editor + start-rune = 107 + allowed-types => + NodeTypeTypeReference + end-rune = 178 + input-source = deprecated type reference test + start-rune = 124 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 131 + input-source = deprecated type reference test + start-rune = 124 + type-name = testuser + NodeTypeSpecificTypeReference + end-rune = 178 + input-source = deprecated type reference test + start-rune = 135 + type-name = testuser + reference-deprecated-type => + NodeTypeDeprecation + deprecation-comments = some comments + deprecation-type = error + end-rune = 169 + input-source = deprecated type reference test + start-rune = 135 + NodeTypeRelation + end-rune = 254 + input-source = deprecated type reference test + relation-name = auditor + start-rune = 185 + allowed-types => + NodeTypeTypeReference + end-rune = 254 + input-source = deprecated type reference test + start-rune = 203 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 206 + input-source = deprecated type reference test + start-rune = 203 + type-name = user + NodeTypeSpecificTypeReference + end-rune = 254 + input-source = deprecated type reference test + start-rune = 210 + type-name = testuser + type-wildcard = true + reference-deprecated-type => + NodeTypeDeprecation + deprecation-comments = comments here + deprecation-type = warn + end-rune = 243 + input-source = deprecated type reference test + start-rune = 210 \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed b/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed new file mode 100644 index 000000000..9b30f01f1 --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed @@ -0,0 +1,14 @@ +use deprecation + +definition deprecated_relation { + + @deprecated(warn, "comments") + relation writer: user + + + @deprecated(error) + relation reader: user +} + +definition user {} +definition testuser {} \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed.expected b/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed.expected new file mode 100644 index 000000000..7eacbcdbb --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecation_inside_definition.zed.expected @@ -0,0 +1,69 @@ +NodeTypeFile + end-rune = 205 + input-source = deprecation inside definition test + start-rune = 0 + child-node => + NodeTypeUseFlag + end-rune = 14 + input-source = deprecation inside definition test + start-rune = 0 + use-flag-name = deprecation + NodeTypeDefinition + definition-name = deprecated_relation + end-rune = 162 + input-source = deprecation inside definition test + start-rune = 17 + child-node => + NodeTypeDeprecation + deprecation-comments = comments + deprecation-type = warn + end-rune = 83 + input-source = deprecation inside definition test + start-rune = 55 + NodeTypeRelation + end-rune = 109 + input-source = deprecation inside definition test + relation-name = writer + start-rune = 89 + allowed-types => + NodeTypeTypeReference + end-rune = 109 + input-source = deprecation inside definition test + start-rune = 106 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 109 + input-source = deprecation inside definition test + start-rune = 106 + type-name = user + NodeTypeDeprecation + deprecation-type = error + end-rune = 134 + input-source = deprecation inside definition test + start-rune = 117 + NodeTypeRelation + end-rune = 160 + input-source = deprecation inside definition test + relation-name = reader + start-rune = 140 + allowed-types => + NodeTypeTypeReference + end-rune = 160 + input-source = deprecation inside definition test + start-rune = 157 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 160 + input-source = deprecation inside definition test + start-rune = 157 + type-name = user + NodeTypeDefinition + definition-name = user + end-rune = 182 + input-source = deprecation inside definition test + start-rune = 165 + NodeTypeDefinition + definition-name = testuser + end-rune = 205 + input-source = deprecation inside definition test + start-rune = 184 \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed b/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed new file mode 100644 index 000000000..188f1655c --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed @@ -0,0 +1,17 @@ +use deprecation + +@deprecated(warn, "user is deprecated") +definition user {} + +@deprecated(warn, "comments here") +definition testuser {} + +@deprecated(error, "test") +definition deprecated_relation { + + relation writer: user + + + @deprecated(error, "test error") + relation reader: user +} \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed.expected b/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed.expected new file mode 100644 index 000000000..ebfe7571c --- /dev/null +++ b/pkg/schemadsl/parser/tests/deprecation_outside_definition.zed.expected @@ -0,0 +1,82 @@ +NodeTypeFile + end-rune = 288 + input-source = deprecation outside definition test + start-rune = 0 + child-node => + NodeTypeUseFlag + end-rune = 14 + input-source = deprecation outside definition test + start-rune = 0 + use-flag-name = deprecation + NodeTypeDeprecation + deprecation-comments = user is deprecated + deprecation-type = warn + end-rune = 55 + input-source = deprecation outside definition test + start-rune = 17 + NodeTypeDefinition + definition-name = user + end-rune = 74 + input-source = deprecation outside definition test + start-rune = 57 + NodeTypeDeprecation + deprecation-comments = comments here + deprecation-type = warn + end-rune = 110 + input-source = deprecation outside definition test + start-rune = 77 + NodeTypeDefinition + definition-name = testuser + end-rune = 133 + input-source = deprecation outside definition test + start-rune = 112 + NodeTypeDeprecation + deprecation-comments = test + deprecation-type = error + end-rune = 161 + input-source = deprecation outside definition test + start-rune = 136 + NodeTypeDefinition + definition-name = deprecated_relation + end-rune = 288 + input-source = deprecation outside definition test + start-rune = 163 + child-node => + NodeTypeRelation + end-rune = 221 + input-source = deprecation outside definition test + relation-name = writer + start-rune = 201 + allowed-types => + NodeTypeTypeReference + end-rune = 221 + input-source = deprecation outside definition test + start-rune = 218 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 221 + input-source = deprecation outside definition test + start-rune = 218 + type-name = user + NodeTypeDeprecation + deprecation-comments = test error + deprecation-type = error + end-rune = 260 + input-source = deprecation outside definition test + start-rune = 229 + NodeTypeRelation + end-rune = 286 + input-source = deprecation outside definition test + relation-name = reader + start-rune = 266 + allowed-types => + NodeTypeTypeReference + end-rune = 286 + input-source = deprecation outside definition test + start-rune = 283 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 286 + input-source = deprecation outside definition test + start-rune = 283 + type-name = user \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/invalid_deprecation.zed b/pkg/schemadsl/parser/tests/invalid_deprecation.zed new file mode 100644 index 000000000..045e7e447 --- /dev/null +++ b/pkg/schemadsl/parser/tests/invalid_deprecation.zed @@ -0,0 +1,6 @@ +definition deprecated_relation { + @deprecated() + relation reader: user +} + +definition user {} diff --git a/pkg/schemadsl/parser/tests/invalid_deprecation.zed.expected b/pkg/schemadsl/parser/tests/invalid_deprecation.zed.expected new file mode 100644 index 000000000..006a05df3 --- /dev/null +++ b/pkg/schemadsl/parser/tests/invalid_deprecation.zed.expected @@ -0,0 +1,34 @@ +NodeTypeFile + end-rune = 48 + input-source = invalid deprecation use + start-rune = 0 + child-node => + NodeTypeDefinition + definition-name = deprecated_relation + end-rune = 48 + input-source = invalid deprecation use + start-rune = 0 + child-node => + NodeTypeDeprecation + end-rune = 48 + input-source = invalid deprecation use + start-rune = 37 + child-node => + NodeTypeError + end-rune = 48 + error-message = Expected identifier for deprecation type + error-source = ) + input-source = invalid deprecation use + start-rune = 49 + NodeTypeError + end-rune = 48 + error-message = Expected end of statement or definition, found: TokenTypeRightParen + error-source = ) + input-source = invalid deprecation use + start-rune = 49 + NodeTypeError + end-rune = 48 + error-message = Unexpected token at root level: TokenTypeRightParen + error-source = ) + input-source = invalid deprecation use + start-rune = 49 \ No newline at end of file diff --git a/pkg/schemadsl/parser/tests/invaliduse.zed.expected b/pkg/schemadsl/parser/tests/invaliduse.zed.expected index 50f146898..f39958613 100644 --- a/pkg/schemadsl/parser/tests/invaliduse.zed.expected +++ b/pkg/schemadsl/parser/tests/invaliduse.zed.expected @@ -10,7 +10,7 @@ NodeTypeFile child-node => NodeTypeError end-rune = 12 - error-message = Unknown use flag: `something`. Options are: expiration, typechecking + error-message = Unknown use flag: `something`. Options are: deprecation, expiration, typechecking error-source = input-source = invalid use diff --git a/proto/internal/core/v1/core.proto b/proto/internal/core/v1/core.proto index a393eed14..a4ffde9af 100644 --- a/proto/internal/core/v1/core.proto +++ b/proto/internal/core/v1/core.proto @@ -204,6 +204,29 @@ message NamespaceDefinition { /** source_position contains the position of the namespace in the source schema, if any */ SourcePosition source_position = 4; + + /** deprecation contains the deprecation information for the namespace, if any */ + Deprecation deprecation = 5; +} + +/** + * DeprecationType is the type of deprecation for a relation. + */ +enum DeprecationType { + DEPRECATED_TYPE_UNSPECIFIED = 0; + DEPRECATED_TYPE_WARNING = 1; + DEPRECATED_TYPE_ERROR = 2; +} + +message Deprecation { + /** + * deprecation_type is the type of deprecation for the relation. + * It can be either a warning or an error, defaults to unspecified. + */ + DeprecationType deprecation_type = 1 [(validate.rules).enum.defined_only = true]; + + /** comments are the comments to show when the relation is used */ + string comments = 2 [(validate.rules).string = {max_bytes: 256}]; } /** @@ -233,6 +256,10 @@ message Relation { string aliasing_relation = 6; string canonical_cache_key = 7; + /** + * deprecation contains the deprecation information for the relation, if any + */ + Deprecation deprecation = 8; } /** @@ -420,6 +447,11 @@ message AllowedRelation { * required_expiration defines the required expiration on this relation. */ ExpirationTrait required_expiration = 7; + + /** + * deprecation contains the deprecation for the relation. + */ + Deprecation deprecation = 8; } /**