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

Predicate on our "well-known attributes" #113

Merged
merged 26 commits into from
Oct 25, 2024
Merged

Predicate on our "well-known attributes" #113

merged 26 commits into from
Oct 25, 2024

Conversation

alexsnaps
Copy link
Member

@alexsnaps alexsnaps commented Oct 19, 2024

fix to #112

@alexsnaps
Copy link
Member Author

This may need to supersede #110 ... stil wip tho

@alexsnaps alexsnaps linked an issue Oct 21, 2024 that may be closed by this pull request
@alexsnaps
Copy link
Member Author

tl;dr this replaces PatternExpression with CEL Predicates, while keeping the former as a working fallback...

Of interest if probably this change as well, where the whole fn needs to be replace as if cfg!(test) within the method would work, but won't make the linker happy on anything but wasm...

@alexsnaps alexsnaps marked this pull request as ready for review October 21, 2024 23:04
@alexsnaps alexsnaps mentioned this pull request Aug 9, 2024
9 tasks
@eguzki eguzki added the enhancement New feature or request label Oct 22, 2024
@eguzki
Copy link
Contributor

eguzki commented Oct 22, 2024

doc missing. At the very least on README.md.

Doc about routeRuleConditions.predicates list being any or allOf

@eguzki
Copy link
Contributor

eguzki commented Oct 22, 2024

I would change the PR tittle. That goes on the auto-generated release notes.

Copy link
Contributor

@eguzki eguzki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review still WIP

src/data/attribute.rs Outdated Show resolved Hide resolved
src/data/attribute.rs Outdated Show resolved Hide resolved
src/data/attribute.rs Outdated Show resolved Hide resolved
src/configuration.rs Show resolved Hide resolved
src/configuration/action.rs Show resolved Hide resolved
@alexsnaps
Copy link
Member Author

Just to be clear about the state of this... now that #110 was merged, while broken, let's not merge this quite yet.
I took @didierofrivia work over in supporting "not so well known attribute", i.e. the data coming from authorino. I'll do that in 2 passes, scalar values (e.g. auth.identity.anonymous being resolved as being of type bool and then supporting any expression coming from authorino, expressed as JSON, in there too: List & Object)
I should get the former done by EOD EST, possibly the latter too...

@alexsnaps
Copy link
Member Author

alexsnaps commented Oct 22, 2024

this change has the first step, but I think the latter step is not required because of how the struct is decomposed in process_metadata; that being said reading this on the Authorino side, I'm unsure treating all values as String would actually always work. I'd need to delegate to @didierofrivia or possibly @adam-cattermole that did that integration

["source", "remote_address"] => remote_address(),
// todo, unsure whether to drop the "auth" part here...
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If auth isn't indeed part of it, which I think it may well not be, then I think it should be added when we store_metadata... rather than shoving what comes back from Authorino in the metadata struct straight into the KUADRANT_NAMESPACE...

@alexsnaps alexsnaps changed the title Known attr Predicate on our "well-known attributes" Oct 23, 2024
Copy link
Contributor

@eguzki eguzki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice peace of work!

Some minor comments dropped.

Doc is required

src/data/cel.rs Show resolved Hide resolved
}

impl AttributeMap {
pub fn new(attributes: Vec<Attribute>) -> Self {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding some comment to explain this high level.

Some example can help like

A map from properties [["auth", "identity", "user"], ["auth", "identity", "group"]] would be

{
    "auth": Node(
         {
             "identity": Node(
                    {
                          "user": Value(["auth", "identity", "c"]), 
                          "group": Value(["auth", "identity", "group"])
                      }
              )
           }
       )
}

src/data/cel.rs Outdated Show resolved Hide resolved
src/data/cel.rs Show resolved Hide resolved
@alexsnaps
Copy link
Member Author

Alright, it should "all" work. i.e. now we store JSON representation of the auth data coming back from authorino, so to not lose the type information... We even get integers! I also added support for getting to headers...

}
}

#[cfg(not(test))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this way of defining the fn when it's meant to be mocked for testing and not. Might be worthy to follow the same pattern for the operation dispatcher and grpc message req/res //TODO:(didierofrivia)

Copy link
Contributor

@didierofrivia didierofrivia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. 💪🏼 🥇 🙏🏼

