mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-02 11:29:17 +00:00
test(kms): pin admin KMS response shapes where they are served (#5626)
The snapshots in crates/kms/src/api_types.rs pinned DeleteKeyResponse, ListKeysResponse, DescribeKeyResponse and CancelKeyDeletionResponse, none of which is serialized by any handler: those endpoints answer with DeleteKmsKeyResponse and siblings in rustfs/src/admin/handlers/kms_keys.rs, separate types carrying different fields. A breaking change to an admin response could not fail them. Tag, untag and update-description had the same gap, where the handler discards the kms-side response and serves its own KmsKeyMetadataResponse. Pin the shapes in the crate that produces them, and delete the four kms mirrors. They were never in the pub use api_types list, had no constructors and no callers, and only looked live because those snapshots named them. Keep the api_types snapshots that pin something real: configure, start, stop and status are served verbatim by kms_dynamic, and the tag family are live ObjectEncryptionService return types whose snapshots pin this crate's public API rather than a wire shape.
This commit is contained in:
+25
-90
@@ -21,7 +21,6 @@ use crate::config::{
|
||||
redacted_secret, redacted_secret_option,
|
||||
};
|
||||
use crate::service_manager::KmsServiceStatus;
|
||||
use crate::types::KeyMetadata;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
@@ -1199,6 +1198,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// The shapes this crate owns, and only those.
|
||||
///
|
||||
/// The first four are served verbatim by the dynamic-configuration admin
|
||||
/// handlers, so pinning them here pins the wire. The last three never
|
||||
/// reach a socket: `ObjectEncryptionService` returns them and the admin
|
||||
/// layer answers with its own `KmsKeyMetadataResponse` instead, so what
|
||||
/// they pin is this crate's public API, not the wire.
|
||||
///
|
||||
/// No key-management response belongs in this test. Those endpoints are
|
||||
/// served from types defined in the `rustfs` crate, and a copy here could
|
||||
/// only ever agree with them by accident — see
|
||||
/// `kms_key_admin_responses_have_stable_json_shapes` in
|
||||
/// `rustfs/src/admin/handlers/kms_keys.rs`.
|
||||
#[test]
|
||||
fn kms_management_responses_have_stable_json_shapes() {
|
||||
insta::assert_json_snapshot!(
|
||||
@@ -1234,41 +1246,6 @@ mod tests {
|
||||
config_summary: None,
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_delete_key_response",
|
||||
stable_json_value(DeleteKeyResponse {
|
||||
success: true,
|
||||
message: "key scheduled for deletion".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
deletion_date: Some("2026-07-01T00:00:00Z".to_string()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_list_keys_response",
|
||||
stable_json_value(ListKeysResponse {
|
||||
success: true,
|
||||
message: "keys listed".to_string(),
|
||||
keys: vec!["key-a".to_string(), "key-b".to_string()],
|
||||
truncated: true,
|
||||
next_marker: Some("key-b".to_string()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_describe_key_response_missing",
|
||||
stable_json_value(DescribeKeyResponse {
|
||||
success: false,
|
||||
message: "key not found".to_string(),
|
||||
key_metadata: None,
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_cancel_key_deletion_response",
|
||||
stable_json_value(CancelKeyDeletionResponse {
|
||||
success: true,
|
||||
message: "key deletion canceled".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_update_key_description_response",
|
||||
stable_json_value(UpdateKeyDescriptionResponse {
|
||||
@@ -1299,60 +1276,18 @@ mod tests {
|
||||
// ========================================
|
||||
// Key Management API Types
|
||||
// ========================================
|
||||
|
||||
/// JSON shape returned by the admin delete-key endpoint.
|
||||
///
|
||||
/// The delete *request* shape lives in [`crate::types::DeleteKeyRequest`] —
|
||||
/// there is deliberately no copy here, because the immediate-deletion gate
|
||||
/// (`force_immediate` + `confirm_key_id`) must have exactly one definition.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DeleteKeyResponse {
|
||||
/// Success flag
|
||||
pub success: bool,
|
||||
/// Status message
|
||||
pub message: String,
|
||||
/// Key ID that was deleted or scheduled for deletion
|
||||
pub key_id: String,
|
||||
/// Deletion date (if scheduled)
|
||||
pub deletion_date: Option<String>,
|
||||
}
|
||||
|
||||
/// Response from list keys operation
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ListKeysResponse {
|
||||
/// Success flag
|
||||
pub success: bool,
|
||||
/// Status message
|
||||
pub message: String,
|
||||
/// List of key IDs
|
||||
pub keys: Vec<String>,
|
||||
/// Whether more keys are available
|
||||
pub truncated: bool,
|
||||
/// Next marker for pagination
|
||||
pub next_marker: Option<String>,
|
||||
}
|
||||
|
||||
/// Response from describe key operation
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DescribeKeyResponse {
|
||||
/// Success flag
|
||||
pub success: bool,
|
||||
/// Status message
|
||||
pub message: String,
|
||||
/// Key metadata
|
||||
pub key_metadata: Option<KeyMetadata>,
|
||||
}
|
||||
|
||||
/// Response from cancel key deletion operation
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CancelKeyDeletionResponse {
|
||||
/// Success flag
|
||||
pub success: bool,
|
||||
/// Status message
|
||||
pub message: String,
|
||||
/// Key ID
|
||||
pub key_id: String,
|
||||
}
|
||||
//
|
||||
// What remains here is the key-metadata trio, and nothing else belongs.
|
||||
// Create, delete, list, describe and cancel-deletion are served from types
|
||||
// defined in the `rustfs` crate (`rustfs/src/admin/handlers/kms_keys.rs`)
|
||||
// carrying fields this crate knows nothing about, so a copy here would shadow
|
||||
// `crate::types` under the same name while agreeing with the wire only by
|
||||
// accident.
|
||||
//
|
||||
// The same holds for `DeleteKeyRequest`: it lives in `crate::types` alone, so
|
||||
// the immediate-deletion gate (`force_immediate` + `confirm_key_id`) has
|
||||
// exactly one definition and cannot be silently dropped by deserializing into
|
||||
// a copy that lacks it.
|
||||
|
||||
/// Request to update key description
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
---
|
||||
source: crates/kms/src/api_types.rs
|
||||
expression: "serde_json::to_value(CancelKeyDeletionResponse\n{\n success: true, message: \"key deletion canceled\".to_string(), key_id:\n \"key-a\".to_string(),\n}).expect(\"cancel deletion response should serialize\")"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"message": "key deletion canceled",
|
||||
"success": true
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
source: crates/kms/src/api_types.rs
|
||||
expression: "serde_json::to_value(DeleteKeyResponse\n{\n success: true, message: \"key scheduled for deletion\".to_string(), key_id:\n \"key-a\".to_string(), deletion_date:\n Some(\"2026-07-01T00:00:00Z\".to_string()),\n}).expect(\"delete key response should serialize\")"
|
||||
---
|
||||
{
|
||||
"deletion_date": "2026-07-01T00:00:00Z",
|
||||
"key_id": "key-a",
|
||||
"message": "key scheduled for deletion",
|
||||
"success": true
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
---
|
||||
source: crates/kms/src/api_types.rs
|
||||
expression: "serde_json::to_value(DescribeKeyResponse\n{\n success: false, message: \"key not found\".to_string(), key_metadata: None,\n}).expect(\"describe key response should serialize\")"
|
||||
---
|
||||
{
|
||||
"key_metadata": null,
|
||||
"message": "key not found",
|
||||
"success": false
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
source: crates/kms/src/api_types.rs
|
||||
expression: "serde_json::to_value(ListKeysResponse\n{\n success: true, message: \"keys listed\".to_string(), keys:\n vec![\"key-a\".to_string(), \"key-b\".to_string()], truncated: true,\n next_marker: Some(\"key-b\".to_string()),\n}).expect(\"list keys response should serialize\")"
|
||||
---
|
||||
{
|
||||
"keys": [
|
||||
"key-a",
|
||||
"key-b"
|
||||
],
|
||||
"message": "keys listed",
|
||||
"next_marker": "key-b",
|
||||
"success": true,
|
||||
"truncated": true
|
||||
}
|
||||
@@ -407,12 +407,13 @@ impl Operation for UntagKmsKeyHandler {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::admin::handlers::kms_keys::stable_json_value;
|
||||
use base64::Engine as _;
|
||||
use rustfs_kms::KmsManager;
|
||||
use rustfs_kms::backends::local::LocalKmsBackend;
|
||||
use rustfs_kms::backends::static_kms::StaticKmsBackend;
|
||||
use rustfs_kms::config::KmsConfig;
|
||||
use rustfs_kms::types::CreateKeyRequest;
|
||||
use rustfs_kms::types::{CreateKeyRequest, KeyState, KeyUsage};
|
||||
use rustfs_policy::policy::action::AdminAction;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -617,6 +618,46 @@ mod tests {
|
||||
assert_eq!(metadata_error_status(&KmsError::key_not_found("gone")), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
/// The single JSON body all three metadata endpoints answer with.
|
||||
///
|
||||
/// `rustfs-kms` returns a separate `TagKeyResponse`/`UntagKeyResponse`/
|
||||
/// `UpdateKeyDescriptionResponse` per operation, but this handler discards
|
||||
/// those and builds its own reply, so only a snapshot in this crate can
|
||||
/// fail when the served shape changes.
|
||||
#[test]
|
||||
fn kms_key_metadata_response_has_a_stable_json_shape() {
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_key_metadata_response",
|
||||
stable_json_value(KmsKeyMetadataResponse {
|
||||
success: true,
|
||||
message: "key tags updated".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
key_metadata: Some(KeyMetadata {
|
||||
key_id: "key-a".to_string(),
|
||||
key_state: KeyState::Enabled,
|
||||
key_usage: KeyUsage::EncryptDecrypt,
|
||||
description: Some("snapshot key".to_string()),
|
||||
creation_date: "2026-01-01T00:00:00Z[UTC]".parse().expect("snapshot timestamp should parse"),
|
||||
deletion_date: None,
|
||||
origin: "RUSTFS_KMS".to_string(),
|
||||
key_manager: "RUSTFS".to_string(),
|
||||
tags: HashMap::from([("name".to_string(), "key-a".to_string())]),
|
||||
}),
|
||||
})
|
||||
);
|
||||
// A describe that failed after the update succeeded drops the echo,
|
||||
// and the field stays present as `null` rather than disappearing.
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_key_metadata_response_without_metadata",
|
||||
stable_json_value(KmsKeyMetadataResponse {
|
||||
success: false,
|
||||
message: "Failed to tag key: key not found".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
key_metadata: None,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_auth_actions_use_dedicated_kms_actions() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -438,17 +438,46 @@ impl Operation for DescribeKeyHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize a KMS admin response into a snapshot-stable JSON value.
|
||||
///
|
||||
/// Response bodies carry `HashMap` tags and metadata, whose iteration order
|
||||
/// varies per run; sorting every object by key is what makes a snapshot of
|
||||
/// them reproducible. Shared with [`super::kms_key_metadata`], which pins its
|
||||
/// own response shape the same way.
|
||||
#[cfg(test)]
|
||||
pub(super) fn stable_json_value(value: impl serde::Serialize) -> serde_json::Value {
|
||||
fn sorted(value: serde_json::Value) -> serde_json::Value {
|
||||
match value {
|
||||
serde_json::Value::Array(values) => serde_json::Value::Array(values.into_iter().map(sorted).collect()),
|
||||
serde_json::Value::Object(map) => {
|
||||
let mut entries = map.into_iter().collect::<Vec<_>>();
|
||||
entries.sort_by(|(left, _), (right, _)| left.cmp(right));
|
||||
serde_json::Value::Object(entries.into_iter().map(|(key, value)| (key, sorted(value))).collect())
|
||||
}
|
||||
value => value,
|
||||
}
|
||||
}
|
||||
|
||||
sorted(serde_json::to_value(value).expect("admin KMS response should serialize"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
CancelKmsKeyDeletionRequest, CreateKeyApiRequest, CreateKmsKeyRequest, DeleteKmsKeyRequest, DeleteKmsKeyResponse,
|
||||
DescribeKmsKeyResponse, GenerateDataKeyApiRequest, delete_key_error_status, delete_request_from_query, extract_key_id,
|
||||
extract_query_params, key_impact_if_requested, key_list_filters, kms_create_key_actions, kms_delete_key_actions,
|
||||
kms_describe_key_actions, kms_generate_data_key_actions, kms_list_keys_actions, scoped_key_id, wants_key_impact,
|
||||
CancelKmsKeyDeletionRequest, CancelKmsKeyDeletionResponse, CreateKeyApiRequest, CreateKeyApiResponse,
|
||||
CreateKmsKeyRequest, CreateKmsKeyResponse, DeleteKmsKeyRequest, DeleteKmsKeyResponse, DescribeKeyApiResponse,
|
||||
DescribeKmsKeyResponse, GenerateDataKeyApiRequest, GenerateDataKeyApiResponse, ListKeysApiResponse, ListKmsKeysResponse,
|
||||
delete_key_error_status, delete_request_from_query, extract_key_id, extract_query_params, key_impact_if_requested,
|
||||
key_list_filters, kms_create_key_actions, kms_delete_key_actions, kms_describe_key_actions,
|
||||
kms_generate_data_key_actions, kms_list_keys_actions, scoped_key_id, stable_json_value, wants_key_impact,
|
||||
};
|
||||
use http::Uri;
|
||||
use hyper::StatusCode;
|
||||
use rustfs_kms::{KeyImpactReport, KeyReference, KeyReferenceKind, KeyStatus, KeyUsage, KmsError, ReferenceScope};
|
||||
use jiff::Zoned;
|
||||
use rustfs_kms::{
|
||||
KeyImpactReport, KeyInfo, KeyMetadata, KeyReference, KeyReferenceKind, KeyState, KeyStatus, KeyUsage, KmsError,
|
||||
ReferenceScope,
|
||||
};
|
||||
use rustfs_policy::policy::action::{Action, AdminAction, KmsAction};
|
||||
use rustfs_policy::policy::{Args, Policy};
|
||||
use std::collections::HashMap;
|
||||
@@ -885,6 +914,149 @@ mod tests {
|
||||
impact
|
||||
}
|
||||
|
||||
fn fixed_zoned(value: &str) -> Zoned {
|
||||
value.parse().expect("snapshot timestamp should parse")
|
||||
}
|
||||
|
||||
fn snapshot_key_metadata() -> KeyMetadata {
|
||||
KeyMetadata {
|
||||
key_id: "key-a".to_string(),
|
||||
key_state: KeyState::Enabled,
|
||||
key_usage: KeyUsage::EncryptDecrypt,
|
||||
description: Some("snapshot key".to_string()),
|
||||
creation_date: fixed_zoned("2026-01-01T00:00:00Z[UTC]"),
|
||||
deletion_date: Some(fixed_zoned("2026-02-01T00:00:00Z[UTC]")),
|
||||
origin: "RUSTFS_KMS".to_string(),
|
||||
key_manager: "RUSTFS".to_string(),
|
||||
tags: HashMap::from([("name".to_string(), "key-a".to_string())]),
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot_key_info() -> KeyInfo {
|
||||
KeyInfo {
|
||||
key_id: "key-a".to_string(),
|
||||
description: Some("snapshot key".to_string()),
|
||||
algorithm: "AES_256".to_string(),
|
||||
usage: KeyUsage::EncryptDecrypt,
|
||||
status: KeyStatus::Active,
|
||||
version: 1,
|
||||
metadata: HashMap::from([("origin".to_string(), "RUSTFS_KMS".to_string())]),
|
||||
tags: HashMap::from([("name".to_string(), "key-a".to_string())]),
|
||||
created_at: fixed_zoned("2026-01-01T00:00:00Z[UTC]"),
|
||||
rotated_at: Some(fixed_zoned("2026-01-15T00:00:00Z[UTC]")),
|
||||
created_by: Some("admin".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Every JSON body this module serves, pinned where it is served from.
|
||||
///
|
||||
/// `rustfs-kms` owns look-alike response types with the same operation
|
||||
/// names and different fields. A snapshot over there cannot fail when one
|
||||
/// of the types below changes, so pinning the admin wire contract has to
|
||||
/// happen in this crate, next to the types that are actually serialized.
|
||||
///
|
||||
/// `Option` fields are covered in both states: none of these types skip a
|
||||
/// `None`, and a consumer that reads `impact` or `key_metadata` as
|
||||
/// explicit `null` breaks if one later starts being omitted instead.
|
||||
#[test]
|
||||
fn kms_key_admin_responses_have_stable_json_shapes() {
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_create_key_response",
|
||||
stable_json_value(CreateKmsKeyResponse {
|
||||
success: true,
|
||||
message: "key created successfully".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
key_metadata: Some(snapshot_key_metadata()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_create_key_api_response",
|
||||
stable_json_value(CreateKeyApiResponse {
|
||||
key_id: "key-a".to_string(),
|
||||
key_metadata: snapshot_key_metadata(),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_describe_key_api_response",
|
||||
stable_json_value(DescribeKeyApiResponse {
|
||||
key_metadata: snapshot_key_metadata(),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_list_keys_api_response",
|
||||
stable_json_value(ListKeysApiResponse {
|
||||
keys: vec![snapshot_key_info()],
|
||||
truncated: true,
|
||||
next_marker: Some("key-b".to_string()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_generate_data_key_api_response",
|
||||
stable_json_value(GenerateDataKeyApiResponse {
|
||||
key_id: "key-a".to_string(),
|
||||
plaintext_key: "cGxhaW50ZXh0LXBsYWNlaG9sZGVy".to_string(),
|
||||
ciphertext_blob: "Y2lwaGVydGV4dC1wbGFjZWhvbGRlcg==".to_string(),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_delete_key_response",
|
||||
stable_json_value(DeleteKmsKeyResponse {
|
||||
success: true,
|
||||
message: "key scheduled for deletion".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
deletion_date: Some("2026-02-01T00:00:00Z".to_string()),
|
||||
impact: Some(referenced_impact()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_delete_key_response_without_impact",
|
||||
stable_json_value(DeleteKmsKeyResponse {
|
||||
success: false,
|
||||
message: "key not found".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
deletion_date: None,
|
||||
impact: None,
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_cancel_key_deletion_response",
|
||||
stable_json_value(CancelKmsKeyDeletionResponse {
|
||||
success: true,
|
||||
message: "key deletion canceled".to_string(),
|
||||
key_id: "key-a".to_string(),
|
||||
key_metadata: Some(snapshot_key_metadata()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_list_keys_response",
|
||||
stable_json_value(ListKmsKeysResponse {
|
||||
success: true,
|
||||
message: "keys listed".to_string(),
|
||||
keys: vec![snapshot_key_info()],
|
||||
truncated: true,
|
||||
next_marker: Some("key-b".to_string()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_describe_key_response",
|
||||
stable_json_value(DescribeKmsKeyResponse {
|
||||
success: true,
|
||||
message: "key described successfully".to_string(),
|
||||
key_metadata: Some(snapshot_key_metadata()),
|
||||
impact: Some(referenced_impact()),
|
||||
})
|
||||
);
|
||||
insta::assert_json_snapshot!(
|
||||
"kms_admin_describe_key_response_missing",
|
||||
stable_json_value(DescribeKmsKeyResponse {
|
||||
success: false,
|
||||
message: "key not found".to_string(),
|
||||
key_metadata: None,
|
||||
impact: None,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Scheduling a deletion for a key that bucket configuration still points
|
||||
/// at succeeds — it destroys nothing and stays cancellable — but the
|
||||
/// caller has to be told, in the same response, what will refuse the
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_key_metadata.rs
|
||||
expression: "stable_json_value(KmsKeyMetadataResponse\n{\n success: true, message: \"key tags updated\".to_string(), key_id:\n \"key-a\".to_string(), key_metadata:\n Some(KeyMetadata\n {\n key_id: \"key-a\".to_string(), key_state: KeyState::Enabled, key_usage:\n KeyUsage::EncryptDecrypt, description:\n Some(\"snapshot key\".to_string()), creation_date:\n \"2026-01-01T00:00:00Z[UTC]\".parse().expect(\"snapshot timestamp should parse\"),\n deletion_date: None, origin: \"RUSTFS_KMS\".to_string(), key_manager:\n \"RUSTFS\".to_string(), tags:\n HashMap::from([(\"name\".to_string(), \"key-a\".to_string())]),\n }),\n})"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": null,
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
},
|
||||
"message": "key tags updated",
|
||||
"success": true
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_key_metadata.rs
|
||||
expression: "stable_json_value(KmsKeyMetadataResponse\n{\n success: false, message: \"Failed to tag key: key not found\".to_string(),\n key_id: \"key-a\".to_string(), key_metadata: None,\n})"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"key_metadata": null,
|
||||
"message": "Failed to tag key: key not found",
|
||||
"success": false
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(CancelKmsKeyDeletionResponse\n{\n success: true, message: \"key deletion canceled\".to_string(), key_id:\n \"key-a\".to_string(), key_metadata: Some(snapshot_key_metadata()),\n})"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": "2026-02-01T00:00:00+00:00[UTC]",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
},
|
||||
"message": "key deletion canceled",
|
||||
"success": true
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(CreateKeyApiResponse\n{ key_id: \"key-a\".to_string(), key_metadata: snapshot_key_metadata(), })"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": "2026-02-01T00:00:00+00:00[UTC]",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(CreateKmsKeyResponse\n{\n success: true, message: \"key created successfully\".to_string(), key_id:\n \"key-a\".to_string(), key_metadata: Some(snapshot_key_metadata()),\n})"
|
||||
---
|
||||
{
|
||||
"key_id": "key-a",
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": "2026-02-01T00:00:00+00:00[UTC]",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
},
|
||||
"message": "key created successfully",
|
||||
"success": true
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(DeleteKmsKeyResponse\n{\n success: true, message: \"key scheduled for deletion\".to_string(), key_id:\n \"key-a\".to_string(), deletion_date:\n Some(\"2026-02-01T00:00:00Z\".to_string()), impact:\n Some(referenced_impact()),\n})"
|
||||
---
|
||||
{
|
||||
"deletion_date": "2026-02-01T00:00:00Z",
|
||||
"impact": {
|
||||
"completeness": "exact",
|
||||
"coverage": {
|
||||
"not_scanned": [
|
||||
"object-envelopes",
|
||||
"in-progress-multipart-uploads"
|
||||
],
|
||||
"scanned": [
|
||||
"bucket-default-encryption",
|
||||
"service-default-key"
|
||||
]
|
||||
},
|
||||
"key_id": "key-a",
|
||||
"references": [
|
||||
{
|
||||
"detail": "bucket default encryption names this key",
|
||||
"id": "sse-bucket",
|
||||
"kind": "bucket-default-encryption"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_id": "key-a",
|
||||
"message": "key scheduled for deletion",
|
||||
"success": true
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(DeleteKmsKeyResponse\n{\n success: false, message: \"key not found\".to_string(), key_id:\n \"key-a\".to_string(), deletion_date: None, impact: None,\n})"
|
||||
---
|
||||
{
|
||||
"deletion_date": null,
|
||||
"impact": null,
|
||||
"key_id": "key-a",
|
||||
"message": "key not found",
|
||||
"success": false
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(DescribeKeyApiResponse\n{ key_metadata: snapshot_key_metadata(), })"
|
||||
---
|
||||
{
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": "2026-02-01T00:00:00+00:00[UTC]",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(DescribeKmsKeyResponse\n{\n success: true, message: \"key described successfully\".to_string(),\n key_metadata: Some(snapshot_key_metadata()), impact:\n Some(referenced_impact()),\n})"
|
||||
---
|
||||
{
|
||||
"impact": {
|
||||
"completeness": "exact",
|
||||
"coverage": {
|
||||
"not_scanned": [
|
||||
"object-envelopes",
|
||||
"in-progress-multipart-uploads"
|
||||
],
|
||||
"scanned": [
|
||||
"bucket-default-encryption",
|
||||
"service-default-key"
|
||||
]
|
||||
},
|
||||
"key_id": "key-a",
|
||||
"references": [
|
||||
{
|
||||
"detail": "bucket default encryption names this key",
|
||||
"id": "sse-bucket",
|
||||
"kind": "bucket-default-encryption"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_metadata": {
|
||||
"creation_date": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"deletion_date": "2026-02-01T00:00:00+00:00[UTC]",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"key_manager": "RUSTFS",
|
||||
"key_state": "Enabled",
|
||||
"key_usage": "EncryptDecrypt",
|
||||
"origin": "RUSTFS_KMS",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
}
|
||||
},
|
||||
"message": "key described successfully",
|
||||
"success": true
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(DescribeKmsKeyResponse\n{\n success: false, message: \"key not found\".to_string(), key_metadata: None,\n impact: None,\n})"
|
||||
---
|
||||
{
|
||||
"impact": null,
|
||||
"key_metadata": null,
|
||||
"message": "key not found",
|
||||
"success": false
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(GenerateDataKeyApiResponse\n{\n key_id: \"key-a\".to_string(), plaintext_key:\n \"cGxhaW50ZXh0LXBsYWNlaG9sZGVy\".to_string(), ciphertext_blob:\n \"Y2lwaGVydGV4dC1wbGFjZWhvbGRlcg==\".to_string(),\n})"
|
||||
---
|
||||
{
|
||||
"ciphertext_blob": "Y2lwaGVydGV4dC1wbGFjZWhvbGRlcg==",
|
||||
"key_id": "key-a",
|
||||
"plaintext_key": "cGxhaW50ZXh0LXBsYWNlaG9sZGVy"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(ListKeysApiResponse\n{\n keys: vec![snapshot_key_info()], truncated: true, next_marker:\n Some(\"key-b\".to_string()),\n})"
|
||||
---
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"algorithm": "AES_256",
|
||||
"created_at": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"created_by": "admin",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"metadata": {
|
||||
"origin": "RUSTFS_KMS"
|
||||
},
|
||||
"rotated_at": "2026-01-15T00:00:00+00:00[UTC]",
|
||||
"status": "Active",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
},
|
||||
"usage": "EncryptDecrypt",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"next_marker": "key-b",
|
||||
"truncated": true
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
---
|
||||
source: rustfs/src/admin/handlers/kms_keys.rs
|
||||
expression: "stable_json_value(ListKmsKeysResponse\n{\n success: true, message: \"keys listed\".to_string(), keys:\n vec![snapshot_key_info()], truncated: true, next_marker:\n Some(\"key-b\".to_string()),\n})"
|
||||
---
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"algorithm": "AES_256",
|
||||
"created_at": "2026-01-01T00:00:00+00:00[UTC]",
|
||||
"created_by": "admin",
|
||||
"description": "snapshot key",
|
||||
"key_id": "key-a",
|
||||
"metadata": {
|
||||
"origin": "RUSTFS_KMS"
|
||||
},
|
||||
"rotated_at": "2026-01-15T00:00:00+00:00[UTC]",
|
||||
"status": "Active",
|
||||
"tags": {
|
||||
"name": "key-a"
|
||||
},
|
||||
"usage": "EncryptDecrypt",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"message": "keys listed",
|
||||
"next_marker": "key-b",
|
||||
"success": true,
|
||||
"truncated": true
|
||||
}
|
||||
Reference in New Issue
Block a user