--- id: railiance-platform.credential-grant.issue name: Railiance Platform credential-grant issuance namespace: railiance-platform:credential-grant version: v1 status: ready package: flexauth.railiance_platform.credential_grant actions: [issue] owner: team:platform-security fixtures: [policy_fixtures.yaml] caring: profile: caring-0.4.0-rc2 enforce: false canonical_roles: [Operator] organization_relations: [ServiceProvider] scopes: - level: Platform id: platform:credential-broker tenant: tenant:platform planes: [Identity, Secret, Audit] capabilities: [Use, Operate, Audit] exposure_modes: [Metadata] conditions: [PurposeBound, TimeLimited, Logged] restrictions: [PrivilegeEscalationBlocked, SecretAccessBlocked] activation: {mode: local} metadata: source: examples/railiance-platform/policy_package.md ttl_unit: seconds --- # Railiance Platform Credential-grant Issuance The policy evaluates non-secret grant metadata only. Duration strings such as `15m` must be parsed by the eventual wire translator into the numeric `context.requested_ttl_seconds`; Rego never infers duration units. ## Rules ```rego import future.keywords.if import future.keywords.in decision := {"effect": "allow", "reason": "credential_grant_allowed"} if { allowed } else := {"effect": "deny", "reason": first_denial} if { true } allowed if { input.action == "issue" input.resource.system == "railiance-platform" input.resource.type == "credential-grant" input.tenant == "tenant:platform" known_grant actor_type_allowed purpose_allowed delivery_mode_allowed ttl_allowed has_bound_subject } default first_denial := "no_matching_rule" first_denial := "wrong_action" if { input.action != "issue" } else := "wrong_system" if { input.resource.system != "railiance-platform" } else := "wrong_resource_type" if { input.resource.type != "credential-grant" } else := "wrong_tenant" if { input.tenant != "tenant:platform" } else := "unknown_grant" if { not known_grant } else := "actor_type_not_allowed" if { not actor_type_allowed } else := "purpose_not_allowed" if { not purpose_allowed } else := "delivery_mode_not_allowed" if { not delivery_mode_allowed } else := "ttl_out_of_bounds" if { not ttl_allowed } else := "missing_subject_binding" if { not has_bound_subject } known_grant if { is_string(input.resource.attributes.grant_id) input.resource.id == sprintf("credential-grant:%s", [input.resource.attributes.grant_id]) is_number(input.resource.attributes.max_ttl_seconds) } actor_type_allowed if { is_string(input.context.actor_type) input.context.actor_type in input.resource.attributes.allowed_actor_types } purpose_allowed if { is_string(input.context.purpose) input.context.purpose != "" input.context.purpose in input.resource.attributes.allowed_purposes } delivery_mode_allowed if { is_string(input.context.delivery_mode) input.context.delivery_mode in input.resource.attributes.allowed_delivery_modes } ttl_allowed if { is_number(input.context.requested_ttl_seconds) input.context.requested_ttl_seconds > 0 input.context.requested_ttl_seconds <= input.resource.attributes.max_ttl_seconds } has_bound_subject if { is_string(input.context.bound_subject) input.context.bound_subject != "" } ``` ## Tests ```rego test package flexauth.railiance_platform.credential_grant_test import future.keywords.if import data.flexauth.railiance_platform.credential_grant request := { "tenant": "tenant:platform", "subject": {"id": "agent:codex/railiance-platform", "type": "Agent"}, "action": "issue", "resource": { "id": "credential-grant:rapp-postgres/audit-core-runtime", "type": "credential-grant", "system": "railiance-platform", "attributes": { "grant_id": "rapp-postgres/audit-core-runtime", "max_ttl_seconds": 3600, "allowed_actor_types": ["human-operator", "approved-agent", "ci-runner"], "allowed_purposes": ["audit-core-runtime"], "allowed_delivery_modes": ["exec-env"] } }, "context": {"actor_type": "approved-agent", "bound_subject": "agent:codex/railiance-platform", "purpose": "audit-core-runtime", "delivery_mode": "exec-env", "requested_ttl_seconds": 900} } test_allow if { credential_grant.decision.effect == "allow" with input as request } test_ttl_string_denied if { credential_grant.decision.reason == "ttl_out_of_bounds" with input as object.union(request, {"context": object.union(request.context, {"requested_ttl_seconds": "15m"})}) } test_unknown_grant_denied if { credential_grant.decision.reason == "unknown_grant" with input as object.union(request, {"resource": {"id": "credential-grant:missing", "type": "credential-grant", "system": "railiance-platform", "attributes": {}}}) } ```