Skip to content

feat: RFC-008 capability class support (ALLOW path)#65

Merged
beonde merged 3 commits into
mainfrom
feat/rfc008-capability-class-allow-path
Apr 29, 2026
Merged

feat: RFC-008 capability class support (ALLOW path)#65
beonde merged 3 commits into
mainfrom
feat/rfc008-capability-class-allow-path

Conversation

@beonde
Copy link
Copy Markdown
Member

@beonde beonde commented Apr 29, 2026

Summary

Adds RFC-008 §5.5 capability class support to capiscio-core (ALLOW path).

Changes

  • Policy config (pkg/policy/config.go): Add CapabilityClassRule struct with Class, MinTrustLevel, AllowedDIDs, DeniedDIDs fields. Dot-notation class name validation via regex.
  • Config validation: Class name format, trust level values, DID conflict detection, duplicate class detection. 7 test functions with 14+ subtests.
  • PIP types (pkg/pip/types.go): Add DenyOnUnknownClass *bool to DecisionRequest.
  • OPA client (pkg/pdp/opa_client.go): Wire DenyOnUnknownClass into OPA input.
  • Proto (proto/capiscio/v1/mcp.proto): Add field 15 optional bool deny_on_unknown_class to EvaluateToolAccessRequest.
  • gRPC handler (internal/rpc/mcp_service.go): Wire CapabilityClass and DenyOnUnknownClass into EvaluateToolAccessInput.
  • MCP service (pkg/mcp/service.go): Extend EvaluateToolAccessInput with CapabilityClass and DenyOnUnknownClass.

Linked PRs

  • capiscio-server: feat/rfc008-capability-class-allow-path
  • capiscio-mcp-python: feat/rfc008-capability-class-allow-path
  • capiscio-ui: feat/rfc008-capability-class-allow-path

Testing

  • All existing tests pass
  • New tests: 7 test functions covering parsing, validation, serialization

- Add CapabilityClassRule struct to policy config with dot-notation class names
- Add config validation for class names, trust levels, DID conflicts, duplicates
- Add DenyOnUnknownClass field to PIP DecisionRequest
- Wire capability_class and deny_on_unknown_class through buildOPAInput
- Add proto field 15 (optional bool deny_on_unknown_class) to EvaluateToolAccessRequest
- Wire gRPC handler to pass capability_class and deny_on_unknown_class to EvaluateToolAccessInput
- Add CapabilityClass and DenyOnUnknownClass fields to mcp.EvaluateToolAccessInput
- Add comprehensive tests for config parsing, validation (14+ subtests), and ToMap serialization

Part of: RFC-008 §5.5 capability class enforcement
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 68.75000% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/rpc/mcp_service.go 0.00% 9 Missing ⚠️
pkg/pdp/opa_client.go 0.00% 1 Missing and 1 partial ⚠️
pkg/policy/config.go 94.28% 1 Missing and 1 partial ⚠️
pkg/rpc/gen/capiscio/v1/mcp.pb.go 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds RFC-008 “capability class” support plumbing (ALLOW path) across policy config, PIP/PDP input, and the MCP gRPC surface so callers can scope policy by capability class and control “unknown class” behavior.

Changes:

  • Extend policy config schema/validation to support capability_classes rules and serialize them into the OPA data document.
  • Add deny_on_unknown_class to PIP DecisionRequest and wire it into OPA input construction.
  • Extend MCP proto + server handler + service input types to carry deny_on_unknown_class (and capability class).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
proto/capiscio/v1/mcp.proto Adds optional bool deny_on_unknown_class = 15 to the MCP EvaluateToolAccess request.
pkg/rpc/gen/capiscio/v1/mcp.pb.go Regenerated Go bindings for the proto change.
pkg/policy/config.go Adds CapabilityClassRule, validation (regex, trust levels, DID conflicts), and capability_classes serialization in ToMap.
pkg/policy/config_test.go Adds parsing/validation/serialization tests for capability classes.
pkg/pip/types.go Adds DenyOnUnknownClass *bool to DecisionRequest.
pkg/pdp/opa_client.go Includes deny_on_unknown_class in OPA input when present.
pkg/mcp/service.go Extends EvaluateToolAccessInput with CapabilityClass and DenyOnUnknownClass.
internal/rpc/mcp_service.go Wires request fields into EvaluateToolAccessInput.
Comments suppressed due to low confidence (1)

