feat(table-catalog): add credential endpoint boundary (#3407)

* feat(table-catalog): add credential scope boundary

* feat(table-catalog): add credential endpoint boundary

* fix(table-catalog): remove redundant scope clone

---------

Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
This commit is contained in:
Henry Guo
2026-06-13 21:26:59 +08:00
committed by GitHub
parent 6b1e114b39
commit 49a893f010
7 changed files with 220 additions and 6 deletions
+15 -1
View File
@@ -112,13 +112,27 @@ added.
Unsupported behavior is documented instead of hidden behind internal errors. The
current unsupported inventory is:
- credential vending: unsupported response boundary exists; real temporary credentials are not issued
- credential vending: non-secret table scope preview and credentials endpoint exist; real temporary credentials are not issued
- background maintenance worker: unsupported
- manifest/data reachability cleanup: unsupported
- snapshot expiration and compaction: unsupported
- Iceberg views: unsupported
- multi-table transactions: not a short-term production claim
## Credential Boundary
RustFS advertises table credential scope metadata without returning reusable
storage secrets. `loadTable` includes the table warehouse prefix in the response
config, and the standard credentials endpoint is registered:
```text
GET /v1/{prefix}/namespaces/{namespace}/tables/{table}/credentials
```
The endpoint returns an empty `storage-credentials` list until temporary,
table-scoped credential issuance is implemented. Clients should continue using
their configured S3 credentials for object data access.
## Spark Manual Baseline
Spark validation should use the same RustFS endpoint and warehouse bucket as the
+3 -2
View File
@@ -111,9 +111,10 @@ CLIENT_MATRIX: list[dict[str, str]] = [
UNSUPPORTED_INVENTORY: list[dict[str, str]] = [
{
"capability": "credential-vending",
"status": "unsupported-response-boundary",
"status": "scope-preview-no-temporary-credentials",
"roadmap_area": "credential-boundary",
"expected_behavior": "load table advertises rustfs.credential-vending=unsupported and returns no long-lived credentials",
"catalog_endpoint": "GET /v1/{prefix}/namespaces/{namespace}/tables/{table}/credentials",
"expected_behavior": "load table advertises the table credential scope; the credentials endpoint returns an empty storage-credentials list and no long-lived credentials",
},
{
"capability": "background-maintenance-worker",
@@ -4,13 +4,19 @@
from __future__ import annotations
import os
import re
import sys
import unittest
from pathlib import Path
from unittest import mock
import pyiceberg_smoke
INTERNAL_ROADMAP_LABEL_RE = re.compile(r"\b(?:PR|PG|P)[0-9]+\b")
SCRIPT_DIR = Path(__file__).resolve().parent
class PyIcebergSmokeConfigTest(unittest.TestCase):
def parse_with_args(self, argv: list[str]) -> object:
env_keys = [
@@ -70,6 +76,12 @@ class PyIcebergSmokeConfigTest(unittest.TestCase):
self.assertIn("status", entry)
self.assertIn("roadmap_area", entry)
def test_published_table_catalog_docs_do_not_use_internal_roadmap_labels(self) -> None:
readme = (SCRIPT_DIR / "README.md").read_text(encoding="utf-8")
self.assertIsNone(INTERNAL_ROADMAP_LABEL_RE.search(readme))
self.assertIsNone(INTERNAL_ROADMAP_LABEL_RE.search(str(pyiceberg_smoke.unsupported_inventory())))
if __name__ == "__main__":
unittest.main()