--- id: forgejo.application-access name: Forgejo authenticated application access namespace: forgejo:application version: v1 status: draft package: flexauth.forgejo.application allow_ttl: 10s actions: [application.access] owner: railiance-apps caring: profile: caring-0.4.0-rc2 enforce: false --- This source policy enforces the original three-group any-of in the sole PDP. The registry identifies the application tenant and admitted issuer. Fresh identity and UserInfo facts arrive only in request context from the admitted Forgejo caller, which verifies issuer JOSE and current UserInfo before this request. They are not static subject registry attributes. This policy requires aal2 assurance. The PEP independently verifies the ID token and supplies fresh UserInfo groups; the authenticated workload caller may represent only the Forgejo system. A decision authorizes one login callback, never a later HTTP/Git/SSH/API operation. The accompanying registry is synthetic test data, not an estate admission. ```rego import rego.v1 default decision := {"effect": "deny", "reason": "application_access_refused"} original_groups := {"forge-admins", "forge-coulomb-owners", "forge-coulomb-readers"} decision := {"effect": "allow", "reason": "current_authenticated_application_access"} if { input.action == "application.access" object.get(input, "purpose", "") == "" input.resource.id == "application:forgejo" input.resource.type == "application" input.resource.system == "forgejo" input.tenant == input.resource.tenant input.tenant == input.resource.attributes.tenant input.subject.tenant == input.tenant input.context.identity_tenant == input.tenant input.subject.id == input.context.identity_subject input.subject.type == input.context.identity_principal_type input.subject.type == "human" input.context.identity_issuer == input.resource.attributes.identity_issuer input.context.identity_assurance == "aal2" is_array(input.context.required_groups_any_of) count(input.context.required_groups_any_of) == 3 {g | g := input.context.required_groups_any_of[_]} == original_groups is_array(input.context.current_userinfo_groups) every value in input.context.current_userinfo_groups { is_string(value) } some group in input.context.current_userinfo_groups group in original_groups is_string(input.context.decisionpep_request_nonce) count(input.context.decisionpep_request_nonce) == 64 } ``` ```rego test package flexauth.forgejo.application_test import rego.v1 import data.flexauth.forgejo.application valid_request := { "tenant": "tenant:synthetic", "subject": { "id": "user:synthetic", "type": "human", "tenant": "tenant:synthetic" }, "action": "application.access", "resource": { "id": "application:forgejo", "type": "application", "system": "forgejo", "tenant": "tenant:synthetic", "attributes": { "tenant": "tenant:synthetic", "identity_issuer": "https://issuer.invalid" } }, "context": { "identity_tenant": "tenant:synthetic", "identity_subject": "user:synthetic", "identity_principal_type": "human", "identity_issuer": "https://issuer.invalid", "identity_assurance": "aal2", "current_userinfo_groups": [ "forge-admins" ], "required_groups_any_of": [ "forge-admins", "forge-coulomb-owners", "forge-coulomb-readers" ], "decisionpep_request_nonce": "0000000000000000000000000000000000000000000000000000000000000000" } } test_original_groups_allow if { every group in ["forge-admins", "forge-coulomb-owners", "forge-coulomb-readers"] { application.decision.effect == "allow" with input as object.union(valid_request, {"context": object.union(valid_request.context, {"current_userinfo_groups": [group]})}) } } test_outsider_denied if { application.decision.effect == "deny" with input as object.union(valid_request, {"context": object.union(valid_request.context, {"current_userinfo_groups": ["outsider"]})}) } test_missing_identity_denied if { application.decision.effect == "deny" with input as object.union(object.remove(valid_request, ["context"]), {"context": object.remove(valid_request.context, ["identity_issuer"])}) } test_low_assurance_denied if { application.decision.effect == "deny" with input as object.union(valid_request, {"context": object.union(valid_request.context, {"identity_assurance": "aal1"})}) } test_changed_group_contract_denied if { application.decision.effect == "deny" with input as object.union(valid_request, {"context": object.union(valid_request.context, {"required_groups_any_of": ["outsider"]})}) } ``` ```yaml fixture [ { "id": "allowed-original-group", "request": { "tenant": "tenant:synthetic", "subject": { "id": "user:synthetic", "type": "human", "tenant": "tenant:synthetic" }, "action": "application.access", "resource": { "id": "application:forgejo", "type": "application", "system": "forgejo", "tenant": "tenant:synthetic", "attributes": { "tenant": "tenant:synthetic", "identity_issuer": "https://issuer.invalid" } }, "context": { "identity_tenant": "tenant:synthetic", "identity_subject": "user:synthetic", "identity_principal_type": "human", "identity_issuer": "https://issuer.invalid", "identity_assurance": "aal2", "current_userinfo_groups": [ "forge-admins" ], "required_groups_any_of": [ "forge-admins", "forge-coulomb-owners", "forge-coulomb-readers" ], "decisionpep_request_nonce": "0000000000000000000000000000000000000000000000000000000000000000" } }, "expect": { "effect": "allow", "reason": "current_authenticated_application_access" } }, { "id": "missing-identity-context", "request": { "tenant": "tenant:synthetic", "subject": { "id": "user:synthetic", "type": "human", "tenant": "tenant:synthetic" }, "action": "application.access", "resource": { "id": "application:forgejo", "type": "application", "system": "forgejo", "tenant": "tenant:synthetic", "attributes": { "tenant": "tenant:synthetic", "identity_issuer": "https://issuer.invalid" } }, "context": {} }, "expect": { "effect": "deny", "reason": "application_access_refused" } } ] ```