mikebridge opened a new pull request, #43827:
URL: https://github.com/apache/superset/pull/43827
### SUMMARY
Hardening follow-up to **#43474**, which added masking of write-only
configuration fields on the semantic-layer read endpoints. That masker scans
only the schema's **top-level** `properties`, so a secret nested inside an
object, a discriminated union, or a list is still returned in the clear — for
example a Snowflake `auth.password` `SecretStr` inside a `password`/`key`
auth
union leaks on `GET /api/v1/semantic_layer/<uuid>`.
This extends #43474 (it does not replace it): the masking now walks the
connector's published `get_configuration_schema()` **recursively**, keeping
#43474's established behavior — mask only fields the schema marks secret
(`writeOnly` / `SecretStr`), reveal everything else, and fail closed by
masking
the whole payload when the schema can't be loaded — while catching secrets at
any depth.
**What changed**
- New `superset/semantic_layers/masking.py`: a schema-directed walker
(`mask_configuration` / `unmask_configuration`) that resolves `$ref` into
`$defs` and descends objects, unions (`anyOf`/`oneOf`/`allOf`), and lists.
For a key described by several union variants it masks the key if **any**
variant marks it secret.
- `_serialize_layer` (read) and `UpdateSemanticLayerCommand`'s round-trip
(write) now delegate to it, so masking and the masked-value passthrough
become recursive together: a nested masked value a client echoes back on
update is restored from the stored config, not written as the mask string.
- **Review Finding 1**: free-form keys governed by `additionalProperties` are
classified against every union variant, not just the first, so a variant
marking such a key secret can't be overridden by an earlier variant that
would reveal it.
- **Review Finding 5**: the module docstring records the provider contract
that
`get_configuration_schema` / `get_runtime_schema` responses (returned to
clients verbatim, e.g. the `runtime_schema` endpoint) must not echo
configuration values back into the schema — masking covers the stored
payload, not a schema built from it.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A — API masking change, no UI surface.
Before: a nested/union secret (e.g. `configuration.auth.password`) is
returned
in the clear by the read endpoints. After: it is `XXXXXXXXXX`, like the
top-level secrets #43474 already masked.
### TESTING INSTRUCTIONS
```
pytest tests/unit_tests/semantic_layers/
```
New/adapted masking unit tests to 100% package coverage: nested/union/list
secret masking (the closed gap), reveal of undescribed and non-secret fields
(matching #43474), the `additionalProperties`-divergence case (Finding 1),
and
every fail-closed path (unregistered type, schema raises, non-dict schema,
pathological recursion depth). #43474's own `api_test`/`update_test` pass
unchanged against the delegating functions.
### ADDITIONAL INFORMATION
- [x] Required feature flags: `SEMANTIC_LAYERS` (development, default off)
- [ ] Changes UI
- [ ] Includes DB Migration
- [x] Bugfix (security hardening; extends #43474)
Credit: builds directly on the masking pattern and provider-schema source
established in #43474.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]