From 835c8e948ed64f5b761717cae6fe7795091a107c Mon Sep 17 00:00:00 2001 From: ivanauth Date: Wed, 26 Nov 2025 18:39:05 -0500 Subject: [PATCH 1/9] docs: document underscore prefix for private identifiers --- docs/schema-language.md | 75 ++++++++++++++++++ e2e/newenemy/newenemy_test.go | 2 +- .../compiler/compiler_test.go | 4 +- pkg/development/wasm/operations_test.go | 2 +- pkg/proto/core/v1/core.pb.go | 78 +++++++++---------- pkg/proto/core/v1/core.pb.validate.go | 60 +++++++------- pkg/schemadsl/compiler/compiler_test.go | 64 ++++++++++++++- pkg/schemadsl/lexer/lex_test.go | 19 +++++ pkg/tuple/parsing.go | 6 +- proto/internal/core/v1/core.proto | 30 +++---- 10 files changed, 247 insertions(+), 93 deletions(-) create mode 100644 docs/schema-language.md diff --git a/docs/schema-language.md b/docs/schema-language.md new file mode 100644 index 000000000..baef1fc13 --- /dev/null +++ b/docs/schema-language.md @@ -0,0 +1,75 @@ +# SpiceDB Schema Language Guide + +## Identifier Naming Conventions + +### Private/Internal Identifiers + +SpiceDB supports using underscore (`_`) as a prefix for identifiers to establish a convention for marking definitions as "private" or "internal". This is particularly useful for: + +- **Synthetic permissions**: Permissions that exist only to compose other permissions +- **Internal relations**: Relations not meant to be directly referenced by application code +- **Implementation details**: Parts of your schema that may change without affecting the public API + +### Examples + +```zed +definition document { + // Public relation - exposed to application code + relation viewer: user + + // Private relation - used internally for permission composition + relation _internal_viewer: user + + // Public permission using private components + permission view = viewer + _internal_viewer +} + +definition _internal_resource { + // This entire resource type is marked as internal + relation owner: user +} +``` + +### Best Practices + +1. **Use underscore prefix for synthetic permissions**: + ```zed + definition resource { + relation owner: user + relation editor: user + + // Private synthetic permission + permission _can_write = owner + editor + + // Public permissions built on private ones + permission edit = _can_write + permission delete = owner + } + ``` + +2. **Mark implementation details as private**: + ```zed + definition folder { + relation parent: folder + relation viewer: user + + // Private permission for traversal logic + permission _parent_view = parent->view + + // Public permission combining direct and inherited access + permission view = viewer + _parent_view + } + ``` + +3. **Future module system compatibility**: When SpiceDB introduces a module system for composing schemas via libraries, underscore-prefixed identifiers will help clearly distinguish between public and private APIs. + +### Technical Details + +- Identifiers can begin with either a letter (`a-z`) or underscore (`_`) +- After the first character, identifiers can contain letters, numbers, and underscores +- Identifiers must end with an alphanumeric character (not an underscore) +- Valid: `_private`, `_internal_relation`, `_helper123` +- Invalid: `_trailing_` (must end with alphanumeric), `123_start` (must start with letter or underscore) +- Note: `__double` is technically valid by the regex pattern but discouraged for readability + +This naming convention is enforced at the schema level and is compatible with all SpiceDB operations and queries. \ No newline at end of file diff --git a/e2e/newenemy/newenemy_test.go b/e2e/newenemy/newenemy_test.go index 24ae51de6..a6ee39a8b 100644 --- a/e2e/newenemy/newenemy_test.go +++ b/e2e/newenemy/newenemy_test.go @@ -64,7 +64,7 @@ definition {{.Resource}} { {{ end }} ` objIDRegex = "[a-zA-Z0-9_][a-zA-Z0-9/_-]{0,127}" - namespacePrefixRegex = "[a-z][a-z0-9_]{1,62}[a-z0-9]" + namespacePrefixRegex = "[a-z_][a-z0-9_]{1,62}[a-z0-9]" ) var ( diff --git a/pkg/composableschemadsl/compiler/compiler_test.go b/pkg/composableschemadsl/compiler/compiler_test.go index 0280e2666..100682a4b 100644 --- a/pkg/composableschemadsl/compiler/compiler_test.go +++ b/pkg/composableschemadsl/compiler/compiler_test.go @@ -769,7 +769,7 @@ func TestCompile(t *testing.T) { "invalid definition name", nilPrefix, `definition someTenant/fo {}`, - "parse error in `invalid definition name`, line 1, column 1: error in object definition someTenant/fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + "parse error in `invalid definition name`, line 1, column 1: error in object definition someTenant/fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", []SchemaDefinition{}, }, { @@ -778,7 +778,7 @@ func TestCompile(t *testing.T) { `definition some_tenant/foos { relation ab: some_tenant/foos }`, - "parse error in `invalid relation name`, line 2, column 5: error in relation ab: invalid Relation.Name: value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + "parse error in `invalid relation name`, line 2, column 5: error in relation ab: invalid Relation.Name: value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", []SchemaDefinition{}, }, { diff --git a/pkg/development/wasm/operations_test.go b/pkg/development/wasm/operations_test.go index 96031f3ae..7a5afcfe9 100644 --- a/pkg/development/wasm/operations_test.go +++ b/pkg/development/wasm/operations_test.go @@ -131,7 +131,7 @@ func TestCheckOperation(t *testing.T) { tuple.MustParse("somenamespace:someobj#anotherrel@user:foo"), nil, &devinterface.DeveloperError{ - Message: "error in object definition fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + Message: "error in object definition fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", Kind: devinterface.DeveloperError_SCHEMA_ISSUE, Source: devinterface.DeveloperError_SCHEMA, Line: 1, diff --git a/pkg/proto/core/v1/core.pb.go b/pkg/proto/core/v1/core.pb.go index c8646684f..f1180c8b7 100644 --- a/pkg/proto/core/v1/core.pb.go +++ b/pkg/proto/core/v1/core.pb.go @@ -3028,14 +3028,14 @@ const file_core_v1_core_proto_rawDesc = "" + "\ttype_name\x18\x01 \x01(\tR\btypeName\x12I\n" + "\vchild_types\x18\x02 \x03(\v2\x1c.core.v1.CaveatTypeReferenceB\n" + "\xfaB\a\x92\x01\x04\b\x00\x10\x01R\n" + - "childTypes\"\x91\x02\n" + - "\x11ObjectAndRelation\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\x12F\n" + - "\tobject_id\x18\x02 \x01(\tB)\xfaB&r$(\x80\b2\x1f^(([a-zA-Z0-9/_|\\-=+]{1,})|\\*)$R\bobjectId\x12L\n" + - "\brelation\x18\x03 \x01(\tB0\xfaB-r+(@2'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$R\brelation\"\xc9\x01\n" + - "\x11RelationReference\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\x12L\n" + - "\brelation\x18\x03 \x01(\tB0\xfaB-r+(@2'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$R\brelation\"'\n" + + "childTypes\"\x94\x02\n" + + "\x11ObjectAndRelation\x12h\n" + + "\tnamespace\x18\x01 \x01(\tBJ\xfaBGrE(\x80\x012@^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12F\n" + + "\tobject_id\x18\x02 \x01(\tB)\xfaB&r$(\x80\b2\x1f^(([a-zA-Z0-9/_|\\-=+]{1,})|\\*)$R\bobjectId\x12M\n" + + "\brelation\x18\x03 \x01(\tB1\xfaB.r,(@2(^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$R\brelation\"\xcc\x01\n" + + "\x11RelationReference\x12h\n" + + "\tnamespace\x18\x01 \x01(\tBJ\xfaBGrE(\x80\x012@^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12M\n" + + "\brelation\x18\x03 \x01(\tB1\xfaB.r,(@2(^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$R\brelation\"'\n" + "\x06Zookie\x12\x1d\n" + "\x05token\x18\x01 \x01(\tB\a\xfaB\x04r\x02 \x01R\x05token\"\xda\x01\n" + "\x13RelationTupleUpdate\x12N\n" + @@ -3069,14 +3069,14 @@ 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" + - "\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" + + "\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\"\x95\x02\n" + + "\x13NamespaceDefinition\x12^\n" + + "\x04name\x18\x01 \x01(\tBJ\xfaBGrE(\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" + - "\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" + + "\x0fsource_position\x18\x04 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\"\x9d\x03\n" + + "\bRelation\x12<\n" + + "\x04name\x18\x01 \x01(\tB(\xfaB%r#(@2\x1f^[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" + "\x10type_information\x18\x03 \x01(\v2\x18.core.v1.TypeInformationR\x0ftypeInformation\x12-\n" + "\bmetadata\x18\x04 \x01(\v2\x11.core.v1.MetadataR\bmetadata\x12@\n" + @@ -3110,10 +3110,10 @@ 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" + - "\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" + + "\x18allowed_direct_relations\x18\x01 \x03(\v2\x18.core.v1.AllowedRelationR\x16allowedDirectRelations\"\x98\x04\n" + + "\x0fAllowedRelation\x12h\n" + + "\tnamespace\x18\x01 \x01(\tBJ\xfaBGrE(\x80\x012@^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12O\n" + + "\brelation\x18\x03 \x01(\tB1\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" + @@ -3144,28 +3144,28 @@ const file_core_v1_core_proto_rawDesc = "" + "\x04This\x1a\x05\n" + "\x03NilB\x11\n" + "\n" + - "child_type\x12\x03\xf8B\x01\"\xba\x02\n" + + "child_type\x12\x03\xf8B\x01\"\xbb\x02\n" + "\x0eTupleToUserset\x12F\n" + "\btupleset\x18\x01 \x01(\v2 .core.v1.TupleToUserset.TuplesetB\b\xfaB\x05\x8a\x01\x02\x10\x01R\btupleset\x12M\n" + "\x10computed_userset\x18\x02 \x01(\v2\x18.core.v1.ComputedUsersetB\b\xfaB\x05\x8a\x01\x02\x10\x01R\x0fcomputedUserset\x12@\n" + - "\x0fsource_position\x18\x03 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x1aO\n" + - "\bTupleset\x12C\n" + - "\brelation\x18\x01 \x01(\tB'\xfaB$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$R\brelation\"\xec\x03\n" + + "\x0fsource_position\x18\x03 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x1aP\n" + + "\bTupleset\x12D\n" + + "\brelation\x18\x01 \x01(\tB(\xfaB%r#(@2\x1f^[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\brelation\"\xed\x03\n" + "\x18FunctionedTupleToUserset\x12R\n" + "\bfunction\x18\x01 \x01(\x0e2*.core.v1.FunctionedTupleToUserset.FunctionB\n" + "\xfaB\a\x82\x01\x04\x10\x01 \x00R\bfunction\x12P\n" + "\btupleset\x18\x02 \x01(\v2*.core.v1.FunctionedTupleToUserset.TuplesetB\b\xfaB\x05\x8a\x01\x02\x10\x01R\btupleset\x12M\n" + "\x10computed_userset\x18\x03 \x01(\v2\x18.core.v1.ComputedUsersetB\b\xfaB\x05\x8a\x01\x02\x10\x01R\x0fcomputedUserset\x12@\n" + - "\x0fsource_position\x18\x04 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x1aO\n" + - "\bTupleset\x12C\n" + - "\brelation\x18\x01 \x01(\tB'\xfaB$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$R\brelation\"H\n" + + "\x0fsource_position\x18\x04 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\x1aP\n" + + "\bTupleset\x12D\n" + + "\brelation\x18\x01 \x01(\tB(\xfaB%r#(@2\x1f^[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\brelation\"H\n" + "\bFunction\x12\x18\n" + "\x14FUNCTION_UNSPECIFIED\x10\x00\x12\x10\n" + "\fFUNCTION_ANY\x10\x01\x12\x10\n" + - "\fFUNCTION_ALL\x10\x02\"\x91\x02\n" + + "\fFUNCTION_ALL\x10\x02\"\x92\x02\n" + "\x0fComputedUserset\x12A\n" + - "\x06object\x18\x01 \x01(\x0e2\x1f.core.v1.ComputedUserset.ObjectB\b\xfaB\x05\x82\x01\x02\x10\x01R\x06object\x12C\n" + - "\brelation\x18\x02 \x01(\tB'\xfaB$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$R\brelation\x12@\n" + + "\x06object\x18\x01 \x01(\x0e2\x1f.core.v1.ComputedUserset.ObjectB\b\xfaB\x05\x82\x01\x02\x10\x01R\x06object\x12D\n" + + "\brelation\x18\x02 \x01(\tB(\xfaB%r#(@2\x1f^[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\brelation\x12@\n" + "\x0fsource_position\x18\x03 \x01(\v2\x17.core.v1.SourcePositionR\x0esourcePosition\"4\n" + "\x06Object\x12\x10\n" + "\fTUPLE_OBJECT\x10\x00\x12\x18\n" + @@ -3184,19 +3184,19 @@ const file_core_v1_core_proto_rawDesc = "" + "\aUNKNOWN\x10\x00\x12\x06\n" + "\x02OR\x10\x01\x12\a\n" + "\x03AND\x10\x02\x12\a\n" + - "\x03NOT\x10\x03\"\xee\x03\n" + - "\x12RelationshipFilter\x12p\n" + - "\rresource_type\x18\x01 \x01(\tBK\xfaBHrF(\x80\x012A^(([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9])?$R\fresourceType\x12W\n" + + "\x03NOT\x10\x03\"\xf1\x03\n" + + "\x12RelationshipFilter\x12r\n" + + "\rresource_type\x18\x01 \x01(\tBM\xfaBJrH(\x80\x012C^(([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9])?$R\fresourceType\x12W\n" + "\x14optional_resource_id\x18\x02 \x01(\tB%\xfaB\"r (\x80\b2\x1b^([a-zA-Z0-9/_|\\-=+]{1,})?$R\x12optionalResourceId\x12d\n" + - "\x1boptional_resource_id_prefix\x18\x05 \x01(\tB%\xfaB\"r (\x80\b2\x1b^([a-zA-Z0-9/_|\\-=+]{1,})?$R\x18optionalResourceIdPrefix\x12W\n" + - "\x11optional_relation\x18\x03 \x01(\tB*\xfaB'r%(@2!^([a-z][a-z0-9_]{1,62}[a-z0-9])?$R\x10optionalRelation\x12N\n" + - "\x17optional_subject_filter\x18\x04 \x01(\v2\x16.core.v1.SubjectFilterR\x15optionalSubjectFilter\"\x86\x03\n" + - "\rSubjectFilter\x12k\n" + - "\fsubject_type\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\vsubjectType\x12Z\n" + + "\x1boptional_resource_id_prefix\x18\x05 \x01(\tB%\xfaB\"r (\x80\b2\x1b^([a-zA-Z0-9/_|\\-=+]{1,})?$R\x18optionalResourceIdPrefix\x12X\n" + + "\x11optional_relation\x18\x03 \x01(\tB+\xfaB(r&(@2\"^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$R\x10optionalRelation\x12N\n" + + "\x17optional_subject_filter\x18\x04 \x01(\v2\x16.core.v1.SubjectFilterR\x15optionalSubjectFilter\"\x89\x03\n" + + "\rSubjectFilter\x12m\n" + + "\fsubject_type\x18\x01 \x01(\tBJ\xfaBGrE(\x80\x012@^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$R\vsubjectType\x12Z\n" + "\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" + + "\x11optional_relation\x18\x03 \x01(\v2%.core.v1.SubjectFilter.RelationFilterR\x10optionalRelation\x1aY\n" + + "\x0eRelationFilter\x12G\n" + + "\brelation\x18\x01 \x01(\tB+\xfaB(r&(@2\"^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$R\brelationB\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 ( diff --git a/pkg/proto/core/v1/core.pb.validate.go b/pkg/proto/core/v1/core.pb.validate.go index 021429241..ccbe3ae88 100644 --- a/pkg/proto/core/v1/core.pb.validate.go +++ b/pkg/proto/core/v1/core.pb.validate.go @@ -1027,7 +1027,7 @@ func (m *ObjectAndRelation) validate(all bool) error { if !_ObjectAndRelation_Namespace_Pattern.MatchString(m.GetNamespace()) { err := ObjectAndRelationValidationError{ field: "Namespace", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -1071,7 +1071,7 @@ func (m *ObjectAndRelation) validate(all bool) error { if !_ObjectAndRelation_Relation_Pattern.MatchString(m.GetRelation()) { err := ObjectAndRelationValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\"", + reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$\"", } if !all { return err @@ -1159,11 +1159,11 @@ var _ interface { ErrorName() string } = ObjectAndRelationValidationError{} -var _ObjectAndRelation_Namespace_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _ObjectAndRelation_Namespace_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$") var _ObjectAndRelation_ObjectId_Pattern = regexp.MustCompile("^(([a-zA-Z0-9/_|\\-=+]{1,})|\\*)$") -var _ObjectAndRelation_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$") +var _ObjectAndRelation_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$") // Validate checks the field values on RelationReference with the rules defined // in the proto definition for this message. If any rules are violated, the @@ -1201,7 +1201,7 @@ func (m *RelationReference) validate(all bool) error { if !_RelationReference_Namespace_Pattern.MatchString(m.GetNamespace()) { err := RelationReferenceValidationError{ field: "Namespace", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -1223,7 +1223,7 @@ func (m *RelationReference) validate(all bool) error { if !_RelationReference_Relation_Pattern.MatchString(m.GetRelation()) { err := RelationReferenceValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\"", + reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$\"", } if !all { return err @@ -1311,9 +1311,9 @@ var _ interface { ErrorName() string } = RelationReferenceValidationError{} -var _RelationReference_Namespace_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _RelationReference_Namespace_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$") -var _RelationReference_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$") +var _RelationReference_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$") // Validate checks the field values on Zookie with the rules defined in the // proto definition for this message. If any rules are violated, the first @@ -2436,7 +2436,7 @@ func (m *NamespaceDefinition) validate(all bool) error { if !_NamespaceDefinition_Name_Pattern.MatchString(m.GetName()) { err := NamespaceDefinitionValidationError{ field: "Name", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -2616,7 +2616,7 @@ var _ interface { ErrorName() string } = NamespaceDefinitionValidationError{} -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]$") +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 Relation with the rules defined in the // proto definition for this message. If any rules are violated, the first @@ -2654,7 +2654,7 @@ func (m *Relation) validate(all bool) error { if !_Relation_Name_Pattern.MatchString(m.GetName()) { err := RelationValidationError{ field: "Name", - reason: "value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -2859,7 +2859,7 @@ var _ interface { ErrorName() string } = RelationValidationError{} -var _Relation_Name_Pattern = regexp.MustCompile("^[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _Relation_Name_Pattern = regexp.MustCompile("^[a-z_][a-z0-9_]{1,62}[a-z0-9]$") // Validate checks the field values on ReachabilityGraph with the rules defined // in the proto definition for this message. If any rules are violated, the @@ -3531,7 +3531,7 @@ func (m *AllowedRelation) validate(all bool) error { if !_AllowedRelation_Namespace_Pattern.MatchString(m.GetNamespace()) { err := AllowedRelationValidationError{ field: "Namespace", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -3653,7 +3653,7 @@ func (m *AllowedRelation) validate(all bool) error { if !_AllowedRelation_Relation_Pattern.MatchString(m.GetRelation()) { err := AllowedRelationValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\"", + reason: "value does not match regex pattern \"^(\\\\.\\\\.\\\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$\"", } if !all { return err @@ -3784,9 +3784,9 @@ var _ interface { ErrorName() string } = AllowedRelationValidationError{} -var _AllowedRelation_Namespace_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _AllowedRelation_Namespace_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$") -var _AllowedRelation_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$") +var _AllowedRelation_Relation_Pattern = regexp.MustCompile("^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$") // Validate checks the field values on ExpirationTrait with the rules defined // in the proto definition for this message. If any rules are violated, the @@ -4942,7 +4942,7 @@ func (m *ComputedUserset) validate(all bool) error { if !_ComputedUserset_Relation_Pattern.MatchString(m.GetRelation()) { err := ComputedUsersetValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -5057,7 +5057,7 @@ var _ interface { ErrorName() string } = ComputedUsersetValidationError{} -var _ComputedUserset_Relation_Pattern = regexp.MustCompile("^[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _ComputedUserset_Relation_Pattern = regexp.MustCompile("^[a-z_][a-z0-9_]{1,62}[a-z0-9]$") // Validate checks the field values on SourcePosition with the rules defined in // the proto definition for this message. If any rules are violated, the first @@ -5522,7 +5522,7 @@ func (m *RelationshipFilter) validate(all bool) error { if !_RelationshipFilter_ResourceType_Pattern.MatchString(m.GetResourceType()) { err := RelationshipFilterValidationError{ field: "ResourceType", - reason: "value does not match regex pattern \"^(([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9])?$\"", + reason: "value does not match regex pattern \"^(([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9])?$\"", } if !all { return err @@ -5588,7 +5588,7 @@ func (m *RelationshipFilter) validate(all bool) error { if !_RelationshipFilter_OptionalRelation_Pattern.MatchString(m.GetOptionalRelation()) { err := RelationshipFilterValidationError{ field: "OptionalRelation", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9])?$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$\"", } if !all { return err @@ -5705,13 +5705,13 @@ var _ interface { ErrorName() string } = RelationshipFilterValidationError{} -var _RelationshipFilter_ResourceType_Pattern = regexp.MustCompile("^(([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9])?$") +var _RelationshipFilter_ResourceType_Pattern = regexp.MustCompile("^(([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9])?$") var _RelationshipFilter_OptionalResourceId_Pattern = regexp.MustCompile("^([a-zA-Z0-9/_|\\-=+]{1,})?$") var _RelationshipFilter_OptionalResourceIdPrefix_Pattern = regexp.MustCompile("^([a-zA-Z0-9/_|\\-=+]{1,})?$") -var _RelationshipFilter_OptionalRelation_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,62}[a-z0-9])?$") +var _RelationshipFilter_OptionalRelation_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$") // Validate checks the field values on SubjectFilter with the rules defined in // the proto definition for this message. If any rules are violated, the first @@ -5749,7 +5749,7 @@ func (m *SubjectFilter) validate(all bool) error { if !_SubjectFilter_SubjectType_Pattern.MatchString(m.GetSubjectType()) { err := SubjectFilterValidationError{ field: "SubjectType", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -5886,7 +5886,7 @@ var _ interface { ErrorName() string } = SubjectFilterValidationError{} -var _SubjectFilter_SubjectType_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _SubjectFilter_SubjectType_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$") var _SubjectFilter_OptionalSubjectId_Pattern = regexp.MustCompile("^(([a-zA-Z0-9/_|\\-=+]{1,})|\\*)?$") @@ -6676,7 +6676,7 @@ func (m *TupleToUserset_Tupleset) validate(all bool) error { if !_TupleToUserset_Tupleset_Relation_Pattern.MatchString(m.GetRelation()) { err := TupleToUserset_TuplesetValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -6764,7 +6764,7 @@ var _ interface { ErrorName() string } = TupleToUserset_TuplesetValidationError{} -var _TupleToUserset_Tupleset_Relation_Pattern = regexp.MustCompile("^[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _TupleToUserset_Tupleset_Relation_Pattern = regexp.MustCompile("^[a-z_][a-z0-9_]{1,62}[a-z0-9]$") // Validate checks the field values on FunctionedTupleToUserset_Tupleset with // the rules defined in the proto definition for this message. If any rules @@ -6803,7 +6803,7 @@ func (m *FunctionedTupleToUserset_Tupleset) validate(all bool) error { if !_FunctionedTupleToUserset_Tupleset_Relation_Pattern.MatchString(m.GetRelation()) { err := FunctionedTupleToUserset_TuplesetValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + reason: "value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", } if !all { return err @@ -6893,7 +6893,7 @@ var _ interface { ErrorName() string } = FunctionedTupleToUserset_TuplesetValidationError{} -var _FunctionedTupleToUserset_Tupleset_Relation_Pattern = regexp.MustCompile("^[a-z][a-z0-9_]{1,62}[a-z0-9]$") +var _FunctionedTupleToUserset_Tupleset_Relation_Pattern = regexp.MustCompile("^[a-z_][a-z0-9_]{1,62}[a-z0-9]$") // Validate checks the field values on SubjectFilter_RelationFilter with the // rules defined in the proto definition for this message. If any rules are @@ -6931,7 +6931,7 @@ func (m *SubjectFilter_RelationFilter) validate(all bool) error { if !_SubjectFilter_RelationFilter_Relation_Pattern.MatchString(m.GetRelation()) { err := SubjectFilter_RelationFilterValidationError{ field: "Relation", - reason: "value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9])?$\"", + reason: "value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$\"", } if !all { return err @@ -7020,4 +7020,4 @@ var _ interface { ErrorName() string } = SubjectFilter_RelationFilterValidationError{} -var _SubjectFilter_RelationFilter_Relation_Pattern = regexp.MustCompile("^([a-z][a-z0-9_]{1,62}[a-z0-9])?$") +var _SubjectFilter_RelationFilter_Relation_Pattern = regexp.MustCompile("^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$") diff --git a/pkg/schemadsl/compiler/compiler_test.go b/pkg/schemadsl/compiler/compiler_test.go index 4b23125f4..6fe05d2f3 100644 --- a/pkg/schemadsl/compiler/compiler_test.go +++ b/pkg/schemadsl/compiler/compiler_test.go @@ -509,7 +509,7 @@ func TestCompile(t *testing.T) { "invalid definition name", nilPrefix, `definition someTenant/fo {}`, - "parse error in `invalid definition name`, line 1, column 1: error in object definition someTenant/fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + "parse error in `invalid definition name`, line 1, column 1: error in object definition someTenant/fo: invalid NamespaceDefinition.Name: value does not match regex pattern \"^([a-z_][a-z0-9_]{1,62}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", []SchemaDefinition{}, }, { @@ -518,7 +518,7 @@ func TestCompile(t *testing.T) { `definition some_tenant/foos { relation ab: some_tenant/foos }`, - "parse error in `invalid relation name`, line 2, column 5: error in relation ab: invalid Relation.Name: value does not match regex pattern \"^[a-z][a-z0-9_]{1,62}[a-z0-9]$\"", + "parse error in `invalid relation name`, line 2, column 5: error in relation ab: invalid Relation.Name: value does not match regex pattern \"^[a-z_][a-z0-9_]{1,62}[a-z0-9]$\"", []SchemaDefinition{}, }, { @@ -1057,6 +1057,66 @@ func TestCompile(t *testing.T) { ), }, }, + { + "underscore prefix namespace", + AllowUnprefixedObjectType(), + `definition _private_resource { + relation owner: user + }`, + "", + []SchemaDefinition{ + namespace.Namespace("_private_resource", + namespace.MustRelation("owner", nil, namespace.AllowedRelation("user", "...")), + ), + }, + }, + { + "underscore prefix relation", + withTenantPrefix, + `definition resource { + relation _internal_owner: sometenant/user + relation viewer: sometenant/user + permission view = viewer + _internal_owner + }`, + "", + []SchemaDefinition{ + namespace.Namespace("sometenant/resource", + namespace.MustRelation("_internal_owner", nil, namespace.AllowedRelation("sometenant/user", "...")), + namespace.MustRelation("viewer", nil, namespace.AllowedRelation("sometenant/user", "...")), + namespace.MustRelation("view", + namespace.Union( + namespace.ComputedUserset("viewer"), + namespace.ComputedUserset("_internal_owner"), + ), + ), + ), + }, + }, + { + "underscore prefix permission", + withTenantPrefix, + `definition document { + relation owner: sometenant/user + permission _internal_edit = owner + permission edit = _internal_edit + }`, + "", + []SchemaDefinition{ + namespace.Namespace("sometenant/document", + namespace.MustRelation("owner", nil, namespace.AllowedRelation("sometenant/user", "...")), + namespace.MustRelation("_internal_edit", + namespace.Union( + namespace.ComputedUserset("owner"), + ), + ), + namespace.MustRelation("edit", + namespace.Union( + namespace.ComputedUserset("_internal_edit"), + ), + ), + ), + }, + }, } for _, test := range tests { diff --git a/pkg/schemadsl/lexer/lex_test.go b/pkg/schemadsl/lexer/lex_test.go index 0a80d50fd..7c4960510 100644 --- a/pkg/schemadsl/lexer/lex_test.go +++ b/pkg/schemadsl/lexer/lex_test.go @@ -66,6 +66,25 @@ var lexerTests = []lexerTest{ tEOF, }}, + // Underscore prefix tests + {"underscore identifier", "_private", []Lexeme{{TokenTypeIdentifier, 0, "_private", ""}, tEOF}}, + {"underscore relation", "_internal_permission", []Lexeme{{TokenTypeIdentifier, 0, "_internal_permission", ""}, tEOF}}, + {"underscore namespace", "_system", []Lexeme{{TokenTypeIdentifier, 0, "_system", ""}, tEOF}}, + {"underscore typepath", "_tenant/_resource", []Lexeme{ + {TokenTypeIdentifier, 0, "_tenant", ""}, + {TokenTypeDiv, 0, "/", ""}, + {TokenTypeIdentifier, 0, "_resource", ""}, + tEOF, + }}, + {"mixed underscore path", "_private/public/_internal", []Lexeme{ + {TokenTypeIdentifier, 0, "_private", ""}, + {TokenTypeDiv, 0, "/", ""}, + {TokenTypeIdentifier, 0, "public", ""}, + {TokenTypeDiv, 0, "/", ""}, + {TokenTypeIdentifier, 0, "_internal", ""}, + tEOF, + }}, + {"multiple slash path", "foo/bar/baz/bang/zoom", []Lexeme{ {TokenTypeIdentifier, 0, "foo", ""}, {TokenTypeDiv, 0, "/", ""}, diff --git a/pkg/tuple/parsing.go b/pkg/tuple/parsing.go index 3e03678cc..d2a336b16 100644 --- a/pkg/tuple/parsing.go +++ b/pkg/tuple/parsing.go @@ -16,11 +16,11 @@ import ( ) const ( - namespaceNameExpr = "([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]" + namespaceNameExpr = "([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]" resourceIDExpr = "([a-zA-Z0-9/_|\\-=+]{1,})" subjectIDExpr = "([a-zA-Z0-9/_|\\-=+]{1,})|\\*" - relationExpr = "[a-z][a-z0-9_]{1,62}[a-z0-9]" - caveatNameExpr = "([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]" + relationExpr = "[a-z_][a-z0-9_]{1,62}[a-z0-9]" + caveatNameExpr = "([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]" ) var onrExpr = fmt.Sprintf( diff --git a/proto/internal/core/v1/core.proto b/proto/internal/core/v1/core.proto index a393eed14..cda0d13e4 100644 --- a/proto/internal/core/v1/core.proto +++ b/proto/internal/core/v1/core.proto @@ -88,7 +88,7 @@ message CaveatTypeReference { message ObjectAndRelation { /** namespace is the full namespace path for the referenced object */ string namespace = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 128 }]; @@ -100,7 +100,7 @@ message ObjectAndRelation { /** relation is the name of the referenced relation or permission under the namespace */ string relation = 3 [(validate.rules).string = { - pattern: "^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$" + pattern: "^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$" max_bytes: 64 }]; } @@ -108,13 +108,13 @@ message ObjectAndRelation { message RelationReference { /** namespace is the full namespace path */ string namespace = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 128 }]; /** relation is the name of the referenced relation or permission under the namespace */ string relation = 3 [(validate.rules).string = { - pattern: "^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$" + pattern: "^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$" max_bytes: 64 }]; } @@ -192,7 +192,7 @@ message Metadata { message NamespaceDefinition { /** name is the unique for the namespace, including prefixes (which are optional) */ string name = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^([a-z_][a-z0-9_]{1,62}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 128 }]; @@ -212,7 +212,7 @@ message NamespaceDefinition { message Relation { /** name is the full name for the relation or permission */ string name = 1 [(validate.rules).string = { - pattern: "^[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 64 }]; @@ -393,7 +393,7 @@ message AllowedRelation { /** namespace is the full namespace path of the allowed object type */ string namespace = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 128 }]; @@ -402,7 +402,7 @@ message AllowedRelation { */ oneof relation_or_wildcard { string relation = 3 [(validate.rules).string = { - pattern: "^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$" + pattern: "^(\\.\\.\\.|[a-z_][a-z0-9_]{1,62}[a-z0-9])$" max_bytes: 64 }]; PublicWildcard public_wildcard = 4; @@ -485,7 +485,7 @@ message SetOperation { message TupleToUserset { message Tupleset { string relation = 1 [(validate.rules).string = { - pattern: "^[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 64 }]; } @@ -504,7 +504,7 @@ message FunctionedTupleToUserset { message Tupleset { string relation = 1 [(validate.rules).string = { - pattern: "^[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 64 }]; } @@ -526,7 +526,7 @@ message ComputedUserset { Object object = 1 [(validate.rules).enum.defined_only = true]; string relation = 2 [(validate.rules).string = { - pattern: "^[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 64 }]; SourcePosition source_position = 3; @@ -560,7 +560,7 @@ message RelationshipFilter { // resource_type is the *optional* resource type of the relationship. // NOTE: It is not prefixed with "optional_" for legacy compatibility. string resource_type = 1 [(validate.rules).string = { - pattern: "^(([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9])?$" + pattern: "^(([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9])?$" max_bytes: 128 }]; @@ -580,7 +580,7 @@ message RelationshipFilter { // relation is the *optional* relation of the relationship. string optional_relation = 3 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$" + pattern: "^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$" max_bytes: 64 }]; @@ -595,13 +595,13 @@ message RelationshipFilter { message SubjectFilter { message RelationFilter { string relation = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$" + pattern: "^([a-z_][a-z0-9_]{1,62}[a-z0-9])?$" max_bytes: 64 }]; } string subject_type = 1 [(validate.rules).string = { - pattern: "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$" + pattern: "^([a-z_][a-z0-9_]{1,61}[a-z0-9]/)*[a-z_][a-z0-9_]{1,62}[a-z0-9]$" max_bytes: 128 }]; From 8005a12483a41053fc777d5129e6707aeeae661f Mon Sep 17 00:00:00 2001 From: ivanauth Date: Wed, 26 Nov 2025 18:57:00 -0500 Subject: [PATCH 2/9] fix: add trailing newline to schema-language.md --- docs/schema-language.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/schema-language.md b/docs/schema-language.md index baef1fc13..fac0a17f1 100644 --- a/docs/schema-language.md +++ b/docs/schema-language.md @@ -72,4 +72,4 @@ definition _internal_resource { - Invalid: `_trailing_` (must end with alphanumeric), `123_start` (must start with letter or underscore) - Note: `__double` is technically valid by the regex pattern but discouraged for readability -This naming convention is enforced at the schema level and is compatible with all SpiceDB operations and queries. \ No newline at end of file +This naming convention is enforced at the schema level and is compatible with all SpiceDB operations and queries. From a0b215a236dec6f21f9a55acd5e0794404235e9c Mon Sep 17 00:00:00 2001 From: ivanauth Date: Wed, 7 Jan 2026 10:43:51 -0500 Subject: [PATCH 3/9] chore: remove in-repo docs (should go to authzed/docs) The schema-language.md file won't be published from this repo. Documentation for underscore prefix identifiers should be added to https://github.com/authzed/docs instead. --- docs/schema-language.md | 75 ----------------------------------------- 1 file changed, 75 deletions(-) delete mode 100644 docs/schema-language.md diff --git a/docs/schema-language.md b/docs/schema-language.md deleted file mode 100644 index fac0a17f1..000000000 --- a/docs/schema-language.md +++ /dev/null @@ -1,75 +0,0 @@ -# SpiceDB Schema Language Guide - -## Identifier Naming Conventions - -### Private/Internal Identifiers - -SpiceDB supports using underscore (`_`) as a prefix for identifiers to establish a convention for marking definitions as "private" or "internal". This is particularly useful for: - -- **Synthetic permissions**: Permissions that exist only to compose other permissions -- **Internal relations**: Relations not meant to be directly referenced by application code -- **Implementation details**: Parts of your schema that may change without affecting the public API - -### Examples - -```zed -definition document { - // Public relation - exposed to application code - relation viewer: user - - // Private relation - used internally for permission composition - relation _internal_viewer: user - - // Public permission using private components - permission view = viewer + _internal_viewer -} - -definition _internal_resource { - // This entire resource type is marked as internal - relation owner: user -} -``` - -### Best Practices - -1. **Use underscore prefix for synthetic permissions**: - ```zed - definition resource { - relation owner: user - relation editor: user - - // Private synthetic permission - permission _can_write = owner + editor - - // Public permissions built on private ones - permission edit = _can_write - permission delete = owner - } - ``` - -2. **Mark implementation details as private**: - ```zed - definition folder { - relation parent: folder - relation viewer: user - - // Private permission for traversal logic - permission _parent_view = parent->view - - // Public permission combining direct and inherited access - permission view = viewer + _parent_view - } - ``` - -3. **Future module system compatibility**: When SpiceDB introduces a module system for composing schemas via libraries, underscore-prefixed identifiers will help clearly distinguish between public and private APIs. - -### Technical Details - -- Identifiers can begin with either a letter (`a-z`) or underscore (`_`) -- After the first character, identifiers can contain letters, numbers, and underscores -- Identifiers must end with an alphanumeric character (not an underscore) -- Valid: `_private`, `_internal_relation`, `_helper123` -- Invalid: `_trailing_` (must end with alphanumeric), `123_start` (must start with letter or underscore) -- Note: `__double` is technically valid by the regex pattern but discouraged for readability - -This naming convention is enforced at the schema level and is compatible with all SpiceDB operations and queries. From 48c6e78c198fe1027c5ef5392a3e7faebdd2e0af Mon Sep 17 00:00:00 2001 From: ivanauth Date: Wed, 7 Jan 2026 10:43:56 -0500 Subject: [PATCH 4/9] chore: trigger CI re-run for flaky E2E test From 1eb6d4b82a58fb006d21171d1b883aa4fed64ecd Mon Sep 17 00:00:00 2001 From: ivanauth Date: Thu, 8 Jan 2026 10:10:50 -0500 Subject: [PATCH 5/9] ci: re-run tests From 1096f00d8bbefc04a7c74523db87b63ddeee6991 Mon Sep 17 00:00:00 2001 From: ivanauth Date: Thu, 8 Jan 2026 10:50:01 -0500 Subject: [PATCH 6/9] feat: allow underscore prefix for private identifiers --- e2e/newenemy/newenemy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/newenemy/newenemy_test.go b/e2e/newenemy/newenemy_test.go index a6ee39a8b..24ae51de6 100644 --- a/e2e/newenemy/newenemy_test.go +++ b/e2e/newenemy/newenemy_test.go @@ -64,7 +64,7 @@ definition {{.Resource}} { {{ end }} ` objIDRegex = "[a-zA-Z0-9_][a-zA-Z0-9/_-]{0,127}" - namespacePrefixRegex = "[a-z_][a-z0-9_]{1,62}[a-z0-9]" + namespacePrefixRegex = "[a-z][a-z0-9_]{1,62}[a-z0-9]" ) var ( From 02398752679382ae8abaf6491f8a2c0a656956ce Mon Sep 17 00:00:00 2001 From: ivanauth Date: Thu, 22 Jan 2026 14:30:34 -0500 Subject: [PATCH 7/9] chore: retrigger CI Co-Authored-By: Claude Opus 4.5 From d37ba733e2afe9863fdc1947ef3bcf2f3a3699ee Mon Sep 17 00:00:00 2001 From: ivanauth Date: Thu, 22 Jan 2026 17:03:21 -0500 Subject: [PATCH 8/9] chore: retrigger CI From ddd8b7b42f50584b56c57be720a4fae6c218e5df Mon Sep 17 00:00:00 2001 From: ivanauth Date: Fri, 23 Jan 2026 10:13:02 -0500 Subject: [PATCH 9/9] ci: bump setup-go action to match go.mod Go 1.25.5 requirement The CI was pinning authzed/actions/setup-go to a commit that defaulted to Go 1.25.3, while go.mod requires Go 1.25.5. This caused Go to attempt auto-downloading the 1.25.5 toolchain from the proxy, which fails when the proxy is unreachable (as seen in the postgres 17 consistency test failure due to network timeout). Update the pin from 6cde6aeb (Go 1.25.3) to 882cac02 (Go 1.25.5) across all workflow files. --- .github/workflows/build-test.yaml | 28 +++++++++++++------------- .github/workflows/lint.yaml | 6 +++--- .github/workflows/nightly.yaml | 2 +- .github/workflows/release-windows.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/security.yaml | 4 ++-- .github/workflows/wasm.yaml | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 30a69d60c..e38aa1a91 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -53,7 +53,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 with: username: "${{ env.DOCKERHUB_PUBLIC_USER }}" @@ -72,7 +72,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Unit tests with coverage" run: "go run mage.go test:unitCover" - name: "Coverage" @@ -90,7 +90,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Steelthread tests" run: "go run mage.go test:steelthread" @@ -102,7 +102,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 with: username: "${{ env.DOCKERHUB_PUBLIC_USER }}" @@ -128,7 +128,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -162,7 +162,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -197,7 +197,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -232,7 +232,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -267,7 +267,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -302,7 +302,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 if: | needs.paths-filter.outputs.codechange == 'true' - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main if: | needs.paths-filter.outputs.codechange == 'true' - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 @@ -336,7 +336,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main with: go-version-file: "e2e/go.mod" cache-dependency-path: "e2e/go.sum" @@ -357,7 +357,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main with: go-version-file: "tools/analyzers/go.mod" cache-dependency-path: "tools/analyzers/go.sum" @@ -371,7 +371,7 @@ jobs: needs.paths-filter.outputs.codechange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Disable AppArmor" if: "runner.os == 'Linux'" @@ -397,7 +397,7 @@ jobs: needs.paths-filter.outputs.protochange == 'true' steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Generate Protos" run: "go run mage.go gen:proto" - uses: "chainguard-dev/actions/nodiff@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d" # main diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index f04f6fce4..6ef2f34f2 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -18,7 +18,7 @@ jobs: runs-on: "depot-ubuntu-24.04-small" steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Check Licenses" uses: "authzed/actions/go-license-check@11667c9b2e8b3649ad2af4d788e57d18f8e8eaf1" # main with: @@ -28,7 +28,7 @@ jobs: runs-on: "depot-ubuntu-24.04-4" steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Generate docs" run: "go run mage.go gen:docs" - uses: "chainguard-dev/actions/nodiff@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d" # main @@ -40,7 +40,7 @@ jobs: runs-on: "depot-ubuntu-24.04-4" steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Lint Everything" run: "go run mage.go lint:all" - uses: "chainguard-dev/actions/nodiff@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d" # main diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index f969c17b5..e53e7a68b 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -16,7 +16,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 with: fetch-depth: 0 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Install snapcraft" run: | sudo snap install snapcraft --channel=8.x/stable --classic diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index 2f9d8578a..2bf962d8b 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -16,7 +16,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 with: fetch-depth: 0 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "nowsprinting/check-version-format-action@bb1181a02ee5d9ae4feead2842236183c85152c6" # v4.0.7 id: "version" with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 88b7073a0..b2ba6ad4a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,7 +17,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 with: fetch-depth: 0 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "nowsprinting/check-version-format-action@bb1181a02ee5d9ae4feead2842236183c85152c6" # v4.0.7 id: "version" with: diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml index aac60f2d1..e1b64ff74 100644 --- a/.github/workflows/security.yaml +++ b/.github/workflows/security.yaml @@ -36,7 +36,7 @@ jobs: steps: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "authzed/actions/codeql@11667c9b2e8b3649ad2af4d788e57d18f8e8eaf1" # main" trivy: @@ -52,7 +52,7 @@ jobs: # this is used so goreleaser generates the right version out of the tags, which we need so that # trivy does not flag an old SpiceDB version fetch-depth: 0 - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - uses: "docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef" # v3.6.0 with: username: "${{ env.DOCKERHUB_PUBLIC_USER }}" diff --git a/.github/workflows/wasm.yaml b/.github/workflows/wasm.yaml index c574fd175..aaa3f218b 100644 --- a/.github/workflows/wasm.yaml +++ b/.github/workflows/wasm.yaml @@ -15,7 +15,7 @@ jobs: - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v4.2.2 with: ref: "${{ env.GITHUB_SHA }}" - - uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main + - uses: "authzed/actions/setup-go@882cac020050006e1829bd3cb1f90f4fe1b99cd6" # main - name: "Build WASM" run: "go run mage.go build:wasm" - uses: "shogo82148/actions-upload-release-asset@8f6863c6c894ba46f9e676ef5cccec4752723c1e" # v1.9.2