-
Notifications
You must be signed in to change notification settings - Fork 3
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
Feat: JSON output in biscuit inspect
#48
Conversation
5efa943
to
21f53dc
Compare
21f53dc
to
5c68ce0
Compare
Token::FailedLogic(l) => display_logic_error(&policies, &l), | ||
Token::RunLimit(l) => display_run_limit(&l), | ||
_ => {} | ||
if let Ok(biscuit) = sig_result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal opinion, but wouldn't it be easier to read with a match block ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for huge blocks like this, i like if-let, as it indents things less. I also think the if/else semantics maps better to what we are actually doing, especially since we're performing side effects.
Common behaviourexit code is never 0 if anything went wrong. stdout always contains a valid JSON object even for stop-the-world errors the json output is either stderr only contains something if the exit code is not 0, it contains a text representation of the error. Open questions
Good caseno input errors, valid biscuit, correct signatures, successful auth & queries exit code: 0 standard error: nothing standard output: {
"token": {
"sealed": false,
"root_key_id": null,
"blocks": [
{
"code": "user(\"1234\");\n",
"external_key": null,
"revocation_id": "0ca759b390fbbb20461d9a2ca0b335371020262cbefc50854ee5cdc000339a877788f40baa0eb4af005eab0f26e556c0a86f063618d720c0619d7a67320de707"
},
{
"code": "user(\"4567\");\n",
"external_key": null,
"revocation_id": "c7e85b0c3bad81a1f381985042df1bd6b04f5c0029b0c38ec8565d767474953e9087af66ac396dd246f416038b7c02d2e943a1c5a5a4f282b7b3f4fcbc19fb0d"
}
]
},
"signatures_check": true,
"auth": {
"policies": [
"allow if user($u)"
],
"result": [
0,
"allow if user($u)"
]
},
"query": {
"query": "user($u) <- user($u)",
"query_all": true,
"facts": [
"user(\"1234\")",
"user(\"4567\")"
]
}
} Failed authorization (authorizer datalog correctly parsed){
"token": {
"sealed": false,
"root_key_id": null,
"blocks": [
{
"code": "user(\"1234\");\n",
"external_key": null,
"revocation_id": "0ca759b390fbbb20461d9a2ca0b335371020262cbefc50854ee5cdc000339a877788f40baa0eb4af005eab0f26e556c0a86f063618d720c0619d7a67320de707"
}
]
},
"signatures_check": true,
"auth": {
"policies": [
"deny if true"
],
"result": {
"error": {
"FailedLogic": {
"Unauthorized": {
"policy": {
"Deny": 0
},
"checks": []
}
}
}
}
},
"query": null
} Input error before biscuit parsing (inconsistent args, incorrect biscuit file name, etc)exit code: 1 stderr: Error: I cannot read input from both stdin and an interactive editor. Please use proper files or flags instead. stdout: {"error":"I cannot read input from both stdin and an interactive editor. Please use proper files or flags instead."} Input error after biscuit parsing (incorrect datalog for the authorizer, missing public key when an authorizer is specified)exit code: 1 stderr: Error: A public key is required when authorizing a biscuit stdout: {"error":"A public key is required when authorizing a biscuit"} alternatives:if the biscuit token can be read, shouldn't we always return it in stdout, and return the error in the proswe always return as much information as we can conscode is more complex. here it is clearly a user error, so failing early is okay imo |
The `--json` flag on `biscuit inspect` now provides results in a structured JSON format: ```json { "token": { "sealed": false, "root_key_id": null, "blocks": [ { "code": "user(\"1234\");\n", "external_key": null, "revocation_id": "0ca759b390fbbb20461d9a2ca0b335371020262cbefc50854ee5cdc000339a877788f40baa0eb4af005eab0f26e556c0a86f063618d720c0619d7a67320de707" }, { "code": "user(\"4567\");\n", "external_key": null, "revocation_id": "c7e85b0c3bad81a1f381985042df1bd6b04f5c0029b0c38ec8565d767474953e9087af66ac396dd246f416038b7c02d2e943a1c5a5a4f282b7b3f4fcbc19fb0d" } ] }, "signatures_check": true, "auth": { "policies": [ "allow if user($u)" ], "result": { "Ok": [ 0, "allow if user($u)" ] } }, "query": { "query": "user($u) <- user($u)", "query_all": true, "facts": [ "user(\"1234\")", "user(\"4567\")" ] } } ``` If either the signature, the authorization, or the query fail during execution, a JSON value is still sent to stdout, with structured errors, an error message is sent to stderr, and the command exits with a non-zero error code. Evaluation still aborts for input errors (missing files, invalid datalog input for the authorizer, etc). In that case, nothing is sent to stdout, an error message is sent to stderr, and the command exits with a non-zero error code. This change required extensive modifications: the implementation interleaved console output with computations. This meant that even if an error was raised and execution aborted, text output would still be shown. For JSON output, this doesn't work, as all results need to be collected before being displayed. The inspection function now returns an `InspectionResults` value, that can either be rendered as text, or as JSON. To be able to generate this value, even in the case of authorization errors, the execution logic had to be updated to not abort early in case of: - failed signature checks - failed authorization - failed queries
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": … } } ```
The
--json
flag onbiscuit inspect
now provides results in a structured JSON format:If either the signature, the authorization, or the query fail during execution, a JSON value is still sent to stdout, with structured errors, an error message is sent to stderr, and the command exits with a non-zero error code.
Evaluation still aborts for input errors (missing files, invalid datalog input for the authorizer, etc). In that case, a JSON object containing an
error
field is sent to stdout, an error message is sent to stderr, and the command exits with a non-zero error code.This change required extensive modifications: the implementation interleaved console output with computations. This meant that even if an error was raised and execution aborted, text output would still be shown. For JSON output, this doesn't work, as all results need to be collected before being displayed.
The inspection function now returns an
InspectionResults
value, that can either be rendered as text, or as JSON. To be able to generate this value, even in the case of authorization errors, the execution logic had to be updated to not abort early in case of: