Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attach source code to certain errors #1351

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cedar-policy-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ stacker = "0.1.15"
arbitrary = { version = "1", features = ["derive"], optional = true }
miette = { version = "7.4.0", features = ["serde"] }
nonempty = "0.10.0"
educe = "0.6.0"

# decimal extension requires regex
regex = { version = "1.8", features = ["unicode"], optional = true }
Expand Down
66 changes: 41 additions & 25 deletions cedar-policy-core/src/ast/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use crate::ast::*;
use crate::parser::Loc;
use educe::Educe;
use itertools::Itertools;
use miette::Diagnostic;
use nonempty::{nonempty, NonEmpty};
Expand Down Expand Up @@ -1495,10 +1496,10 @@ impl PrincipalConstraint {
/// Fill in the Slot, if any, with the given EUID
pub fn with_filled_slot(self, euid: Arc<EntityUID>) -> Self {
match self.constraint {
PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => Self {
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => Self {
constraint: PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)),
},
PrincipalOrResourceConstraint::In(EntityReference::Slot) => Self {
PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => Self {
constraint: PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)),
},
_ => self,
Expand Down Expand Up @@ -1626,10 +1627,10 @@ impl ResourceConstraint {
/// Fill in the Slot, if any, with the given EUID
pub fn with_filled_slot(self, euid: Arc<EntityUID>) -> Self {
match self.constraint {
PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => Self {
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => Self {
constraint: PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)),
},
PrincipalOrResourceConstraint::In(EntityReference::Slot) => Self {
PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => Self {
constraint: PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)),
},
_ => self,
Expand Down Expand Up @@ -1672,12 +1673,19 @@ impl From<&ResourceConstraint> for proto::ResourceConstraint {
}

/// A reference to an EntityUID that may be a Slot
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[derive(Educe, Serialize, Deserialize, Clone, Debug, Eq)]
#[educe(Hash, PartialEq, PartialOrd, Ord)]
pub enum EntityReference {
/// Reference to a literal EUID
EUID(Arc<EntityUID>),
/// Template Slot
Slot,
Slot(
#[serde(skip)]
#[educe(PartialEq(ignore))]
#[educe(PartialOrd(ignore))]
#[educe(Hash(ignore))]
Option<Loc>,
),
}

impl EntityReference {
Expand All @@ -1694,7 +1702,9 @@ impl EntityReference {
pub fn into_expr(&self, slot: SlotId) -> Expr {
match self {
EntityReference::EUID(euid) => Expr::val(euid.clone()),
EntityReference::Slot => Expr::slot(slot),
EntityReference::Slot(loc) => {
Expr::slot(slot).with_maybe_source_loc(loc.as_ref().cloned())
}
}
}
}
Expand All @@ -1713,7 +1723,7 @@ impl From<&proto::EntityReference> for EntityReference {
match proto::entity_reference::Ty::try_from(ty.to_owned())
.expect("decode should succeed")
{
proto::entity_reference::Ty::Slot => EntityReference::Slot,
proto::entity_reference::Ty::Slot => EntityReference::Slot(None),
}
}
proto::entity_reference::Data::Euid(euid) => {
Expand All @@ -1732,7 +1742,7 @@ impl From<&EntityReference> for proto::EntityReference {
euid.as_ref(),
))),
},
EntityReference::Slot => Self {
EntityReference::Slot(_) => Self {
data: Some(proto::entity_reference::Data::Ty(
proto::entity_reference::Ty::Slot.into(),
)),
Expand All @@ -1758,6 +1768,12 @@ impl Diagnostic for UnexpectedSlotError {
}),
}
}

fn source_code(&self) -> Option<&dyn miette::SourceCode> {
match self {
Self::FoundSlot(Slot { loc, .. }) => loc.as_ref().map(|l| l as &dyn miette::SourceCode),
}
}
}

