Skip to content

Add name attribute alias on Resource entities #4766

@jhrozek

Description

@jhrozek

Part of stacklok/stacklok-enterprise-platform#stacklok/stacklok-enterprise-platform#376

Description

Add a "name" attribute to Resource entities in authorizeResourceRead alongside the existing "uri" attribute, both set to the resource URI value. The enterprise Cedar schema declares "name" as the canonical attribute on all three resource types (Tool, Prompt, Resource) for consistency, but authorizeResourceRead currently only sets "uri". Without "name", enterprise-generated Cedar policies that reference resource.name on Resource entities will silently fail schema validation.

Context

The platform authorization Cedar schema (defined in the design document 02-cedar-compilation.md) uses "name" as the primary attribute for Tool, Prompt, and Resource entity types. Tool and Prompt entities already set "name" in authorizeToolCall and authorizePromptGet respectively. However, authorizeResourceRead only sets "uri" -- an OSS-specific attribute that predates the enterprise schema. Adding "name" aligns Resource entities with the other two resource types and ensures enterprise-compiled policies work correctly.

Note: CreateResourceEntity in entity.go (line 73) does set attributes["name"] = resourceID as a default, but authorizeResourceRead passes its own attributes map via mergeContexts which includes "uri" but not "name". Since the explicit attributes override the defaults during merge, the "name" from the entity factory is effectively overwritten by the attributes map that lacks it. Adding "name" explicitly in the authorizeResourceRead attributes map ensures it survives the merge.

Dependencies: None (this is an independent change)
Blocks: #4768 (group extraction integration may rely on consistent entity attributes)

Acceptance Criteria

  • authorizeResourceRead sets "name": resourceURI in the attributes map passed to CreateEntitiesForRequest
  • authorizeResourceRead retains "uri": resourceURI for backward compatibility with existing standalone Cedar policies
  • Both "name" and "uri" attributes carry the same value (the resource URI)
  • Existing tests continue to pass with no behavior change
  • New unit test verifies that a Resource entity created via authorizeResourceRead exposes both name and uri attributes with the same value
  • All tests pass
  • Code reviewed and approved

Technical Approach

Recommended Implementation

In authorizeResourceRead (around line 481 of core.go), add "name": resourceURI to the attributes map. The change is a single line addition:

Current code:

attributes := mergeContexts(map[string]interface{}{
    "uri":       resourceURI,
    "operation": "read",
    "feature":   "resource",
}, attrsMap)

Target code:

attributes := mergeContexts(map[string]interface{}{
    "name":      resourceURI,    // canonical name used by Cedar schema
    "uri":       resourceURI,    // backward-compatible alias
    "operation": "read",
    "feature":   "resource",
}, attrsMap)

This is consistent with how authorizeToolCall and authorizePromptGet already set "name" on their respective resource entities.

Patterns & Frameworks

  • Follow the existing mergeContexts pattern used by authorizeToolCall (line 407) and authorizePromptGet (line 443), both of which already include "name" in their attributes map
  • Cedar entity attribute conventions from the cedar-policy/cedar-go library -- attributes are string-keyed maps that flow through convertMapToCedarRecord
  • The "name" attribute is already declared in the Cedar schema for Resource entities (type String, required), so this change makes the OSS authorizer schema-compliant

Code Pointers

  • pkg/authz/authorizers/cedar/core.go -- authorizeResourceRead method (line ~464): the one function that needs modification. Add "name": resourceURI to the attributes map literal
  • pkg/authz/authorizers/cedar/core.go -- authorizeToolCall (line ~392): reference for how "name" is already set on Tool entities
  • pkg/authz/authorizers/cedar/core.go -- authorizePromptGet (line ~428): reference for how "name" is already set on Prompt entities
  • pkg/authz/authorizers/cedar/entity.go -- CreateResourceEntity (line 63): note that line 73 sets attributes["name"] = resourceID as a default, but this is overridden when authorizeResourceRead passes an attributes map without "name" through mergeContexts
  • pkg/authz/authorizers/cedar/core_test.go -- existing test patterns for AuthorizeWithJWTClaims with MCPFeatureResource / MCPOperationRead (line ~204)

Component Interfaces

No interface changes required. The change is purely internal -- adding one key to an attributes map literal within authorizeResourceRead. The function signature, return type, and behavior for existing callers remain identical.

// No signature change -- only the internal attributes map is modified:
func (a *Authorizer) authorizeResourceRead(
    clientID, resourceURI string,
    claimsMap map[string]interface{},
    attrsMap map[string]interface{},
) (bool, error) {
    // ... unchanged except for the attributes map literal ...
}

Testing Strategy

Unit Tests

  • Test that a Cedar policy using resource.name on a Resource entity evaluates correctly (PERMIT when name matches)
  • Test that a Cedar policy using resource.uri on a Resource entity still evaluates correctly (backward compat -- PERMIT when uri matches)
  • Test that both name and uri carry the same value (the resource URI) by writing a policy that checks resource.name == resource.uri

Integration Tests

  • The existing TestAuthorizeWithJWTClaims test case "User with specific role in array can access resource" (line ~204) continues to pass -- this validates no regression in resource read authorization

Edge Cases

  • Resource URI with special characters (the sanitizeURIForCedar function handles this for the entity ID, but the raw URI is stored in both name and uri attributes -- verify this is consistent with Tool and Prompt behavior)

Out of Scope

  • Removing the "uri" attribute (it must be kept for backward compatibility with existing standalone Cedar policies)
  • Changes to entity.go -- the CreateResourceEntity default name attribute is fine as-is; the fix is in the caller
  • Changes to other authorize* methods (authorizeToolCall, authorizePromptGet, authorizeFeatureList) -- they already handle name correctly or are not relevant
  • Cedar schema validation enforcement in the OSS authorizer (the schema is only used by the enterprise controller)

References

  • Design doc: 04-oss-changes.md -- Section 8 ("Rename uri attribute to name on Resource entities") describes this change with before/after code
  • Cedar schema: 02-cedar-compilation.md -- Section 7 ("Cedar Schema") defines Resource entity with a required name attribute of type String
  • Compatibility table: 04-oss-changes.md -- confirms resource.uri remains as alias ("Yes -- alias")

Metadata

Metadata

Assignees

Labels

authorizationgoPull requests that update go code

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions