-
Notifications
You must be signed in to change notification settings - Fork 15
Add CBOR support #970
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
base: main
Are you sure you want to change the base?
Add CBOR support #970
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -357,7 +357,8 @@ impl CertKeyPair { | |
| .as_bytes() | ||
| .to_vec(), | ||
| ) | ||
| .await; | ||
| .await | ||
| .context("putting in etcd")?; | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use anyhow::{bail, Context, Result}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ciborium::value::Value as CborValue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use serde_json::{value::Number as JsonNumber, Value as JsonValue}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const SELF_DESCRIBING_CBOR_TAG: u64 = 55799; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn cbor_to_json(cbor: CborValue) -> Result<JsonValue> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(match cbor { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Null => JsonValue::Null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Bool(boolean) => JsonValue::Bool(boolean), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Text(string) => JsonValue::String(string), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Integer(int) => JsonValue::Number({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let int: i128 = int.into(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Ok(int) = u64::try_from(int) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonNumber::from(int) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if let Ok(int) = i64::try_from(int) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonNumber::from(int) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonNumber::from_f64(int as f64).context("Integer not JSON compatible")? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Float(float) => JsonValue::Number(JsonNumber::from_f64(float).context("Float not JSON compatible")?), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Array(vec) => JsonValue::Array(vec.into_iter().map(cbor_to_json).collect::<Result<Vec<_>>>()?), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Map(map) => JsonValue::Object(serde_json::Map::from_iter( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| map.into_iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|(k, v)| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let key_str = match k { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Bytes(bytes) => String::from_utf8(bytes).context("Invalid UTF-8 in CBOR map key")?, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Text(text) => text, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ => bail!("Unsupported CBOR map key type {:?}", k), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok((key_str, cbor_to_json(v)?)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect::<Result<Vec<(String, JsonValue)>>>()?, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: Handle proposed-encoding tags for CBOR bytes? https://github.com/kubernetes/kubernetes/pull/125419 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // It seems that in a typical k8s cluster these are not used anywhere (secrets are | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // protobuf, and they're pretty much the only place where raw bytes are used in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // values), so I don't have an example to test that implementation on. For now we will | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // crash on unhandled tags below to be safe. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Bytes(vec) => JsonValue::String(String::from_utf8(vec).context("Invalid UTF-8 in CBOR bytes")?), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Tag(value, _tag) => unimplemented!("Unsupported CBOR tag {:?}", value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ => unimplemented!("Unsupported CBOR type {:?}", cbor), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn json_to_cbor(json: JsonValue) -> Result<CborValue> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(match json { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::Null => CborValue::Null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::Bool(boolean) => CborValue::Bool(boolean), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::String(string) => CborValue::Bytes(string.into_bytes()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::Number(number) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(int) = number.as_i64() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Integer(int.into()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if let Some(uint) = number.as_u64() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Integer(uint.into()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if let Some(float) = number.as_f64() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Float(float) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bail!("Unsupported number type") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::Array(arr) => CborValue::Array(arr.into_iter().map(json_to_cbor).collect::<Result<Vec<_>>>()?), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonValue::Object(map) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fallback for regular JSON objects (shouldn't happen in our flow) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let map_entries: Vec<(CborValue, CborValue)> = map | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .into_iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|(k, v)| Ok((CborValue::Bytes(k.into_bytes()), json_to_cbor(v)?))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect::<Result<Vec<_>>>()?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Map(map_entries) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub(crate) fn k8s_cbor_bytes_to_json(cbor_bytes: &[u8]) -> Result<JsonValue> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let v: CborValue = ciborium::de::from_reader(cbor_bytes)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let (v, had_self_describing_tag) = match v { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CborValue::Tag(value, contents) => match value { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELF_DESCRIBING_CBOR_TAG => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Self-describing CBOR tag, unwrap the contents | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (*contents, true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ => panic!("Unsupported CBOR tag {}", value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace The pipeline flagged this 🐛 Proposed fix- _ => panic!("Unsupported CBOR tag {}", value),
+ _ => bail!("Unsupported CBOR tag {}", value),🧰 Tools🪛 GitHub Actions: Rust[error] 84-84: Clippy error: panic! should not be present in production code. Consider avoiding panics in production paths (panic! at src/etcd_encoding/k8s_cbor.rs:84). 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // We expected a self-describing CBOR tag at the root. Of course we could just proceed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // as is (since it's just raw CBOR) but it's a bit fishy, so just bail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ => bail!("CBOR data that does not start with self-describing tag is not supported"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cbor_to_json(v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+78
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Use Line 84 uses Suggested fix- let (v, had_self_describing_tag) = match v {
+ let v = match v {
CborValue::Tag(value, contents) => match value {
SELF_DESCRIBING_CBOR_TAG => {
// Self-describing CBOR tag, unwrap the contents
- (*contents, true)
+ *contents
}
- _ => panic!("Unsupported CBOR tag {}", value),
+ _ => bail!("Unsupported CBOR tag {}", value),
},
// We expected a self-describing CBOR tag at the root. Of course we could just proceed
// as is (since it's just raw CBOR) but it's a bit fishy, so just bail
- _ => bail!("CBOR data that does not start with self-describing tag is not supported"),
+ _ => bail!("CBOR data without self-describing tag is not supported"),
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub(crate) fn json_to_k8s_cbor_bytes(json: JsonValue) -> Result<Vec<u8>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let cbor = json_to_cbor(json)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Put back the self-describing CBOR tag that we stripped | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let tagged_cbor = CborValue::Tag(SELF_DESCRIBING_CBOR_TAG, Box::new(cbor)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut bytes = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ciborium::ser::into_writer(&tagged_cbor, &mut bytes)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(bytes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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.
Replace
unimplemented!macros with proper error handling.These
unimplemented!()calls will panic in production. They should return errors with context about the unsupported type.🔧 Suggested fix
Note: The catch-all
_ => unimplemented!(...)on line 43 may be unreachable if allCborValuevariants are handled above. If so, consider removing it or replacing withunreachable!()with a comment explaining why.