impl From<EntityUID> for EntityReference {
Expand Down Expand Up @@ -1825,12 +1841,12 @@ impl PrincipalOrResourceConstraint {

/// Constrained to equal a slot
pub fn is_eq_slot() -> Self {
PrincipalOrResourceConstraint::Eq(EntityReference::Slot)
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None))
}

/// Constrained to be in a slot
pub fn is_in_slot() -> Self {
PrincipalOrResourceConstraint::In(EntityReference::Slot)
PrincipalOrResourceConstraint::In(EntityReference::Slot(None))
}

/// Hierarchical constraint.
Expand All @@ -1840,7 +1856,7 @@ impl PrincipalOrResourceConstraint {

/// Type constraint additionally constrained to be in a slot.
pub fn is_entity_type_in_slot(entity_type: Arc<EntityType>) -> Self {
PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot)
PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot(None))
}

/// Type constraint with a hierarchical constraint.
Expand Down Expand Up @@ -1901,11 +1917,11 @@ impl PrincipalOrResourceConstraint {
match self {
PrincipalOrResourceConstraint::Any => None,
PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)) => Some(euid),
PrincipalOrResourceConstraint::In(EntityReference::Slot) => None,
PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => None,
PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)) => Some(euid),
PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => None,
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => None,
PrincipalOrResourceConstraint::IsIn(_, EntityReference::EUID(euid)) => Some(euid),
PrincipalOrResourceConstraint::IsIn(_, EntityReference::Slot) => None,
PrincipalOrResourceConstraint::IsIn(_, EntityReference::Slot(_)) => None,
PrincipalOrResourceConstraint::Is(_) => None,
}
}
Expand Down Expand Up @@ -2315,9 +2331,9 @@ pub(crate) mod test_generators {
let v = vec![
PrincipalOrResourceConstraint::any(),
PrincipalOrResourceConstraint::is_eq(euid.clone()),
PrincipalOrResourceConstraint::Eq(EntityReference::Slot),
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)),
PrincipalOrResourceConstraint::is_in(euid),
PrincipalOrResourceConstraint::In(EntityReference::Slot),
PrincipalOrResourceConstraint::In(EntityReference::Slot(None)),
];

