Skip to content

Commit

Permalink
Initial yaml file format for age sops file metadata.
Browse files Browse the repository at this point in the history
  • Loading branch information
gibbz00 committed Dec 9, 2023
1 parent 74383b0 commit a52c448
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 7 deletions.
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@ members = [ "crates/*" ]
age = "0.9"
indoc = "2"
rand = "0.8"
serde = { version = "1", features = ["derive"] }
serde_with = "3"
serde_yaml = "0.9"
textwrap = "0.16"
thiserror = "1"

[patch.crates-io]
# TEMP: https://github.com/str4d/rage/pull/420
age = { git = "https://github.com/gibbz00/rage", branch = "public_key_partial_eq" }
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
- [ ] Message authentication code (MAC) for encrypted parts only.
- Flag: `--mac-only-encrypted`.
- `.rops.yaml`: `partial_encryption.mac_only_encrypted: true`.
- [ ] Last modified metadata

### Integrations:

Expand Down
13 changes: 11 additions & 2 deletions crates/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@ version = "0.1.0"
edition = "2021"

[features]
# Integrations:
age = ["dep:age"]
age-test-utils = ["age", "test-utils", "dep:indoc"]
age-test-utils = ["age", "test-utils", "dep:indoc", "dep:textwrap"]
# File formats:
yaml = ["dep:serde_yaml"]

test-utils = []

[dependencies]
rand.workspace = true
serde.workspace = true
serde_with.workspace = true
thiserror.workspace = true

# AGE
age = { workspace = true, features = ["armor"], optional = true }

# AGE + TEST_UTILS
# AGE && TEST_UTILS
textwrap = { workspace = true, optional = true }
indoc = { workspace = true, optional = true }

# YAML
serde_yaml = { workspace = true, optional = true }
4 changes: 2 additions & 2 deletions crates/lib/src/error_handling.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use thiserror::Error;

use crate::*;

pub type RopsResult<T> = Result<T, RopsError>;

#[derive(Debug, Error)]
Expand All @@ -23,13 +21,15 @@ pub enum RopsError {
#[cfg(feature = "age")]
impl From<age::EncryptError> for RopsError {
fn from(encrypt_error: age::EncryptError) -> Self {
use crate::*;
Self::Encryption(AgeIntegration::NAME, encrypt_error.to_string())
}
}

#[cfg(feature = "age")]
impl From<age::DecryptError> for RopsError {
fn from(decrypt_error: age::DecryptError) -> Self {
use crate::*;
Self::Decryption(AgeIntegration::NAME, decrypt_error.to_string())
}
}
4 changes: 3 additions & 1 deletion crates/lib/src/integration/core.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::fmt::Display;

use crate::*;

pub trait Integration {
const NAME: &'static str;
type PublicKey;
type PublicKey: Display;
type PrivateKey;

fn parse_public_key(public_key_str: &str) -> RopsResult<Self::PublicKey>;
Expand Down
14 changes: 12 additions & 2 deletions crates/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ pub use data_key::{DataKey, DATA_KEY_BYTE_SIZE};
mod error_handling;
pub use error_handling::{RopsError, RopsResult};

mod sops_file;
pub use sops_file::*;

mod integration;
pub use integration::*;

#[cfg(feature = "test-utils")]
pub use test_utils::MockTestUtil;
pub use mocking::MockTestUtil;
#[cfg(all(feature = "test-utils", feature = "yaml"))]
pub use mocking::MockYamlTestUtil;
#[cfg(feature = "test-utils")]
mod test_utils {
mod mocking {
pub trait MockTestUtil {
fn mock() -> Self;
}

#[cfg(feature = "yaml")]
pub trait MockYamlTestUtil {
fn mock_yaml() -> String;
}
}
110 changes: 110 additions & 0 deletions crates/lib/src/sops_file/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
mod file_format {}

#[cfg(feature = "test-utils")]
pub use test_utils::*;
#[cfg(feature = "test-utils")]
mod test_utils {
#[cfg(feature = "yaml")]
pub use yaml::YamlTestUtils;
#[cfg(feature = "yaml")]
mod yaml {
use std::fmt::Debug;

use serde::{de::DeserializeOwned, Serialize};

use crate::*;

pub struct YamlTestUtils;

impl YamlTestUtils {
pub fn assert_serialization<T: MockTestUtil + MockYamlTestUtil + Serialize>() {
assert_eq!(T::mock_yaml(), serde_yaml::to_string(&T::mock()).unwrap())
}

pub fn assert_deserialization<T: MockTestUtil + MockYamlTestUtil + DeserializeOwned + Debug + PartialEq>() {
assert_eq!(T::mock(), serde_yaml::from_str(&T::mock_yaml()).unwrap())
}
}
}
}

pub use metadata::*;
mod metadata {
pub use core::SopsFileMetadata;
mod core {
use serde::{Deserialize, Serialize};

use crate::*;

#[derive(Serialize, Deserialize)]
pub struct SopsFileMetadata {
#[cfg(feature = "age")]
pub age: Vec<SopsFileAgeMetadata>,
}
}

#[cfg(feature = "age")]
pub use age::SopsFileAgeMetadata;
#[cfg(feature = "age")]
mod age {
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};

use crate::*;

#[serde_as]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct SopsFileAgeMetadata {
#[serde_as(as = "DisplayFromStr")]
#[serde(rename = "recipient")]
pub public_key: <AgeIntegration as Integration>::PublicKey,
#[serde(rename = "enc")]
pub encrypted_data_key: String,
}

#[cfg(feature = "test-utils")]
mod test_utils {
use super::*;

impl MockTestUtil for SopsFileAgeMetadata {
fn mock() -> Self {
Self {
public_key: AgeIntegration::mock_public_key(),
encrypted_data_key: AgeIntegration::mock_encrypted_data_key_str().to_string(),
}
}
}

#[cfg(feature = "yaml")]
impl MockYamlTestUtil for SopsFileAgeMetadata {
fn mock_yaml() -> String {
indoc::formatdoc! {"
recipient: {}
enc: |
{}",
AgeIntegration::mock_public_key_str(),
textwrap::indent(AgeIntegration::mock_encrypted_data_key_str()," ")
}
}
}
}

#[cfg(test)]
mod tests {
#[cfg(feature = "yaml")]
mod yaml {
use crate::*;

#[test]
fn serializes_yaml_age_sops_file_metadata() {
YamlTestUtils::assert_serialization::<SopsFileAgeMetadata>()
}

#[test]
fn deserializes_yaml_age_sops_file_metadata() {
YamlTestUtils::assert_deserialization::<SopsFileAgeMetadata>()
}
}
}
}
}

0 comments on commit a52c448

Please sign in to comment.