Skip to content

Commit c9ac0c8

Browse files
committed
Add unknown_entities method to PartialResponse
Introduces unknown_entities method to the PartialResponse. Signed-off-by: Vlad <[email protected]>
1 parent 5dd810b commit c9ac0c8

File tree

4 files changed

+67
-15
lines changed

4 files changed

+67
-15
lines changed

cedar-policy-core/src/ast/policy.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ use miette::Diagnostic;
2323
use nonempty::{nonempty, NonEmpty};
2424
use serde::{Deserialize, Serialize};
2525
use smol_str::SmolStr;
26-
use std::{collections::HashMap, sync::Arc};
26+
use std::{
27+
collections::{HashMap, HashSet},
28+
str::FromStr,
29+
sync::Arc,
30+
};
2731
use thiserror::Error;
2832

2933
#[cfg(feature = "wasm")]
@@ -581,6 +585,25 @@ impl Policy {
581585
pub fn is_static(&self) -> bool {
582586
self.link.is_none()
583587
}
588+
589+
/// Returns all the unknown entities in the policy during evaluation
590+
pub fn unknown_entities(&self) -> HashSet<EntityUID> {
591+
self.condition()
592+
.unknowns()
593+
.filter_map(
594+
|Unknown {
595+
name,
596+
type_annotation,
597+
}| {
598+
if matches!(type_annotation, Some(Type::Entity { .. })) {
599+
EntityUID::from_str(name.as_str()).ok()
600+
} else {
601+
None
602+
}
603+
},
604+
)
605+
.collect()
606+
}
584607
}
585608

586609
impl std::fmt::Display for Policy {

cedar-policy/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Cedar Language Version: TBD
2626
edge cases, policies that previously failed to validate under strict validation
2727
will now pass validation, probably with an `ImpossiblePolicy` warning. (#1355,
2828
resolving #638)
29+
- Added `PartialResponse::unknown_entities` method (#1557)
2930

3031
### Added
3132

cedar-policy/src/api.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,15 @@ impl PartialResponse {
10591059
self.0.all_residuals().map(Policy::from_ast)
10601060
}
10611061

1062+
/// Returns all unknown entities during the evaluation of the response
1063+
pub fn unknown_entities(&self) -> HashSet<EntityUid> {
1064+
let mut entity_uids = HashSet::new();
1065+
for policy in self.0.all_residuals() {
1066+
entity_uids.extend(policy.unknown_entities().into_iter().map(Into::into));
1067+
}
1068+
entity_uids
1069+
}
1070+
10621071
/// Return the residual for a given [`PolicyId`], if it exists in the response
10631072
pub fn get(&self, id: &PolicyId) -> Option<Policy> {
10641073
self.0.get(id.as_ref()).map(Policy::from_ast)
@@ -3569,20 +3578,9 @@ impl Policy {
35693578
#[cfg(feature = "partial-eval")]
35703579
pub fn unknown_entities(&self) -> HashSet<EntityUid> {
35713580
self.ast
3572-
.condition()
3573-
.unknowns()
3574-
.filter_map(
3575-
|ast::Unknown {
3576-
name,
3577-
type_annotation,
3578-
}| {
3579-
if matches!(type_annotation, Some(ast::Type::Entity { .. })) {
3580-
EntityUid::from_str(name.as_str()).ok()
3581-
} else {
3582-
None
3583-
}
3584-
},
3585-
)
3581+
.unknown_entities()
3582+
.into_iter()
3583+
.map(Into::into)
35863584
.collect()
35873585
}
35883586

cedar-policy/src/test/test.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,36 @@ mod policy_set_tests {
810810
.contains(&"test_entity_type::\"unknown\"".parse().unwrap()));
811811
}
812812

813+
#[cfg(feature = "partial-eval")]
814+
#[test]
815+
fn partial_response_unknown_entities() {
816+
let authorizer = Authorizer::new();
817+
let request = Request::new(
818+
EntityUid::from_strs("Test", "test"),
819+
EntityUid::from_strs("Action", "a"),
820+
EntityUid::from_strs("Resource", "b"),
821+
Context::empty(),
822+
None,
823+
)
824+
.unwrap();
825+
826+
let entities = Entities::default().partial();
827+
828+
let mut pset = PolicySet::new();
829+
let static_policy = Policy::parse(
830+
Some(PolicyId::new("id")),
831+
"permit(principal,action,resource) when {principal.foo == 1};",
832+
)
833+
.expect("Failed to parse");
834+
pset.add(static_policy).expect("Failed to add");
835+
836+
let response = authorizer.is_authorized_partial(&request, &pset, &entities);
837+
assert_eq!(response.unknown_entities().len(), 1);
838+
assert!(response
839+
.unknown_entities()
840+
.contains(&"Test::\"test\"".parse().unwrap()));
841+
}
842+
813843
#[test]
814844
fn unlink_linked_policy() {
815845
let template = Template::parse(

0 commit comments

Comments
 (0)