From c176a74a7cc4f64352fa313fc1ffb27b62a90cc2 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Fri, 17 Jul 2026 15:52:11 +0200 Subject: [PATCH 1/5] Group token create permissions by API method types. --- .../metalstack/api/v2/predefined_rules.proto | 23 +++++- proto/metalstack/api/v2/token.proto | 73 +++++++++++++++++-- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/proto/metalstack/api/v2/predefined_rules.proto b/proto/metalstack/api/v2/predefined_rules.proto index 5d3335ff..d897b8ac 100644 --- a/proto/metalstack/api/v2/predefined_rules.proto +++ b/proto/metalstack/api/v2/predefined_rules.proto @@ -77,8 +77,27 @@ extend buf.validate.StringRules { // IsTenantLogin returns true if name field satisfies our requirements optional bool is_tenant_login = 80048962 [(buf.validate.predefined).cel = { id: "string.is_tenant_login" - message: "must be within 2 and 256 characters" - expression: "this.size() >= 2 && this.size() <= 256" + message: "must be within 2 and 128 characters" + expression: "this.size() >= 2 && this.size() <= 128" + }]; + + // IsTenantSubjectPermission returns true if name field satisfies our requirements + optional bool is_tenant_subject_permission = 80048963 [(buf.validate.predefined).cel = { + id: "string.is_tenant_subject_permission" + message: "must be '*' or within 2 and 128 characters " + expression: "this == '*' || this.size() >= 2 && this.size() <= 128" + }]; + // IsProjectSubjectPermission returns true if name field satisfies our requirements + optional bool is_project_subject_permission = 80048964 [(buf.validate.predefined).cel = { + id: "string.is_project_subject_permission" + message: "must be '*' or within 2 and 128 characters " + expression: "this == '*' || this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')" + }]; + // IsMachineSubjectPermission returns true if name field satisfies our requirements + optional bool is_machine_subject_permission = 80048965 [(buf.validate.predefined).cel = { + id: "string.is_machine_subject_permission" + message: "must be '*' or within 2 and 128 characters " + expression: "this == '*' || this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')" }]; } diff --git a/proto/metalstack/api/v2/token.proto b/proto/metalstack/api/v2/token.proto index 0f061dd8..db327c91 100644 --- a/proto/metalstack/api/v2/token.proto +++ b/proto/metalstack/api/v2/token.proto @@ -146,15 +146,74 @@ message TokenServiceCreateRequest { Labels labels = 9; } -// MethodPermission is a mapping from a subject/project to a service method +// MethodPermission contains service method permissions message MethodPermission { - // Subject maybe either the project or the tenant - // for which the methods should be allowed - // + // PermissionType defines the type of the method permission + oneof permissiontype { + // PublicPermissions carries public method permissions + PublicPermissions public = 1; + // SelfPermissions carries self method permissions + SelfPermissions self = 2; + // ProjectPermissions carries project method permissions + ProjectPermissions project = 3; + // TenantPermissions carries tenant method permissions + TenantPermissions tenant = 4; + // AdminPermissions carries admin method permissions + AdminPermissions admin = 5; + // MachinePermissions carries machine method permissions + MachinePermissions machine = 6; + // InfraPermissions carries infra method permissions + InfraPermissions infra = 7; + } +} + +// PublicPermissions carries public method permissions +message PublicPermissions { + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// SelfPermissions carries self method permissions +message SelfPermissions { + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// ProjectPermissions carries project method permissions +message ProjectPermissions { + // asterisk (*) can be specified to match any subject + string project = 1 [(buf.validate.field).string.(metalstack.api.v2.is_project_subject_permission) = true]; + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// TenantPermissions carries tenant method permissions +message TenantPermissions { + // Login of the tenant // asterisk (*) can be specified to match any subject - // empty string ("") can be specified for requests that do not require a subject, e.g. partition list - // otherwise either a projectid or a tenant login should be specified - string subject = 1 [(buf.validate.field).string = {max_len: 256}]; + string login = 1 [(buf.validate.field).string.(metalstack.api.v2.is_tenant_subject_permission) = true]; + + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// AdminPermissions carries admin method permissions +message AdminPermissions { + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// MachinePermissions carries machine method permissions +message MachinePermissions { + // UUID of this machine + // asterisk (*) can be specified to match any subject + string uuid = 1 [(buf.validate.field).string.(metalstack.api.v2.is_machine_subject_permission) = true]; + // Methods which should be accessible + repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; +} + +// InfraPermissions carries infra method permissions +message InfraPermissions { // Methods which should be accessible repeated string methods = 2 [(buf.validate.field).repeated.max_items = 500]; } From d025923913c872b8c8d361c45aad330dbe41cba3 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Mon, 20 Jul 2026 09:28:35 +0200 Subject: [PATCH 2/5] Add tests. --- doc/index.html | 299 ++++++- go/metalstack/api/v2/predefined_rules.pb.go | 104 ++- go/metalstack/api/v2/token.pb.go | 801 ++++++++++++++---- go/tests/validation/image_test.go | 4 +- go/tests/validation/network_test.go | 4 +- go/tests/validation/token_test.go | 79 +- js/metalstack/api/v2/predefined_rules_pb.d.ts | 18 + js/metalstack/api/v2/predefined_rules_pb.js | 38 +- js/metalstack/api/v2/predefined_rules_pb.ts | 44 +- js/metalstack/api/v2/token_pb.d.ts | 214 ++++- js/metalstack/api/v2/token_pb.js | 61 +- js/metalstack/api/v2/token_pb.ts | 262 +++++- .../metalstack/api/v2/predefined_rules.proto | 8 +- .../metalstack/api/v2/predefined_rules_pb2.py | 12 +- .../api/v2/predefined_rules_pb2.pyi | 6 + python/metalstack/api/v2/token_pb2.py | 100 ++- python/metalstack/api/v2/token_pb2.pyi | 66 +- 17 files changed, 1806 insertions(+), 314 deletions(-) diff --git a/doc/index.html b/doc/index.html index 6e7b44fc..7548641d 100644 --- a/doc/index.html +++ b/doc/index.html @@ -264,6 +264,18 @@

Table of Contents

XFile-level Extensions +
  • + XFile-level Extensions +
  • + +
  • + XFile-level Extensions +
  • + +
  • + XFile-level Extensions +
  • + @@ -450,10 +462,38 @@

    Table of Contents

    metalstack/api/v2/token.proto