v.into_iter()
Expand Down Expand Up @@ -2601,15 +2617,15 @@ mod test {
Some(&e)
);
assert_eq!(
PrincipalOrResourceConstraint::In(EntityReference::Slot).get_euid(),
PrincipalOrResourceConstraint::In(EntityReference::Slot(None)).get_euid(),
None
);
assert_eq!(
PrincipalOrResourceConstraint::Eq(EntityReference::EUID(e.clone())).get_euid(),
Some(&e)
);
assert_eq!(
PrincipalOrResourceConstraint::Eq(EntityReference::Slot).get_euid(),
PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)).get_euid(),
None
);
assert_eq!(
Expand All @@ -2627,7 +2643,7 @@ mod test {
assert_eq!(
PrincipalOrResourceConstraint::IsIn(
Arc::new("T".parse().unwrap()),
EntityReference::Slot
EntityReference::Slot(None)
)
.get_euid(),
None
Expand Down Expand Up @@ -2688,7 +2704,7 @@ mod test {

#[test]
fn euid_into_expr() {
let e = EntityReference::Slot;
let e = EntityReference::Slot(None);
assert_eq!(
e.into_expr(SlotId::principal()),
Expr::slot(SlotId::principal())
Expand All @@ -2702,7 +2718,7 @@ mod test {

#[test]
fn por_constraint_display() {
let t = PrincipalOrResourceConstraint::Eq(EntityReference::Slot);
let t = PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None));
let s = t.display(PrincipalOrResource::Principal);
assert_eq!(s, "principal == ?principal");
let t = PrincipalOrResourceConstraint::Eq(EntityReference::euid(Arc::new(
Expand All @@ -2720,7 +2736,7 @@ mod test {
"expected a static policy, got a template containing the slot ?principal"
)
.help("try removing the template slot(s) from this policy")
.exactly_one_underline("permit(principal == ?principal, action, resource);")
.exactly_one_underline("?principal")
.build()
);
});
Expand Down Expand Up @@ -2775,8 +2791,8 @@ mod test {
EntityReference::from(&proto::EntityReference::from(&er1))
);
assert_eq!(
EntityReference::Slot,
EntityReference::from(&proto::EntityReference::from(&EntityReference::Slot))
EntityReference::Slot(None),
EntityReference::from(&proto::EntityReference::from(&EntityReference::Slot(None)))
);

let read_euid: Arc<EntityUID> = Arc::new(EntityUID::with_eid("read"));
Expand Down
6 changes: 3 additions & 3 deletions cedar-policy-core/src/error_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ macro_rules! impl_diagnostic_from_source_loc_field {
/// of a field of type `Option<Loc>`
#[macro_export]
macro_rules! impl_diagnostic_from_source_loc_opt_field {
( $i:ident ) => {
( $($id:ident).+ ) => {
fn source_code(&self) -> Option<&dyn miette::SourceCode> {
self.$i
self.$($id).+
.as_ref()
.map(|loc| &loc.src as &dyn miette::SourceCode)
}

fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
self.$i
self.$($id).+
.as_ref()
.map(|loc| Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _)
}
Expand Down
20 changes: 10 additions & 10 deletions cedar-policy-core/src/est/scope_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => {
PrincipalConstraint::Eq(EqConstraint::Slot {
slot: ast::SlotId::principal(),
})
Expand All @@ -610,7 +610,7 @@ impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => {
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::principal(),
})
Expand All @@ -622,7 +622,7 @@ impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
},
ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::principal(),
},
}),
Expand All @@ -647,7 +647,7 @@ impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => {
ResourceConstraint::Eq(EqConstraint::Slot {
slot: ast::SlotId::resource(),
})
Expand All @@ -657,7 +657,7 @@ impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => {
ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::resource(),
})
Expand All @@ -669,7 +669,7 @@ impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
},
ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::resource(),
},
}),
Expand Down Expand Up @@ -700,7 +700,7 @@ impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => {
if slot == ast::SlotId::principal() {
Ok(ast::PrincipalOrResourceConstraint::Eq(
ast::EntityReference::Slot,
ast::EntityReference::Slot(None),
))
} else {
Err(Self::Error::InvalidSlotName)
Expand All @@ -714,7 +714,7 @@ impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
if slot == ast::SlotId::principal() {
Ok(ast::PrincipalOrResourceConstraint::In(
ast::EntityReference::Slot,
ast::EntityReference::Slot(None),
))
} else {
Err(Self::Error::InvalidSlotName)
Expand Down Expand Up @@ -765,7 +765,7 @@ impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
ResourceConstraint::Eq(EqConstraint::Slot { slot }) => {
if slot == ast::SlotId::resource() {
Ok(ast::PrincipalOrResourceConstraint::Eq(
ast::EntityReference::Slot,
ast::EntityReference::Slot(None),
))
} else {
Err(Self::Error::InvalidSlotName)
Expand All @@ -779,7 +779,7 @@ impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
if slot == ast::SlotId::resource() {
Ok(ast::PrincipalOrResourceConstraint::In(
ast::EntityReference::Slot,
ast::EntityReference::Slot(None),
))
} else {
Err(Self::Error::InvalidSlotName)
Expand Down
2 changes: 1 addition & 1 deletion cedar-policy-core/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ pub(crate) mod test_utils {
msg: &ExpectedErrorMessage<'_>,
) {
assert!(
errs.iter().any(|e| msg.matches(Some(src), e)),
errs.iter().any(|e| msg.matches(e)),
"for the following input:\n{src}\nexpected some error to match the following:\n{msg}\nbut actual errors were:\n{:?}", // the Debug representation of `miette::Report` is the pretty one, for some reason
miette::Report::new(errs.clone()),
);
Expand Down
Loading
Loading