feat: expose grant schema for UI linting support (#6470)

This commit is contained in:
Bharath Gajjala authored and GitHub committed 2026-03-18 09:49:16 -05:00
1 parent 0f9307c0ae
commit 8dae2ee45b
3 files changed
+188

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
// Copyright IBM Corp. 2020, 2025
// SPDX-License-Identifier: BUSL-1.1
package perms
import (
"context"
"encoding/json"
"fmt"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
)
// GrantSchema represents the schema of grants in the system,
// including the resource types and their associated actions, scopes.
type GrantSchema struct {
ResourceTypes []ResourceTypeSchema `json:"resource_types"`
}
type ResourceTypeSchema struct {
// Type is the string representation of the resource type
Type string `json:"type"`
// The collection actions that are valid for this resource type
CollectionActions []string `json:"collection_actions,omitempty"`
// The id actions that are valid for this resource type
IdActions []string `json:"id_actions,omitempty"`
// The scopes that are valid for this resource type
Scopes []string `json:"scopes,omitempty"`
// The ID prefixes that are valid for this resource type
IdPrefixes []string `json:"id_prefixes,omitempty"`
// The parent resource type, if any, omitted if no parent
ParentType string `json:"parent_type,omitempty"`
}
// BuildGrantSchema constructs the full grant schema from the registered
// resource types, actions, and scope definitions.
func BuildGrantSchema(ctx context.Context) (*GrantSchema, error) {
const op = "perms.BuildGrantSchema"
schema := &GrantSchema{}
for name, typ := range resource.Map {
// Skip resource types that aren't real grantable resources
// These types will fail further lookups and aren't useful to include in the schema
if typ == resource.Unknown || typ == resource.All || typ == resource.Controller {
continue
}
// Collect all collection actions
colActions, err := action.CollectionActionSetForResource(typ)
if err != nil {
return nil, fmt.Errorf("%s: error getting collection actions for %q: %w", op, name, err)
}
var colStrs []string
for a := range colActions {
colStrs = append(colStrs, a.String())
}
// Collect all id actions
idActions, err := action.IdActionSetForResource(typ)
if err != nil {
return nil, fmt.Errorf("%s: error getting id actions for %q: %w", op, name, err)
}
var idStrs []string
for a := range idActions {
if a == action.NoOp {
continue
}
idStrs = append(idStrs, a.String())
}
// Collect all scopes that can be applied to this resource type
scopes, err := scope.AllowedIn(ctx, typ)
if err != nil {
return nil, fmt.Errorf("%s: error getting allowed scopes for %q: %w", op, name, err)
}
var scopeStrs []string
for _, s := range scopes {
scopeStrs = append(scopeStrs, s.String())
}
// Parent type is the resource's parent if one exists,
// otherwise this will be an empty string.
var parentType string
if parent := typ.Parent(); parent != typ {
parentType = parent.String()
}
schema.ResourceTypes = append(schema.ResourceTypes, ResourceTypeSchema{
Type: name,
CollectionActions: colStrs,
IdActions: idStrs,
Scopes: scopeStrs,
IdPrefixes: globals.ResourcePrefixesFromType(typ),
ParentType: parentType,
})
}
return schema, nil
}
// BuildGrantSchemaJSON builds the grant schema and marshals it to JSON
func BuildGrantSchemaJSON(ctx context.Context) ([]byte, error) {
schema, err := BuildGrantSchema(ctx)
if err != nil {
return nil, err
}
return json.Marshal(schema)
}
+51
View File
@@ -0,0 +1,51 @@
// Copyright IBM Corp. 2020, 2025
// SPDX-License-Identifier: BUSL-1.1
package perms_test
import (
"context"
"encoding/json"
"testing"
"github.com/hashicorp/boundary/internal/perms"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
// Import to trigger init() registrations in all service handlers
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/accounts"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/aliases"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/authmethods"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/authtokens"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/billing"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentiallibraries"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentials"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentialstores"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/groups"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_catalogs"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_sets"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/hosts"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/managed_groups"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/policies"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/scopes"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/session_recordings"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/storage_buckets"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
)
func TestBuildGrantSchema(t *testing.T) {
ctx := context.Background()
schema, err := perms.BuildGrantSchema(ctx)
require.NoError(t, err)
require.NotNil(t, schema)
assert.NotEmpty(t, schema.ResourceTypes, "resource types should not be empty")
// JSON serialization should produce valid JSON
data, err := perms.BuildGrantSchemaJSON(ctx)
require.NoError(t, err)
assert.True(t, json.Valid(data), "output should be valid JSON")
}