Skip to content

Commit

Permalink
fix: improve JSON encoding of sig, auth & query errors
Browse files Browse the repository at this point in the history
The naïve encoding of `Result` in JSON is an object with either a `Ok`
or a `Err` field, containing the JSON encoding of either the value or the error. This is a rather uncommon JSON encoding for errors and ties the output to the implementation language.

This commit introduces an equivalent enum, with a different encoding:

- in case of success, the value is serialized without any wrapping
- in case of error, the error is wrapped in an object with a single `error` field

```json
{
    "query": "user($u) <- user($u)",
    "query_all": false,
    "facts": [ "user(\"1234\")"]
}
```

```json
{
    "query": "user($u) <- user($u)",
    "query_all": false,
    "facts": {
      "error": …
    }
}
```
  • Loading branch information
divarvel committed Jul 21, 2023
1 parent 708ef44 commit 1f14c3a
Showing 1 changed file with 42 additions and 13 deletions.
55 changes: 42 additions & 13 deletions src/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,36 @@ impl TokenDescription {
}
}

#[derive(Copy, Clone, Serialize)]
#[serde(untagged)]
enum RResult<A, E> {
Ok(A),
Err { error: E },
}

impl<A, E> From<std::result::Result<A, E>> for RResult<A, E> {
fn from(value: std::result::Result<A, E>) -> Self {
match value {
Ok(a) => Self::Ok(a),
Err(error) => Self::Err { error },
}
}
}

impl<A, E> RResult<A, E> {
pub fn into_result(self) -> std::result::Result<A, E> {
match self {
Self::Ok(a) => Ok(a),
Self::Err { error } => Err(error),
}
}
}

#[derive(Serialize)]
struct QueryResult {
query: String,
query_all: bool,
facts: std::result::Result<Vec<String>, Token>,
facts: RResult<Vec<String>, Token>,
}

impl QueryResult {
Expand All @@ -74,7 +99,7 @@ impl QueryResult {
} else {
println!("🔎 Running query: {}", &self.query);
}
match &self.facts {
match &self.facts.clone().into_result() {
Ok(facts) => {
if facts.is_empty() {
println!("❌ No results");
Expand All @@ -94,12 +119,12 @@ impl QueryResult {
#[derive(Serialize)]
struct AuthResult {
policies: Vec<String>,
result: std::result::Result<(usize, String), Token>,
result: RResult<(usize, String), Token>,
}

impl AuthResult {
fn render(&self) {
match &self.result {
match &self.result.clone().into_result() {
Ok((_, policy)) => {
println!("✅ Authorizer check succeeded 🛡️");
println!("Matched allow policy: {}", policy);
Expand Down Expand Up @@ -151,13 +176,13 @@ impl InspectionResults {
}

if let Some(ref auth) = self.auth {
if auth.result.is_err() {
if auth.result.clone().into_result().is_err() {
Err(AuthorizationFailed)?;
}
}

if let Some(ref query) = self.query {
if query.facts.is_err() {
if query.facts.clone().into_result().is_err() {
Err(QueryFailed)?;
}
}
Expand Down Expand Up @@ -194,7 +219,9 @@ fn handle_query(
Ok(QueryResult {
query: query.to_string(),
query_all,
facts: facts.map(|fs| fs.iter().map(|f| f.to_string()).collect::<Vec<_>>()),
facts: facts
.map(|fs| fs.iter().map(|f| f.to_string()).collect::<Vec<_>>())
.into(),
})
}

Expand Down Expand Up @@ -332,12 +359,14 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result<InspectionResults> {

auth_result = Some(AuthResult {
policies: policies.iter().map(|p| p.to_string()).collect::<Vec<_>>(),
result: authorizer_result.map(|i| {
(
i,
policies.get(i).expect("Incorrect policy index").to_string(),
)
}),
result: authorizer_result
.map(|i| {
(
i,
policies.get(i).expect("Incorrect policy index").to_string(),
)
})
.into(),
});

if let Some(snapshot_file) = &inspect.dump_snapshot_to {
Expand Down

0 comments on commit 1f14c3a

Please sign in to comment.