Skip to content

feat(tables): gate RTAS per-table behind 'replace.enabled' table property#2

Closed
jiang95-dev wants to merge 2 commits into
mainfrom
lejiang/gate-rtas
Closed

feat(tables): gate RTAS per-table behind 'replace.enabled' table property#2
jiang95-dev wants to merge 2 commits into
mainfrom
lejiang/gate-rtas

Conversation

@jiang95-dev

Copy link
Copy Markdown
Owner

Summary

Add a per-table flag that gates the RTAS (Replace Table As Select) command. RTAS is now blocked by default and is only permitted when the table has the regular table property replace.enabled set to true. The gate reads the table's persisted properties (not the incoming request body), so it cannot be bypassed by the same request that performs the replace, and it is independent of the existing creator-only replace check.

Changes

  • Client-facing API Changes
  • New Features
  • Tests

Details:

  • New per-table flag: regular table property replace.enabled (default absent/false ⇒ RTAS blocked). Constant AuthorizationUtils.RTAS_ENABLED_TABLE_PROP.
  • Enforcement: new AuthorizationUtils.checkReplaceTableEnabled(TableDto) throws UnsupportedClientOperationException(RTAS_ON_DISABLED_TABLE) (HTTP 400) when the property is not true. Called from:
    • TablesServiceImpl.putTable on the stageReplace path.
    • IcebergSnapshotsServiceImpl.putIcebergSnapshots on the replaceCommit path.
  • Added RTAS_ON_DISABLED_TABLE to UnsupportedClientOperationException.Operation.
  • To allow RTAS on a table, set the property (e.g. Spark: ALTER TABLE db.t SET TBLPROPERTIES ('replace.enabled'='true')).

Testing Done

  • Added new tests for the changes made.
  • Updated existing tests to reflect the changes made.

For all the boxes checked:

  • services/tables unit/e2e tests run and pass locally (:services:tables:test for TablesControllerTest, SnapshotsControllerTest, PoliciesSpecMapperTest, TableDtoMappingTest).
  • Added TablesControllerTest.testStagedReplaceFailsWhenRtasDisabled (asserts 400 + message when replace.enabled is not set).
  • Updated testStagedReplace and testPutSnapshotsReplaceCommit to opt in via the property.
  • Opted in the Spark/app RTAS integration tests so they reflect the new default: RTASTest (4 cases), RTASJavaTest (2 cases), OperationsTest RTAS case.
  • Local code review completed

Additional Information

  • Breaking Changes

Existing tables that relied on RTAS will be blocked until replace.enabled=true is set on them. This is the intended opt-in default for gating the destructive replace operation.

Levi Jiang and others added 2 commits June 24, 2026 13:18
…erty

Add a per-table flag that gates the RTAS (Replace Table As Select)
command. RTAS is now blocked by default and is only allowed when the
table has the regular table property 'replace.enabled' set to true.

The gate is enforced in TablesServiceImpl (stageReplace) and
IcebergSnapshotsServiceImpl (replaceCommit) via
AuthorizationUtils.checkReplaceTableEnabled, which reads the table's
persisted properties (so it cannot be bypassed by the incoming request
body) and returns HTTP 400 when RTAS is disabled.

Updated existing replace tests to opt in, added a negative test, and
opted in the Spark/app RTAS integration tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add RTASTest.testRTASFailsWhenReplaceDisabled which creates a table
without opting into RTAS and asserts that REPLACE TABLE ... AS SELECT is
rejected with a BadRequestException carrying the "Replace (RTAS) is not
enabled" message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jiang95-dev

Copy link
Copy Markdown
Owner Author

Superseded by linkedin#640 (published upstream).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant