Skip to content

enh(rbac): column-level SELECT mask privilege for data desensitization#35005

Open
Copilot wants to merge 14 commits intomainfrom
copilot/add-select-permission-mask-display
Open

enh(rbac): column-level SELECT mask privilege for data desensitization#35005
Copilot wants to merge 14 commits intomainfrom
copilot/add-select-permission-mask-display

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

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 matching SColumnNode entries in the projection list with hasMask=1 using the (tableId, colId) pair from the auth result.
  • translateCheckPrivCols() — Extended: when IS_MASK_ON(pColNameFlag) is true, calls setMaskFlagOnProjCol (with keyLen guard before hash key deref). Replaces the previous hasMaskCols==0 single-fire guard with unconditional marking.
  • createMaskFuncNode() — Builds a mask_full(col, '*') SFunctionNode for a marked column; only applies to VARCHAR/NCHAR (the types mask_full supports). Column clone has hasMask cleared to prevent re-entrant masking. fmGetFuncInfo resolves funcId and resType.
  • translateProcessMaskColFunc() — Fully implemented: walks projection list, replaces each hasMask=1 column node with its mask_full wrapper via REPLACE_NODE.
  • Removed the #ifdef PRIV_TODO stub and now-dead helpers (rewriteMaskColFunc, checkMaskNode, nodesCheckMaskNode, SCheckMaskNodeCxt).

test/cases/25-Privileges/test_priv_rbac.py

Added do_check_column_mask_privileges():

-- root setup
grant select(c0, mask(c1), mask(c2), mask(t1), mask(t2)) on table d_mask.stb_mask to u_mask;
grant select(c0, mask(c1), mask(c2)) on table d_mask.ntb_mask to u_mask;

-- querying as u_mask
select c0, c1, c2 from d_mask.ntb_mask;
-- c0 → 2 (real value), c1 → '*', c2 → '*'

select c0, c1, c2, t1, t2 from d_mask.ctb_mask;
-- c0 → 1, c1/c2/t1/t2 → '*'

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 中。具体需求如下:
以下列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 调用或者出入参进行一定的重构也可以。

[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.]

[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 tanslateProcessMaskColFunc and maskFullFunction. The user referenced a macro #ifdef PRIV_TODO that 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.
  1. Technical Foundation:
  • SQL: Used for database operations and defining user permissions.
  • Python: For implementing test cases in the specified file.
  • Functions: tanslateProcessMaskColFunc and maskFullFunction are relevant to the feature's implementation.
  1. Codebase Status:
  • File Name: test_priv_rbac.py
  • 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...

Created from VS Code.

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
Copilot AI requested a review from kailixu March 31, 2026 03:19
@kailixu kailixu marked this pull request as ready for review March 31, 2026 09:02
@kailixu kailixu requested a review from guanshengliang as a code owner March 31, 2026 09:02
Copilot AI review requested due to automatic review settings March 31, 2026 09:02
@kailixu kailixu requested review from a team and dapan1121 as code owners March 31, 2026 09:02
@kailixu kailixu changed the title Implement column-level SELECT mask privilege for data desensitization enh(rbac): column-level SELECT mask privilege for data desensitization Mar 31, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_full type 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_full is being broadened to accept/return VARBINARY/GEOMETRY/JSON types. Since translateMaskFull() sets the function result type to the input type, mask_full(<json>, '*') or mask_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 keeping mask_full's public signature string-only and handling non-string masking via an internal wrapper/cast to VARCHAR at translation time (or adjust translateMaskFull to 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.

@kailixu kailixu requested a review from zitsen as a code owner April 7, 2026 07:17
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.

3 participants