Signed-off-by: Alex Snaps <[email protected]>
.get()
.expect("Expression must be compiled by now")
.eval()
{
Copy link
Member Author

@alexsnaps alexsnaps Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how we've send data to limitador so far, losing the type information... just a string: true, 42, bob looks "good" today

// todo this probably should be a proper string literal!
Value::String(s) => (*s).clone(),
Value::Bool(b) => format!("{b}"),
Value::Null => "null".to_owned(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if we should skip that descriptor entry... this could happen if a value is explicitly set to null in auth ...

@alexsnaps
Copy link
Member Author

Status update: this 🔥 the need for anything but CEL. While the previous ways are still there, they should NOT be used anymore and comes with bunch of caveat... I'll let the code speak for itself as how one can shoot themselves in the foot by going to raw properties/attribute values.

Copy link
Contributor

@eguzki eguzki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments and food for thoughts.

This is not about requesting changes.

From my side, this is ready to be merged

@@ -128,7 +129,7 @@ pub fn set_attribute(attr: &str, value: &[u8]) {
pub fn store_metadata(metastruct: &Struct) {
let metadata = process_metadata(metastruct, String::new());
for (key, value) in metadata {
let attr = format!("{KUADRANT_NAMESPACE}\\.{key}");
let attr = format!("{KUADRANT_NAMESPACE}\\.auth\\.{key}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that the auth prefix should come from pub fn process_auth_grpc_response method.

Then, pub fn store_metadata(metastruct: &Struct) could be pub fn store_metadata(prefix: &str, metastruct: &Struct)

My diff

diff --git a/src/data/attribute.rs b/src/data/attribute.rs
index 9e65caa..7888462 100644
--- a/src/data/attribute.rs
+++ b/src/data/attribute.rs
@@ -126,10 +126,10 @@ pub fn set_attribute(attr: &str, value: &[u8]) {
     };
 }
 
-pub fn store_metadata(metastruct: &Struct) {
+pub fn store_metadata(prefix: &str, metastruct: &Struct) {
     let metadata = process_metadata(metastruct, String::new());
     for (key, value) in metadata {
-        let attr = format!("{KUADRANT_NAMESPACE}\\.auth\\.{key}");
+        let attr = format!("{KUADRANT_NAMESPACE}\\.{prefix}\\.{key}");
         debug!("set_attribute: {attr} = {value}");
         set_attribute(attr.as_str(), value.into_bytes().as_slice());
     }
diff --git a/src/service/auth.rs b/src/service/auth.rs
index c8e4a4d..8364a8b 100644
--- a/src/service/auth.rs
+++ b/src/service/auth.rs
@@ -128,7 +128,7 @@ impl AuthService {
     ) -> Result<(), StatusCode> {
         if let GrpcMessageResponse::Auth(check_response) = auth_resp {
             // store dynamic metadata in filter state
-            store_metadata(check_response.get_dynamic_metadata());
+            store_metadata("auth", check_response.get_dynamic_metadata());
 
             match check_response.http_response {
                 Some(CheckResponse_oneof_http_response::ok_response(ok_response)) => {

@@ -128,7 +129,7 @@ pub fn set_attribute(attr: &str, value: &[u8]) {
pub fn store_metadata(metastruct: &Struct) {
let metadata = process_metadata(metastruct, String::new());
for (key, value) in metadata {
let attr = format!("{KUADRANT_NAMESPACE}\\.{key}");
let attr = format!("{KUADRANT_NAMESPACE}\\.auth\\.{key}");
debug!("set_attribute: {attr} = {value}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this debug! macro in pub fn set_attribute(attr: &str, value: &[u8]) ?

@@ -128,7 +129,7 @@ pub fn set_attribute(attr: &str, value: &[u8]) {
pub fn store_metadata(metastruct: &Struct) {
let metadata = process_metadata(metastruct, String::new());
for (key, value) in metadata {
let attr = format!("{KUADRANT_NAMESPACE}\\.{key}");
let attr = format!("{KUADRANT_NAMESPACE}\\.auth\\.{key}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a comment saying that attributes set here are accessible with wasm.* prefix?

@@ -22,6 +23,23 @@ pub mod action;
pub mod action_set;
mod action_set_index;

#[derive(Deserialize, Debug, Clone)]
pub struct ExpressionItem {
pub key: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make key optional? it would default to the expression value (not the referenced value, though).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes for a very horrible default, but... 🤷

@alexsnaps
Copy link
Member Author

@eguzki This is my gift to you... you all of course :)
Do whatever you want with the PR! You have my blessing. I need to move on here...

@eguzki eguzki merged commit fcff575 into main Oct 25, 2024
9 checks passed
@eguzki eguzki deleted the known_attr branch October 25, 2024 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

CEL expressions
3 participants