Skip to content

Commit

Permalink
Flatten rops_file::tree module.
Browse files Browse the repository at this point in the history
  • Loading branch information
gibbz00 committed Dec 16, 2023
1 parent fa19b3b commit 662add5
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 144 deletions.
91 changes: 91 additions & 0 deletions crates/lib/src/rops_file/format/yaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,94 @@ impl FileFormat for YamlFileFormat {
serde_yaml::from_str(str)
}
}

mod encrypted_map_to_tree {}

mod decrypted_map_to_tree {
use indexmap::IndexMap;
use serde_yaml::{Mapping as YamlMap, Value as YamlValue};

use crate::*;

impl TryFrom<RopsFileMap<Decrypted, YamlFileFormat>> for RopsTree<Decrypted> {
type Error = DecryptedMapToTreeError;

fn try_from(rops_file_map: RopsFileMap<Decrypted, YamlFileFormat>) -> Result<Self, Self::Error> {
return recursive_map_call(rops_file_map.into_inner_map());

fn recursive_map_call(yaml_map: YamlMap) -> Result<RopsTree<Decrypted>, DecryptedMapToTreeError> {
let mut inner_map = IndexMap::default();

for (yaml_key, value_yaml) in yaml_map {
inner_map.insert(validate_key(yaml_key)?, recursive_value_call(value_yaml)?);
}

return Ok(RopsTree::Map(inner_map));

fn validate_key(yaml_value: YamlValue) -> Result<String, DecryptedMapToTreeError> {
match yaml_value {
YamlValue::String(string) => Ok(string),
other => Err(DecryptedMapToTreeError::NonStringKey(
serde_yaml::to_string(&other).expect("yaml value not serializable"),
)),
}
}
}

fn recursive_value_call(yaml_value: YamlValue) -> Result<RopsTree<Decrypted>, DecryptedMapToTreeError> {
Ok(match yaml_value {
// SOPS simply throws away tags, so do we for now.
// It can, however, deserialize manually added tags to encrypted documents,
// so we could in theory keep the tags somewhere without breaking SOPS compatability.
YamlValue::Tagged(tagged) => recursive_value_call(tagged.value)?,
YamlValue::Mapping(map) => recursive_map_call(map)?,
YamlValue::Bool(boolean) => RopsTree::Leaf(RopsValue::Boolean(boolean)),
YamlValue::String(string) => RopsTree::Leaf(RopsValue::String(string)),
YamlValue::Number(number) => RopsTree::Leaf(match number.is_f64() {
true => RopsValue::Float(number.as_f64().expect("number not a f64")),
false => RopsValue::Integer(
number
.as_i64()
.ok_or_else(|| DecryptedMapToTreeError::IntegerOutOfRange(number.as_u64().expect("number not an u64")))?,
),
}),
YamlValue::Sequence(sequence) => {
RopsTree::Sequence(sequence.into_iter().map(recursive_value_call).collect::<Result<Vec<_>, _>>()?)
}
YamlValue::Null => RopsTree::Null,
})
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn transforms_decrypted_yaml_map() {
assert_eq!(
RopsTree::mock(),
RopsFileMap::<Decrypted, YamlFileFormat>::mock().try_into().unwrap()
)
}

#[test]
fn dissallows_non_string_keys() {
let file_map = RopsFileMap::from_inner_map(serde_yaml::from_str::<YamlMap>("123: 456").unwrap());
assert!(matches!(
RopsTree::try_from(file_map).unwrap_err(),
DecryptedMapToTreeError::NonStringKey(_)
))
}

#[test]
fn dissallows_out_of_range_integers() {
let file_map = RopsFileMap::from_inner_map(serde_yaml::from_str::<YamlMap>(&format!("invalid_integer: {}", u64::MAX)).unwrap());
assert!(matches!(
RopsTree::try_from(file_map).unwrap_err(),
DecryptedMapToTreeError::IntegerOutOfRange(_)
))
}
}
}
2 changes: 1 addition & 1 deletion crates/lib/src/rops_file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod value;
pub use value::*;

mod tree;
pub use tree::{RopsTree, RopsTreeBuildError};
pub use tree::{DecryptedMapToTreeError, EncryptedMapToTreeError, RopsTree};

mod metadata;
pub use metadata::*;
Expand Down
54 changes: 54 additions & 0 deletions crates/lib/src/rops_file/tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::*;

#[derive(Debug, PartialEq)]
pub enum RopsTree<S: RopsFileState> {
Sequence(Vec<RopsTree<S>>),
Map(indexmap::IndexMap<String, RopsTree<S>>),
Null,
Leaf(S::RopsTreeLeaf),
}

#[derive(Debug, thiserror::Error)]
pub enum DecryptedMapToTreeError {
#[error("only string keys are supported, found: {0}")]
NonStringKey(String),
#[error("integer out of range, allowed values must fit inside an i64, found: {0}")]
IntegerOutOfRange(u64),
}

#[derive(Debug, thiserror::Error)]
pub enum EncryptedMapToTreeError {}

#[cfg(feature = "test-utils")]
mod mock {
use indexmap::indexmap;

use super::*;

impl MockTestUtil for RopsTree<Decrypted> {
fn mock() -> Self {
Self::Map(indexmap! {
"hello".to_string() => RopsTree::Leaf(RopsValue::String("world!".to_string())),
"nested_map".to_string() => RopsTree::Map(indexmap! {
"null_key".to_string() => RopsTree::Null,
"array".to_string() => RopsTree::Sequence(vec![
RopsTree::Leaf(RopsValue::String("string".to_string())),
RopsTree::Map(indexmap! {
"nested_map_in_array".to_string() => RopsTree::Map(indexmap!{
"integer".to_string() => RopsTree::Leaf(RopsValue::Integer(1234))
}),
}),
RopsTree::Map(indexmap!{
"float".to_string() => RopsTree::Leaf(RopsValue::Float(1234.56789))
}),
]),
}
),
"booleans".to_string() => RopsTree::Sequence(vec![
RopsTree::Leaf(RopsValue::Boolean(true)),
RopsTree::Leaf(RopsValue::Boolean(false))
])
})
}
}
}
9 changes: 0 additions & 9 deletions crates/lib/src/rops_file/tree/core.rs

This file was deleted.

7 changes: 0 additions & 7 deletions crates/lib/src/rops_file/tree/error.rs

This file was deleted.

30 changes: 0 additions & 30 deletions crates/lib/src/rops_file/tree/mock.rs

This file was deleted.

11 changes: 0 additions & 11 deletions crates/lib/src/rops_file/tree/mod.rs

This file was deleted.

86 changes: 0 additions & 86 deletions crates/lib/src/rops_file/tree/yaml.rs

This file was deleted.

0 comments on commit 662add5

Please sign in to comment.