mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: generate RBAC scope name constants (#19896)
# Generate RBAC scope name constants This PR adds a new generated file `coderd/rbac/scopes_constants_gen.go` that contains typed constants for all RBAC scope names in the format `Scope<Resource><Action>`. For example, `ScopeWorkspaceRead` for the scope "workspace:read". These constants make it easier to reference specific scopes in code without using string literals, improving type safety and making refactoring easier. The PR: - Adds a new template file `scripts/typegen/scopenames.gotmpl` - Updates the typegen script to support generating scope name constants - Updates the Makefile to include the new generated file in build targets
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
@@ -31,6 +32,9 @@ var codersdkTemplate string
|
||||
//go:embed typescript.tstmpl
|
||||
var typescriptTemplate string
|
||||
|
||||
//go:embed scopenames.gotmpl
|
||||
var scopenamesTemplate string
|
||||
|
||||
//go:embed countries.tstmpl
|
||||
var countriesTemplate string
|
||||
|
||||
@@ -96,6 +100,8 @@ func generateRBAC(tmpl string) ([]byte, error) {
|
||||
// No typescript formatting
|
||||
return src, nil
|
||||
}
|
||||
case "scopenames":
|
||||
source = scopenamesTemplate
|
||||
default:
|
||||
return nil, xerrors.Errorf("%q is not a valid RBAC template target", tmpl)
|
||||
}
|
||||
@@ -225,6 +231,37 @@ func generateRbacObjects(templateSource string) ([]byte, error) {
|
||||
"actionsList": func() []ActionDetails {
|
||||
return actionList
|
||||
},
|
||||
"actionsOf": func(d Definition) []string {
|
||||
// Extract and sort action string keys for deterministic output.
|
||||
list := make([]string, 0, len(d.Actions))
|
||||
for a := range d.Actions {
|
||||
list = append(list, string(a))
|
||||
}
|
||||
slices.Sort(list)
|
||||
return list
|
||||
},
|
||||
"allCaseList": func(defs []Definition) string {
|
||||
// Build a multi-line comma-separated list of all scope constants (including builtins)
|
||||
// suitable for use in a `case ...:` clause, without a trailing comma.
|
||||
var names []string
|
||||
// Builtins first, sourced dynamically from the rbac package to avoid drift.
|
||||
for _, n := range rbac.BuiltinScopeNames() {
|
||||
// Use typed string literals to avoid relying on constant identifiers.
|
||||
names = append(names, fmt.Sprintf("ScopeName(%q)", string(n)))
|
||||
}
|
||||
for _, d := range defs {
|
||||
res := pascalCaseName[string](d.Type)
|
||||
acts := make([]string, 0, len(d.Actions))
|
||||
for a := range d.Actions {
|
||||
acts = append(acts, string(a))
|
||||
}
|
||||
slices.Sort(acts)
|
||||
for _, a := range acts {
|
||||
names = append(names, "Scope"+res+pascalCaseName[string](a))
|
||||
}
|
||||
}
|
||||
return strings.Join(names, ",\n\t\t")
|
||||
},
|
||||
"actionEnum": func(action policy.Action) string {
|
||||
x++
|
||||
v, ok := actionMap[string(action)]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Code generated by: go run ./scripts/typegen rbac scopenames; DO NOT EDIT.
|
||||
package rbac
|
||||
|
||||
// ScopeName constants generated from policy.RBACPermissions.
|
||||
// These represent low-level "<resource>:<action>" scope names.
|
||||
// Built-in non-low-level scopes like "all" and "application_connect" remain
|
||||
// declared in code, not here, to avoid duplication.
|
||||
|
||||
const (
|
||||
{{- range $def := . }}
|
||||
{{- $Res := pascalCaseName $def.Type }}
|
||||
{{- range $act := actionsOf $def }}
|
||||
Scope{{$Res}}{{ pascalCaseName $act }} ScopeName = "{{ $def.Type }}:{{ $act }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
// Valid reports whether the ScopeName matches one of the known scope values.
|
||||
// This includes both builtin scope names and generated low-level scopes.
|
||||
// Builtins are sourced from rbac.BuiltinScopeNames() at generation time to
|
||||
// ensure changes in rbac/scopes.go remain in sync here.
|
||||
func (e ScopeName) Valid() bool {
|
||||
switch e {
|
||||
case {{ allCaseList . }}:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AllScopeNameValues returns a slice containing all known scope values,
|
||||
// including builtin and generated low-level scopes.
|
||||
func AllScopeNameValues() []ScopeName {
|
||||
return []ScopeName{
|
||||
{{ allCaseList . }},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user