This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-11614-069345b9b252342eff29ca0b1a85748625a5da40
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git

commit e905793f20b79d4431a678dd3bb0fedb8cfcab90
Author: autoCAT <[email protected]>
AuthorDate: Fri Oct 16 13:18:34 2026 +0000

    Redact Parquet encryption keys from Debug output (#11614)
    
    # Which issue does this PR close?
    
    Relates to #7373. This addresses Debug-output redaction; key-memory
    zeroization remains separate work.
    
    # Rationale for this change
    
    Debug-printing `FileEncryptionProperties`, or a `WriterProperties`
    configuration containing it, currently includes raw footer and column
    encryption keys. Logging these configurations can consequently expose
    the keys along with otherwise useful diagnostics.
    
    # What changes are included in this PR?
    
    Give the private `EncryptionKey` type a manual Debug implementation that
    prints only its type, following the existing `FileDecryptionProperties`
    formatting style. Enclosing encryption and writer configurations retain
    their other diagnostic fields.
    
    # Are these changes tested?
    
    Regression tests exercise ordinary and pretty Debug formatting through
    the public encryption properties, writer builder, and built writer
    properties. They fail against the previous derived implementation. The
    tests also verify that explicit key and key-metadata getters preserve
    their bytes.
    
    Both new regressions fail before the change and pass after it. The
    Parquet suite with encryption enabled passes (1,798 tests; 7 ignored),
    as does the full workspace suite (7,330 tests; 29 ignored). Workspace
    Clippy with all targets and features, formatting, and spelling checks
    pass. An independent path-dependent application also confirms that
    public encryption and writer configurations no longer expose either key.
    
    # Are there any significant user-facing changes?
    
    The public API and encryption behavior are unchanged. Debug formatting
    no longer includes the contents of the private key objects.
    
    Signed-off-by: Yanzhi Xin <[email protected]>
---
 parquet/src/encryption/encrypt.rs      |  9 ++++-
 parquet/tests/encryption/encryption.rs | 62 ++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/parquet/src/encryption/encrypt.rs 
b/parquet/src/encryption/encrypt.rs
index eb0cd09e83..591eac802d 100644
--- a/parquet/src/encryption/encrypt.rs
+++ b/parquet/src/encryption/encrypt.rs
@@ -26,15 +26,22 @@ use crate::parquet_thrift::{ThriftCompactOutputProtocol, 
WriteThrift};
 use crate::schema::types::{ColumnDescPtr, SchemaDescriptor};
 use ring::rand::{SecureRandom, SystemRandom};
 use std::collections::{HashMap, HashSet};
+use std::fmt::Formatter;
 use std::io::Write;
 use std::sync::Arc;
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
 struct EncryptionKey {
     key: Vec<u8>,
     key_metadata: Option<Vec<u8>>,
 }
 
+impl std::fmt::Debug for EncryptionKey {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(f, "EncryptionKey {{ }}")
+    }
+}
+
 impl EncryptionKey {
     fn new(key: Vec<u8>) -> EncryptionKey {
         Self {
diff --git a/parquet/tests/encryption/encryption.rs 
b/parquet/tests/encryption/encryption.rs
index 9a507ebf50..74d2bc364a 100644
--- a/parquet/tests/encryption/encryption.rs
+++ b/parquet/tests/encryption/encryption.rs
@@ -46,6 +46,68 @@ use parquet::schema::parser::parse_message_type;
 use std::fs::File;
 use std::sync::Arc;
 
+#[test]
+fn test_encryption_properties_key_debug_redaction() {
+    let footer_key = b"SYNTHETIC-FOOTER".to_vec();
+    let column_key = b"SYNTHETIC-COLUMN".to_vec();
+    let footer_key_metadata = b"footer-key-id".to_vec();
+    let column_key_metadata = b"column-key-id".to_vec();
+    let properties = FileEncryptionProperties::builder(footer_key.clone())
+        .with_footer_key_metadata(footer_key_metadata.clone())
+        .with_column_key_and_metadata(
+            "private_column",
+            column_key.clone(),
+            column_key_metadata.clone(),
+        )
+        .build()
+        .unwrap();
+
+    for output in [format!("{properties:?}"), format!("{properties:#?}")] {
+        let compact: String = output.split_whitespace().collect();
+        for key in [&footer_key, &column_key] {
+            let key_debug: String = 
format!("{key:?}").split_whitespace().collect();
+            assert!(!compact.contains(&key_debug));
+        }
+        assert!(output.contains("FileEncryptionProperties"));
+        assert!(output.contains("private_column"));
+    }
+
+    assert_eq!(properties.footer_key(), &footer_key);
+    assert_eq!(properties.footer_key_metadata(), Some(&footer_key_metadata));
+    assert_eq!(
+        properties.column_keys(),
+        (
+            vec!["private_column".to_string()],
+            vec![column_key],
+            vec![column_key_metadata],
+        )
+    );
+}
+
+#[test]
+fn test_writer_properties_key_debug_redaction() {
+    let footer_key = b"SYNTHETIC-FOOTER".to_vec();
+    let column_key = b"SYNTHETIC-COLUMN".to_vec();
+    let encryption = FileEncryptionProperties::builder(footer_key.clone())
+        .with_column_key("private_column", column_key.clone())
+        .build()
+        .unwrap();
+    let builder = 
WriterProperties::builder().with_file_encryption_properties(encryption);
+    let builder_debug = [format!("{builder:?}"), format!("{builder:#?}")];
+    let properties = builder.build();
+    for output in builder_debug
+        .into_iter()
+        .chain([format!("{properties:?}"), format!("{properties:#?}")])
+    {
+        let compact: String = output.split_whitespace().collect();
+        for key in [&footer_key, &column_key] {
+            let key_debug: String = 
format!("{key:?}").split_whitespace().collect();
+            assert!(!compact.contains(&key_debug));
+        }
+        assert!(output.contains("private_column"));
+    }
+}
+
 #[test]
 fn test_non_uniform_encryption_plaintext_footer() {
     fn non_uniform_encryption_plaintext_footer(footer_key: &[u8], column_keys: 
&[(&str, &[u8])]) {

Reply via email to