Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02e47-6aac-7ee1-914d-0584c75d3c81
158 lines
4.7 KiB
Markdown
158 lines
4.7 KiB
Markdown
---
|
|
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": {}}})
|
|
}
|
|
```
|