From 32ebd8eaf956ab271e3629b12b125e6ea9d03fe3 Mon Sep 17 00:00:00 2001 From: Sreesh Maheshwar Date: Sun, 6 Sep 2026 23:01:09 +0100 Subject: [PATCH 1/2] feat(io): expose FileIO configuration properties --- src/iceberg/arrow/s3/arrow_s3_file_io.cc | 4 ++++ src/iceberg/file_io.h | 7 +++++++ src/iceberg/resolving_file_io.h | 4 ++++ src/iceberg/test/arrow_s3_file_io_test.cc | 12 ++++++++++++ src/iceberg/test/rest_file_io_test.cc | 12 ++++++++++++ 5 files changed, 39 insertions(+) diff --git a/src/iceberg/arrow/s3/arrow_s3_file_io.cc b/src/iceberg/arrow/s3/arrow_s3_file_io.cc index 7b9f1d4d6..f007d3ff2 100644 --- a/src/iceberg/arrow/s3/arrow_s3_file_io.cc +++ b/src/iceberg/arrow/s3/arrow_s3_file_io.cc @@ -213,6 +213,10 @@ class ArrowS3FileIO final : public FileIO, public SupportsStorageCredentials { return storage_credentials_; } + const std::unordered_map& properties() const override { + return default_properties_; + } + SupportsStorageCredentials* AsSupportsStorageCredentials() override { return this; } private: diff --git a/src/iceberg/file_io.h b/src/iceberg/file_io.h index 3ea4afa49..7f16d7487 100644 --- a/src/iceberg/file_io.h +++ b/src/iceberg/file_io.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "iceberg/iceberg_export.h" @@ -180,6 +181,12 @@ class ICEBERG_EXPORT FileIO { /// \brief Return storage-credential support when implemented by this FileIO. virtual SupportsStorageCredentials* AsSupportsStorageCredentials() { return nullptr; } + + /// \brief Return this FileIO's configuration properties (empty by default). + virtual const std::unordered_map& properties() const { + static const std::unordered_map kEmpty; + return kEmpty; + } }; /// \brief Mix-in for FileIO implementations that route object paths to diff --git a/src/iceberg/resolving_file_io.h b/src/iceberg/resolving_file_io.h index 837afd60e..ce8928fbe 100644 --- a/src/iceberg/resolving_file_io.h +++ b/src/iceberg/resolving_file_io.h @@ -60,6 +60,10 @@ class ICEBERG_EXPORT ResolvingFileIO final : public FileIO, const std::vector& credentials() const override; + const std::unordered_map& properties() const override { + return properties_; + } + SupportsStorageCredentials* AsSupportsStorageCredentials() override { return this; } private: diff --git a/src/iceberg/test/arrow_s3_file_io_test.cc b/src/iceberg/test/arrow_s3_file_io_test.cc index 721c9ae2b..bd27999ef 100644 --- a/src/iceberg/test/arrow_s3_file_io_test.cc +++ b/src/iceberg/test/arrow_s3_file_io_test.cc @@ -175,6 +175,18 @@ TEST_F(ArrowS3FileIOTest, StoresCredentials) { EXPECT_EQ(credentialed->credentials(), credentials); } +TEST_F(ArrowS3FileIOTest, PropertiesExposeFileIOConfiguration) { + auto result = MakeS3FileIO({{std::string(S3Properties::kClientRegion), "us-east-1"}, + {std::string(S3Properties::kAccessKeyId), "key"}, + {std::string(S3Properties::kSecretAccessKey), "secret"}}); + ASSERT_THAT(result, IsOk()); + + const auto& properties = result.value()->properties(); + EXPECT_EQ(properties.at(std::string(S3Properties::kClientRegion)), "us-east-1"); + EXPECT_EQ(properties.at(std::string(S3Properties::kAccessKeyId)), "key"); + EXPECT_EQ(properties.at(std::string(S3Properties::kSecretAccessKey)), "secret"); +} + TEST_F(ArrowS3FileIOTest, SkipsNonS3CredentialPrefix) { auto result = MakeS3FileIO({}); ASSERT_THAT(result, IsOk()); diff --git a/src/iceberg/test/rest_file_io_test.cc b/src/iceberg/test/rest_file_io_test.cc index dde3238a8..400111d07 100644 --- a/src/iceberg/test/rest_file_io_test.cc +++ b/src/iceberg/test/rest_file_io_test.cc @@ -95,6 +95,18 @@ TEST(RestFileIOTest, DefaultResolverDelegatesThroughRegistry) { EXPECT_THAT(result.value()->DeleteFile("rest-test://file"), IsOk()); } +TEST(RestFileIOTest, DefaultResolverExposesMergedProperties) { + auto result = MakeTableFileIO({{"catalog-only", "catalog"}, {"shared", "catalog"}}, + {{"table-only", "table"}, {"shared", "table"}}, + /*storage_credentials=*/{}); + ASSERT_THAT(result, IsOk()); + + EXPECT_THAT(result.value()->properties(), + ::testing::UnorderedElementsAre(::testing::Pair("catalog-only", "catalog"), + ::testing::Pair("table-only", "table"), + ::testing::Pair("shared", "table"))); +} + TEST(RestFileIOTest, MakeCatalogFileIOPassesThroughCustomImpl) { const std::string custom_impl = "com.mycompany.CustomFileIO"; FileIORegistry::Register( From cdbb4978b579da08f89d4273edb5e98daf1cefb0 Mon Sep 17 00:00:00 2001 From: Sreesh Maheshwar Date: Sun, 6 Sep 2026 23:09:12 +0100 Subject: [PATCH 2/2] docs: warn that FileIO properties may be sensitive --- src/iceberg/file_io.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/iceberg/file_io.h b/src/iceberg/file_io.h index 7f16d7487..9bf87f4b8 100644 --- a/src/iceberg/file_io.h +++ b/src/iceberg/file_io.h @@ -182,7 +182,10 @@ class ICEBERG_EXPORT FileIO { /// \brief Return storage-credential support when implemented by this FileIO. virtual SupportsStorageCredentials* AsSupportsStorageCredentials() { return nullptr; } - /// \brief Return this FileIO's configuration properties (empty by default). + /// \brief Return the configuration used to create this FileIO. + /// + /// The returned map may contain credentials. Callers must not log or expose it. + /// Implementations that do not expose their configuration return an empty map. virtual const std::unordered_map& properties() const { static const std::unordered_map kEmpty; return kEmpty;