enh(rbac): column-level SELECT mask privilege for data desensitization#35005
Open
enh(rbac): column-level SELECT mask privilege for data desensitization#35005
Conversation
Agent-Logs-Url: https://github.com/taosdata/TDengine/sessions/d0aba723-2503-4048-8a6c-7e93e38590dd Co-authored-by: kailixu <7546098+kailixu@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add select permission mask display for sensitive data
Implement column-level SELECT mask privilege for data desensitization
Mar 31, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Implements column-level SELECT masking (“data desensitization”) so that columns granted via mask(col) are returned as '*' instead of their real values, by translating masked projection columns into mask_full(col, '*') and adding coverage in RBAC privilege tests.
Changes:
- Parser translation: mark masked projection columns based on auth results and rewrite them to
mask_full(col, '*'). - Function layer: broaden
mask_fulltype support and adjust scalar execution to avoid charset conversion for non-string types. - Tests: add RBAC coverage for masked columns across normal tables, supertables/child tables, and masked tags (including JSON tags).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
source/libs/parser/src/parTranslater.c |
Sets hasMask on projected columns from privilege auth results and rewrites masked projections into mask_full calls. |
source/libs/function/src/builtins.c |
Expands mask_full builtin signature to accept additional variable-length types. |
source/libs/scalar/src/sclfunc.c |
Updates maskFullFunction to only do NCHAR/VARCHAR charset conversion and otherwise copy mask bytes directly. |
test/cases/25-Privileges/test_priv_rbac.py |
Adds an RBAC test that validates masked output for multiple column/tag types and table kinds. |
Comments suppressed due to low confidence (1)
source/libs/function/src/builtins.c:7151
mask_fullis being broadened to accept/return VARBINARY/GEOMETRY/JSON types. SincetranslateMaskFull()sets the function result type to the input type,mask_full(<json>, '*')ormask_full(<geometry>, '*')will produce a JSON/GEOMETRY-typed value containing'*', which may be an invalid representation for those types and could lead to unexpected client decoding/printing behavior. If the intent is only to support privilege-driven masking as a textual'*', consider keepingmask_full's public signature string-only and handling non-string masking via an internal wrapper/cast to VARCHAR at translation time (or adjusttranslateMaskFullto return VARCHAR for these non-displayable types).
.name = "mask_full",
.type = FUNCTION_TYPE_MASK_FULL,
.classification = FUNC_MGT_SCALAR_FUNC | FUNC_MGT_STRING_FUNC,
.parameters = {.minParamNum = 2,
.maxParamNum = 2,
.paramInfoPattern = 1,
.inputParaInfo[0][0] = {.isLastParam = true,
.startParam = 1,
.endParam = 2,
.validDataType = FUNC_PARAM_SUPPORT_VARCHAR_TYPE | FUNC_PARAM_SUPPORT_NCHAR_TYPE | FUNC_PARAM_SUPPORT_VARB_TYPE | FUNC_PARAM_SUPPORT_GEOMETRY_TYPE | FUNC_PARAM_SUPPORT_JSON_TYPE | FUNC_PARAM_SUPPORT_NULL_TYPE,
.validNodeType = FUNC_PARAM_SUPPORT_EXPR_NODE,
.paramAttribute = FUNC_PARAM_NO_SPECIFIC_ATTRIBUTE,
.valueRangeFlag = FUNC_PARAM_NO_SPECIFIC_VALUE,},
.outputParaInfo = {.validDataType = FUNC_PARAM_SUPPORT_VARCHAR_TYPE | FUNC_PARAM_SUPPORT_NCHAR_TYPE | FUNC_PARAM_SUPPORT_VARB_TYPE | FUNC_PARAM_SUPPORT_GEOMETRY_TYPE | FUNC_PARAM_SUPPORT_JSON_TYPE}},
.translateFunc = translateMaskFull,
.getEnvFunc = NULL,
.initFunc = NULL,
.sprocessFunc = maskFullFunction,
.finalizeFunc = NULL
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a column is granted with
mask(col)in a SELECT privilege, querying that column should display*instead of the actual value. The translation layer had a stub (#ifdef PRIV_TODO) that detected mask flags but never acted on them.Changes
source/libs/parser/src/parTranslater.c(#ifdef TD_ENTERPRISE)setMaskFlagOnProjCol()— After auth check, marks matchingSColumnNodeentries in the projection list withhasMask=1using the(tableId, colId)pair from the auth result.translateCheckPrivCols()— Extended: whenIS_MASK_ON(pColNameFlag)is true, callssetMaskFlagOnProjCol(withkeyLenguard before hash key deref). Replaces the previoushasMaskCols==0single-fire guard with unconditional marking.createMaskFuncNode()— Builds amask_full(col, '*')SFunctionNodefor a marked column; only applies to VARCHAR/NCHAR (the typesmask_fullsupports). Column clone hashasMaskcleared to prevent re-entrant masking.fmGetFuncInforesolvesfuncIdandresType.translateProcessMaskColFunc()— Fully implemented: walks projection list, replaces eachhasMask=1column node with itsmask_fullwrapper viaREPLACE_NODE.#ifdef PRIV_TODOstub and now-dead helpers (rewriteMaskColFunc,checkMaskNode,nodesCheckMaskNode,SCheckMaskNodeCxt).test/cases/25-Privileges/test_priv_rbac.pyAdded
do_check_column_mask_privileges():Covers normal tables, supertable child tables, masked tag columns, and permission-denied error for columns outside the grant.
Original prompt
总体目标:我要开发一个新的功能,列 select 权限指定 mask 时,脱敏展示,在 select 时,结果展示为 *。需要功能实现,测试用例在 test_priv_rbac.py 中添加,如果不存在的话。
开发分支:main
本地路径:/proj/github/3.imb/TDinternal 为企业版分支,/proj/github/3.imb/TDinternal/community 为社区版分支。
该功能已经包含部分函数,例如,tanslateProcessMaskColFunc,但是,未完成实现(具体实现以你为准,只用于参考),且包含在未定义的 宏 #ifdef PRIV_TODO 中。具体需求如下:
[Chronological Review: The conversation began with the user requesting the development of a new feature for displaying masked select permissions in a database context. The user provided detailed SQL examples and specified the need for test cases in a particular Python file. The user also mentioned existing functions and macros related to the feature. The conversation included multiple requests for clarification and reiteration of the feature requirements, culminating in a cancellation command to delegate to a cloud agent, which was subsequently retracted.]以下列SQL为例:
drop database if exists d0;
create database d0;
use d0;
create table stb0 (ts timestamp, c0 int, c1 varchar(20),c2 nchar(20)) tags(t0 int, t1 varchar(20), t2 nchar(20));
create table ctb0 using stb0 tags(0,'0','0');
create table ntb0 (ts timestamp, c0 int, c1 varchar(20),c2 nchar(20));
insert into ctb0 values(now,0,'0','0');
insert into ctb0 values(now+1s,1,'1','1');
insert into ntb0 values(now,0,'0','0');
insert into ntb0 values(now+1s,1,'1','1');
create user u1 pass 'taosdata_12345';
grant select(mask(c1),mask(c2),mask(t1),mask(t2)) on table d0.stb0 to u1;
grant select(mask(c1),mask(c2)) on table d0.ntb0 to u1;
show user privileges;
select * from stb0;
select * from ctb0;
select * from ntb0;
针对用户 u1,列权限设置 mask,结果展示时,脱敏展示。在处理结果展示时,借用 maskFullFunction 函数的实现处理结果展示。maskFullFunction 原本是用于在应用层,用户指定的脱敏函数,而非数据库层通过权限指定的脱敏展示。如果 maskFullFunction 不能直接调用,将 maskFullFunction 调用或者出入参进行一定的重构也可以。
[Intent Mapping: The user explicitly requested the development of a feature for masked select permissions, stating: "我要开发一个新的功能,列 select 权限指定 mask 时,脱敏展示,在 select 时,结果展示为 *。" They also requested the addition of test cases in the specified Python file if they did not already exist.]
[Technical Inventory: Technologies mentioned include SQL for database operations, Python for test case implementation, and specific functions like
tanslateProcessMaskColFuncandmaskFullFunction. The user referenced a macro#ifdef PRIV_TODOthat indicates incomplete functionality.][Code Archaeology: The user is working on the file
/proj/github/3.imb/TDinternal/community/test/cases/25-Privileges/test_priv_rbac.py. They provided SQL commands for creating databases and tables, inserting data, and granting user permissions. The focus is on implementing a feature that masks sensitive data in query results.][Progress Assessment: The user has outlined the feature requirements and provided SQL examples but has not yet implemented the functionality or test cases. The user is in the planning phase, detailing how the feature should behave.]
[Context Validation: All critical information for continuation is captured, including the specific SQL commands, user permissions, and the need for test cases in the specified Python file.]
[Recent Commands Analysis: The last agent command was a cancellation of a previous request to "Delegate to cloud agent." No specific tool results were generated from this command as it was a cancellation. The agent was actively working on understanding the user's requirements for the feature implementation when the token budget was exceeded. The user’s goal is to implement a feature for masked select permissions in a database context, which connects to the overall objective of enhancing data security.]
1. Conversation Overview: - Primary Objectives: The user aims to develop a feature for displaying masked select permissions in a database, specifically stating: "我要开发一个新的功能,列 select 权限指定 mask 时,脱敏展示,在 select 时,结果展示为 *。" They also requested test cases in `test_priv_rbac.py`. - Session Context: The conversation has revolved around the user's detailed requirements for the feature, including SQL examples and existing functions. The user has reiterated their needs multiple times and attempted to delegate tasks to a cloud agent, which was later canceled. - User Intent Evolution: The user's focus has remained consistent on developing the masking feature and ensuring proper testing, with no significant shifts in direction.- Technical Foundation:
- SQL: Used for database operations and defining user permissions.
- Python: For implementing test cases in the specified file.
- Functions:
- Codebase Status:
- File Name:
- Purpose: To contain test cases for the new masking feature.
- Current State: No modifications have been made yet; the user is still in the planning phase.
- Key Code Segments: SQL commands provided by the user for creating databases, tables, and user permissions.
- Dependencies: The implementation...
tanslateProcessMaskColFuncandmaskFullFunctionare relevant to the feature's implementation.test_priv_rbac.pyCreated from VS Code.