pkg/mcp/service.go:58

  • EvaluateToolAccessInput now carries CapabilityClass and DenyOnUnknownClass, but Service.EvaluateToolAccess ignores both when calling guard.EvaluateToolAccess (it only forwards toolName/paramsHash/origin/credential/config). This means the new RFC-008 fields never affect PDP input / policy decisions. Consider extending the guard/service evaluation path to propagate these fields into the PIP DecisionRequest (e.g., Action.CapabilityClass and top-level deny_on_unknown_class) so the ALLOW-path behavior is actually enforced.
// EvaluateToolAccess evaluates tool access using RFC-006 §6.2-6.4
func (s *Service) EvaluateToolAccess(
	ctx context.Context,
	input *EvaluateToolAccessInput,
) (*EvaluateResult, error) {
	return s.guard.EvaluateToolAccess(
		ctx,
		input.ToolName,
		input.ParamsHash,
		input.Origin,
		input.Credential,
		input.Config,
	)
}

Comment thread pkg/policy/config.go Outdated
Comment on lines +69 to +71
// capabilityClassPattern validates RFC-008 §7.1 dot-notation class names.
// Allowed characters: lowercase letters, digits, hyphens, and dots as separators.
var capabilityClassPattern = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$`)
Comment thread pkg/policy/config.go Outdated
Comment on lines +177 to +181
}
if ccSeen[cc.Class] {
errs = append(errs, fmt.Sprintf("capability_classes[%d]: duplicate class %q", i, cc.Class))
}
ccSeen[cc.Class] = true
Comment thread proto/capiscio/v1/mcp.proto Outdated
string constraints_json = 13; // reserved for envelope
string parent_constraints_json = 14; // reserved for envelope

// RFC-008: PEP-level unknown capability class behavior (default: deny)
beonde added 2 commits April 29, 2026 17:03
- Reuse envelope.ValidateCapabilityClass() instead of local regex
  (fixes regex mismatch: policy allowed hyphens, envelope allowed underscores)
- Extract validateCapabilityClasses() helper to reduce cyclomatic complexity
- Fix duplicate-class detection to skip empty/invalid class names
- Clarify proto deny_on_unknown_class comment re: proto3 bool defaults
- Update tests to use RFC-compliant names (underscores, not hyphens)
Copilot AI review requested due to automatic review settings April 29, 2026 21:24
@beonde beonde merged commit 794e3b9 into main Apr 29, 2026
7 checks passed
@beonde beonde deleted the feat/rfc008-capability-class-allow-path branch April 29, 2026 21:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds RFC-008 capability class support plumbing across policy config, MCP RPC/API surfaces, and PDP/OPA input to enable “ALLOW path” capability-class-aware authorization decisions.

Changes:

  • Extend policy config schema with capability_classes rules + validation and ToMap serialization.
  • Add deny_on_unknown_class (presence-aware) to MCP proto and wire it through MCP RPC types.
  • Add DenyOnUnknownClass to PIP DecisionRequest and include it in OPA input construction.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
proto/capiscio/v1/mcp.proto Adds optional bool deny_on_unknown_class = 15 with documented fail-closed intent.
pkg/rpc/gen/capiscio/v1/mcp.pb.go Regenerated Go bindings to include presence-aware DenyOnUnknownClass *bool.
pkg/policy/config.go Introduces CapabilityClassRule, validates class names via envelope.ValidateCapabilityClass, serializes to OPA data map.
pkg/policy/config_test.go Adds parsing/validation/serialization tests for capability classes.
pkg/pip/types.go Extends PDP request model with DenyOnUnknownClass *bool.
pkg/pdp/opa_client.go Adds deny_on_unknown_class to OPA input when explicitly set.
pkg/mcp/service.go Extends MCP service input type with CapabilityClass and DenyOnUnknownClass.
internal/rpc/mcp_service.go Maps proto request fields into MCP service input.

Comment thread pkg/mcp/service.go
Comment on lines +41 to 43
CapabilityClass string // RFC-008: capability class for policy evaluation
DenyOnUnknownClass *bool // RFC-008: PEP-level unknown class behavior (nil = deny)
}
Comment on lines +166 to +170
Credential: cred,
Config: config,
CapabilityClass: req.CapabilityClass,
DenyOnUnknownClass: req.DenyOnUnknownClass,
}
Comment thread pkg/pdp/opa_client.go
Comment on lines +196 to +199
// RFC-008: PEP-level flag for unknown capability class behavior
if req.DenyOnUnknownClass != nil {
input["deny_on_unknown_class"] = *req.DenyOnUnknownClass
}
Comment on lines +85 to +87
// Proto3 default for bool is false, but the server treats an unset field
// as "deny" (fail-closed). Set explicitly to false to allow unknown classes
// (e.g. in development/staging environments).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants