diff --git a/src/minio.rs b/src/minio.rs index 7189ac5..94a992c 100644 --- a/src/minio.rs +++ b/src/minio.rs @@ -23,6 +23,8 @@ enum MinioError { SetQuotaFailed, #[error("Failed to set bucket retention!")] SetRetentionFailed, + #[error("Failed to set policy!")] + ApplyPolicyFailed, } #[derive(Debug, Clone)] @@ -91,6 +93,23 @@ struct MinioRetentionResult { pub validity: Option, } +#[derive(Debug, Clone, Deserialize)] +struct MinioPolicy { + pub policy: String, +} + +#[allow(non_snake_case)] +#[derive(Debug, Clone, Deserialize)] +struct MinioPolicyInfo { + pub policyInfo: PolicyInfo, +} + +#[allow(non_snake_case)] +#[derive(Debug, Clone, Deserialize)] +struct PolicyInfo { + Policy: serde_json::Value, +} + impl BasicMinioResult { pub fn success(&self) -> bool { self.status == "success" @@ -412,6 +431,49 @@ impl MinioService { } Ok(None) } + + /// Apply a bucket policy + pub async fn policy_apply(&self, name: &str, content: &str) -> anyhow::Result<()> { + let tmp_file = mktemp::Temp::new_file()?; + std::fs::write(&tmp_file, content)?; + + let res = self + .exec_mc_cmd::(&[ + "admin", + "policy", + "create", + MC_ALIAS_NAME, + name, + tmp_file.to_str().unwrap(), + ]) + .await?; + + if res.get(0).map(|r| r.success()) != Some(true) { + return Err(MinioError::ApplyPolicyFailed.into()); + } + + Ok(()) + } + + /// Get the list of existing policies + pub async fn policy_list(&self) -> anyhow::Result> { + Ok(self + .exec_mc_cmd::(&["admin", "policy", "list", MC_ALIAS_NAME]) + .await? + .iter() + .map(|p| p.policy.to_string()) + .collect()) + } + + /// Get the content of a given policy + pub async fn policy_content(&self, name: &str) -> anyhow::Result { + let policy = self + .exec_mc_cmd::(&["admin", "policy", "info", MC_ALIAS_NAME, name]) + .await? + .remove(0); + + Ok(serde_json::to_string(&policy.policyInfo.Policy)?) + } } #[cfg(test)] @@ -420,6 +482,7 @@ mod test { use crate::minio_test_server::MinioTestServer; const TEST_BUCKET_NAME: &str = "mybucket"; + const TEST_POLICY_NAME: &str = "mypolicy"; #[tokio::test] async fn list_buckets_empty_instance() { @@ -863,4 +926,31 @@ mod test { None ); } + + fn unify_policy(p: &str) -> String { + serde_json::to_string(&serde_json::from_str::(p).unwrap()).unwrap() + } + + #[tokio::test] + async fn policy_apply() { + let _ = env_logger::builder().is_test(true).try_init(); + + let srv = MinioTestServer::start().await.unwrap(); + let service = srv.as_service(); + + let policy_1 = unify_policy(include_str!("../test/test-policy1.json")); + let policy_2 = unify_policy(include_str!("../test/test-policy2.json")); + + assert_ne!(policy_1, policy_2); + + assert!(!service.policy_list().await.unwrap().contains(&TEST_POLICY_NAME.to_string())); + + service.policy_apply(TEST_POLICY_NAME, &policy_1).await.unwrap(); + assert!(service.policy_list().await.unwrap().contains(&TEST_POLICY_NAME.to_string())); + assert_eq!(unify_policy(&service.policy_content(TEST_POLICY_NAME).await.unwrap()), policy_1); + + service.policy_apply(TEST_POLICY_NAME, &policy_2).await.unwrap(); + assert!(service.policy_list().await.unwrap().contains(&TEST_POLICY_NAME.to_string())); + assert_eq!(unify_policy(&service.policy_content(TEST_POLICY_NAME).await.unwrap()), policy_2); + } } diff --git a/test/bucket-policy.yaml b/test/bucket-policy.json similarity index 100% rename from test/bucket-policy.yaml rename to test/bucket-policy.json diff --git a/test/test-policy1.json b/test/test-policy1.json new file mode 100644 index 0000000..acbf1c5 --- /dev/null +++ b/test/test-policy1.json @@ -0,0 +1,15 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ListObjectsInBucket", + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": [ + "arn:aws:s3:::bucket" + ] + } + ] +} \ No newline at end of file diff --git a/test/test-policy2.json b/test/test-policy2.json new file mode 100644 index 0000000..e45f5c0 --- /dev/null +++ b/test/test-policy2.json @@ -0,0 +1,11 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ListObjectsInBucket", + "Effect": "Allow", + "Action": ["s3:ListBucket"], + "Resource": ["arn:aws:s3:::bucketdos"] + } + ] +}