Conversation
…-purge to authorized/contained locations Reject REGISTER_TABLE requests whose metadata location or embedded table location is not authorized or contained within the namespace. Authorize DROP_TABLE purge against the table's location, and fence purge deletions to the table's own location as defense in depth. Co-Authored-By: Claude Code <noreply@anthropic.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 5
Open (5)
Adding a new public accessor for the internalFileIOincreases the public API surface of… · New Logging a WARN for every skipped deletion can flood logs during purge if a malicious/corrupt table… · New There are now multiple, slightly different containment/normalization implementations in the… · New The hard cast((HiveCatalog) catalog)can throwClassCastExceptionat runtime if this adapter… · NewFiles.deleteIfExists(Path.of(metadataLocation))assumesmetadataLocationis a local filesystem… · New
What changed in this PR
This PR tightens authorization around Iceberg REST catalog table registration and drop-table purge operations by validating locations (metadata/table) and adding a defense-in-depth deletion fence so purge cannot remove files outside the table location.
Changes:
- Add REGISTER_TABLE validation to authorize the metadata location and the embedded table location (or enforce namespace containment when no authorizer exists).
- Add DROP_TABLE purge authorization against the table’s location in the REST adapter.
- Fence purge deletions in
HiveCatalog.dropTable(..., purge=true)to the table’s own location via aFileIOwrapper.
| File | Description |
|---|---|
| standalone-metastore/metastore-rest-catalog/src/main/java/org/apache/iceberg/rest/IcebergAuthorizer.java | Adds register-table + drop-purge authorization/containment logic and URI normalization helpers. |
| standalone-metastore/metastore-rest-catalog/src/main/java/org/apache/iceberg/rest/HMSCatalogAdapter.java | Wires new authorization checks into REST endpoints for register-table and drop-table purge. |
| iceberg/iceberg-catalog/src/main/java/org/apache/iceberg/hive/HiveCatalog.java | Wraps purge deletion with a scoped FileIO and exposes catalog FileIO via a new accessor. |
| iceberg/iceberg-catalog/src/main/java/org/apache/iceberg/hive/ScopedDeleteFileIO.java | Introduces a FileIO decorator to skip deletions outside the table’s location. |
| standalone-metastore/metastore-rest-catalog/src/test/java/org/apache/iceberg/rest/*.java | Adds unit/integration tests covering authorization decisions and purge fencing behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| return name; | ||
| } | ||
|
|
||
| public FileIO io() { |
| public void deleteFile(String path) { | ||
| if (!isContained(location, normalize(path))) { | ||
| LOG.warn("Skipping delete outside table location {}: {}", location, path); | ||
| return; | ||
| } |
| private static boolean isContained(String root, String candidate) { | ||
| return candidate.equals(root) || candidate.startsWith(root.endsWith("/") ? root : root + "/"); | ||
| } | ||
|
|
||
| private static String normalize(String location) { | ||
| return new Path(location).toUri().normalize().toString(); | ||
| } |
| FileIO io = ((HiveCatalog) catalog).io(); | ||
| icebergAuthorizer.validateRegisterTable(catalogName, namespace, namespaceMetadata, request, io); | ||
| return castResponse(LoadTableResponse.class, CatalogHandlers.registerTable(catalog, namespace, request)); |
| private static String writeMetadataFile(String directory, String tableLocation) throws IOException { | ||
| var metadataLocation = directory + "/v1.metadata.json"; | ||
| Files.deleteIfExists(java.nio.file.Path.of(metadataLocation)); | ||
| var io = new HadoopFileIO(new Configuration(false)); | ||
| var metadata = TableMetadata.newTableMetadata(new Schema(), PartitionSpec.unpartitioned(), tableLocation, | ||
| Collections.emptyMap()); | ||
| TableMetadataParser.write(metadata, io.newOutputFile(metadataLocation)); | ||
| return metadataLocation; | ||
| } |
|




Summary
Test plan
mvn -pl standalone-metastore/metastore-rest-catalog,iceberg/iceberg-catalog -am test— 885 tests inmetastore-rest-catalog(0 failures/errors, 45 skipped Docker-dependent), 142 tests iniceberg-catalog(0 failures/errors, 16 skipped)🤖 Generated with Claude Code