Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 56ca9d7

Browse files
committed
Enhance localization and entity type management
- Updated built-in sensitive data types to include SYS suffix for consistency across documentation and code. - Implemented functionality to disable and enable entity types for tenants, allowing for more flexible data security configurations. - Added user language preference handling during login and updated language detection logic to prioritize user settings. - Improved frontend components to reflect changes in entity type codes and added language switcher for better user experience.
1 parent de0022a commit 56ca9d7

File tree

20 files changed

+509
-60
lines changed

20 files changed

+509
-60
lines changed

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ curl -X POST "http://localhost:5001/v1/guardrails" \
159159
* Three risk levels: low, medium, high
160160
* Six masking methods: replace, mask, hash, encrypt, shuffle, random
161161
* Configurable input/output direction detection
162-
* Built-in types: ID_CARD_NUMBER, PHONE_NUMBER, EMAIL, BANK_CARD_NUMBER, PASSPORT_NUMBER, IP_ADDRESS
162+
* Built-in types: ID_CARD_NUMBER_SYS, PHONE_NUMBER_SYS, EMAIL_SYS, BANK_CARD_NUMBER_SYS, PASSPORT_NUMBER_SYS, IP_ADDRESS_SYS
163163

164164
* 📊 **Enhanced Detection Results**
165165

@@ -199,9 +199,9 @@ curl -X POST "http://localhost:5001/v1/guardrails" \
199199
"result": {
200200
"compliance": {"risk_level": "Safe", "categories": []},
201201
"security": {"risk_level": "Safe", "categories": []},
202-
"data": {"risk_level": "High", "categories": ["PHONE_NUMBER", "ID_CARD_NUMBER"]}
202+
"data": {"risk_level": "High", "categories": ["PHONE_NUMBER_SYS", "ID_CARD_NUMBER_SYS"]}
203203
},
204-
"suggest_answer": "My phone is <PHONE_NUMBER>, ID is <ID_CARD_NUMBER>"
204+
"suggest_answer": "My phone is <PHONE_NUMBER_SYS>, ID is <ID_CARD_NUMBER_SYS>"
205205
}
206206
```
207207

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ Xiangxin AI Guardrails v2.4.0 introduces **Data Leak Detection** capability to p
982982
- **Three Risk Levels**: Low, Medium, High risk classification
983983
- **Configurable Detection Direction**: Input/Output detection control
984984
- **Multiple Masking Methods**:
985-
- **Replace**: Replace with placeholder tokens (e.g., `<PHONE_NUMBER>`)
985+
- **Replace**: Replace with placeholder tokens (e.g., `<PHONE_NUMBER_SYS>`)
986986
- **Mask**: Partial masking (e.g., `139****5678`)
987987
- **Hash**: SHA256 hashing
988988
- **Encrypt**: Encryption processing
@@ -991,12 +991,12 @@ Xiangxin AI Guardrails v2.4.0 introduces **Data Leak Detection** capability to p
991991

992992
### 📋 Built-in Sensitive Data Types
993993

994-
- **ID_CARD_NUMBER**: Chinese ID card numbers
995-
- **PHONE_NUMBER**: Mobile phone numbers
996-
- **EMAIL**: Email addresses
997-
- **BANK_CARD_NUMBER**: Bank card numbers
998-
- **PASSPORT_NUMBER**: Passport numbers
999-
- **IP_ADDRESS**: IP addresses
994+
- **ID_CARD_NUMBER_SYS**: Chinese ID card numbers
995+
- **PHONE_NUMBER_SYS**: Mobile phone numbers
996+
- **EMAIL_SYS**: Email addresses
997+
- **BANK_CARD_NUMBER_SYS**: Bank card numbers
998+
- **PASSPORT_NUMBER_SYS**: Passport numbers
999+
- **IP_ADDRESS_SYS**: IP addresses
10001000
- **CREDIT_CARD**: Credit card numbers
10011001
- **SSN**: Social Security Numbers
10021002

@@ -1017,22 +1017,22 @@ Prevents models from leaking sensitive data to users.
10171017
```json
10181018
{
10191019
"id": "guardrails-6048ed54e2bb482d894d6cb8c3842153",
1020-
"overall_risk_level": "高风险",
1021-
"suggest_action": "代答",
1022-
"suggest_answer": "我的电话号码是<PHONE_NUMBER>,银行卡号是<BANK_CARD_NUMBER>,身份证号是<ID_CARD_NUMBER>",
1020+
"overall_risk_level": "high_risk",
1021+
"suggest_action": "replace",
1022+
"suggest_answer": "My phone number is <PHONE_NUMBER_SYS>, bank card number is <BANK_CARD_NUMBER_SYS>, ID card number is <ID_CARD_NUMBER_SYS>",
10231023
"score": 0.999998927117538,
10241024
"result": {
10251025
"compliance": {
1026-
"risk_level": "无风险",
1026+
"risk_level": "no_risk",
10271027
"categories": []
10281028
},
10291029
"security": {
1030-
"risk_level": "无风险",
1030+
"risk_level": "no_risk",
10311031
"categories": []
10321032
},
10331033
"data": {
1034-
"risk_level": "高风险",
1035-
"categories": ["BANK_CARD_NUMBER", "ID_CARD_NUMBER", "PHONE_NUMBER"]
1034+
"risk_level": "high_risk",
1035+
"categories": ["BANK_CARD_NUMBER_SYS", "ID_CARD_NUMBER_SYS", "PHONE_NUMBER_SYS"]
10361036
}
10371037
}
10381038
}
@@ -1095,7 +1095,7 @@ response = requests.post(
10951095
headers={"Authorization": "Bearer your-api-key"},
10961096
json={
10971097
"name": "High Risk Behavior Ban",
1098-
"risk_level": "高风险",
1098+
"risk_level": "high_risk",
10991099
"trigger_count": 3,
11001100
"time_window_minutes": 60,
11011101
"ban_duration_minutes": 1440,

README_ZH.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,7 @@ def chat_with_openai(prompt, model="Xiangxin-Guardrails-Text"):
995995
- **三级风险等级**:低、中、高风险分类
996996
- **可配置检测方向**:输入/输出检测控制
997997
- **多种脱敏方法**
998-
- **替换(Replace)**:替换为占位符标记(如:`<PHONE_NUMBER>`
998+
- **替换(Replace)**:替换为占位符标记(如:`<PHONE_NUMBER_SYS>`
999999
- **掩码(Mask)**:部分掩码显示(如:`139****5678`
10001000
- **哈希(Hash)**:SHA256哈希加密
10011001
- **加密(Encrypt)**:加密处理
@@ -1004,12 +1004,12 @@ def chat_with_openai(prompt, model="Xiangxin-Guardrails-Text"):
10041004

10051005
### 📋 内置敏感数据类型
10061006

1007-
- **ID_CARD_NUMBER**:身份证号
1008-
- **PHONE_NUMBER**:手机号
1009-
- **EMAIL**:邮箱地址
1010-
- **BANK_CARD_NUMBER**:银行卡号
1011-
- **PASSPORT_NUMBER**:护照号
1012-
- **IP_ADDRESS**:IP地址
1007+
- **ID_CARD_NUMBER_SYS**:身份证号
1008+
- **PHONE_NUMBER_SYS**:手机号
1009+
- **EMAIL_SYS**:邮箱地址
1010+
- **BANK_CARD_NUMBER_SYS**:银行卡号
1011+
- **PASSPORT_NUMBER_SYS**:护照号
1012+
- **IP_ADDRESS_SYS**:IP地址
10131013
- **CREDIT_CARD**:信用卡号
10141014
- **SSN**:社会保障号
10151015

@@ -1030,22 +1030,22 @@ def chat_with_openai(prompt, model="Xiangxin-Guardrails-Text"):
10301030
```json
10311031
{
10321032
"id": "guardrails-6048ed54e2bb482d894d6cb8c3842153",
1033-
"overall_risk_level": "高风险",
1034-
"suggest_action": "代答",
1035-
"suggest_answer": "我的电话号码是<PHONE_NUMBER>,银行卡号是<BANK_CARD_NUMBER>,身份证号是<ID_CARD_NUMBER>",
1033+
"overall_risk_level": "high_risk",
1034+
"suggest_action": "replace",
1035+
"suggest_answer": "My phone number is <PHONE_NUMBER_SYS>, bank card number is <BANK_CARD_NUMBER_SYS>, ID card number is <ID_CARD_NUMBER_SYS>",
10361036
"score": 0.999998927117538,
10371037
"result": {
10381038
"compliance": {
1039-
"risk_level": "无风险",
1039+
"risk_level": "no_risk",
10401040
"categories": []
10411041
},
10421042
"security": {
1043-
"risk_level": "无风险",
1043+
"risk_level": "no_risk",
10441044
"categories": []
10451045
},
10461046
"data": {
1047-
"risk_level": "高风险",
1048-
"categories": ["BANK_CARD_NUMBER", "ID_CARD_NUMBER", "PHONE_NUMBER"]
1047+
"risk_level": "no_risk",
1048+
"categories": ["BANK_CARD_NUMBER_SYS", "ID_CARD_NUMBER_SYS", "PHONE_NUMBER_SYS"]
10491049
}
10501050
}
10511051
}
@@ -1108,7 +1108,7 @@ response = requests.post(
11081108
headers={"Authorization": "Bearer your-api-key"},
11091109
json={
11101110
"name": "高风险行为封禁",
1111-
"risk_level": "高风险",
1111+
"risk_level": "no_risk",
11121112
"trigger_count": 3,
11131113
"time_window_minutes": 60,
11141114
"ban_duration_minutes": 1440,
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# 数据安全功能改进总结
2+
3+
## 修改概述
4+
5+
本次修改主要解决了以下问题:
6+
7+
1. **系统默认实体类型命名规范化**:将系统自带的6个实体类型名称添加`_SYS`后缀
8+
2. **租户级别的实体类型禁用功能**:允许租户禁用系统实体类型
9+
3. **租户实体类型重名检查**:确保同一租户内实体类型不重名
10+
4. **全局实体类型管理**:确保管理员对全局实体类型的修改影响所有租户
11+
12+
## 具体修改内容
13+
14+
### 1. 系统默认实体类型名称修改
15+
16+
**文件**: `backend/services/data_security_service.py`
17+
18+
将以下实体类型名称添加`_SYS`后缀:
19+
- `ID_CARD_NUMBER``ID_CARD_NUMBER_SYS`
20+
- `PHONE_NUMBER``PHONE_NUMBER_SYS`
21+
- `EMAIL``EMAIL_SYS`
22+
- `BANK_CARD_NUMBER``BANK_CARD_NUMBER_SYS`
23+
- `PASSPORT_NUMBER``PASSPORT_NUMBER_SYS`
24+
- `IP_ADDRESS``IP_ADDRESS_SYS`
25+
26+
### 2. 新增数据库表
27+
28+
**文件**: `backend/database/migrations/add_tenant_entity_type_disables.sql`
29+
30+
创建了`tenant_entity_type_disables`表,用于存储租户禁用的实体类型:
31+
- `id`: 主键
32+
- `tenant_id`: 租户ID
33+
- `entity_type`: 被禁用的实体类型代码
34+
- `disabled_at`: 禁用时间
35+
- 唯一约束:`(tenant_id, entity_type)`
36+
37+
### 3. 新增数据库模型
38+
39+
**文件**: `backend/database/models.py`
40+
41+
添加了`TenantEntityTypeDisable`模型类,对应`tenant_entity_type_disables`表。
42+
43+
### 4. 数据安全服务增强
44+
45+
**文件**: `backend/services/data_security_service.py`
46+
47+
#### 新增方法:
48+
- `disable_entity_type_for_tenant()`: 禁用租户的实体类型
49+
- `enable_entity_type_for_tenant()`: 启用租户的实体类型
50+
- `get_tenant_disabled_entity_types()`: 获取租户禁用的实体类型列表
51+
52+
#### 修改方法:
53+
- `_get_user_entity_types()`: 在获取实体类型时排除被租户禁用的实体类型
54+
55+
### 5. API路由增强
56+
57+
**文件**: `backend/routers/data_security.py`
58+
59+
#### 新增API端点:
60+
- `POST /api/v1/config/data-security/entity-types/{entity_type}/disable`: 禁用实体类型
61+
- `POST /api/v1/config/data-security/entity-types/{entity_type}/enable`: 启用实体类型
62+
- `GET /api/v1/config/data-security/disabled-entity-types`: 获取禁用的实体类型列表
63+
64+
#### 修改现有API:
65+
- 创建实体类型时检查租户内重名(`create_entity_type`
66+
67+
## 功能特性
68+
69+
### 1. 租户级别的实体类型管理
70+
71+
- **禁用系统实体类型**:租户可以禁用系统提供的实体类型,使其对自己不生效
72+
- **启用系统实体类型**:租户可以重新启用之前禁用的系统实体类型
73+
- **查看禁用状态**:租户可以查看当前禁用的实体类型列表
74+
75+
### 2. 实体类型重名检查
76+
77+
- **租户内唯一性**:同一租户内不能创建相同名称的实体类型
78+
- **跨租户允许**:不同租户之间可以创建相同名称的实体类型
79+
80+
### 3. 全局实体类型管理
81+
82+
- **管理员权限**:只有超级管理员可以创建、修改、删除全局实体类型
83+
- **全局影响**:管理员对全局实体类型的修改会立即影响所有租户
84+
- **租户禁用**:租户可以禁用全局实体类型,但不影响其他租户
85+
86+
## 使用示例
87+
88+
### 1. 租户禁用系统实体类型
89+
90+
```bash
91+
# 禁用身份证号检测
92+
POST /api/v1/config/data-security/entity-types/ID_CARD_NUMBER_SYS/disable
93+
94+
# 禁用手机号检测
95+
POST /api/v1/config/data-security/entity-types/PHONE_NUMBER_SYS/disable
96+
```
97+
98+
### 2. 租户启用系统实体类型
99+
100+
```bash
101+
# 启用身份证号检测
102+
POST /api/v1/config/data-security/entity-types/ID_CARD_NUMBER_SYS/enable
103+
```
104+
105+
### 3. 查看租户禁用的实体类型
106+
107+
```bash
108+
GET /api/v1/config/data-security/disabled-entity-types
109+
110+
# 响应示例
111+
{
112+
"disabled_entity_types": ["ID_CARD_NUMBER_SYS", "PHONE_NUMBER_SYS"]
113+
}
114+
```
115+
116+
## 数据库迁移
117+
118+
执行以下命令来应用数据库迁移:
119+
120+
```bash
121+
cd backend
122+
python -c "
123+
from database.connection import get_db_session
124+
from sqlalchemy import text
125+
126+
with open('database/migrations/add_tenant_entity_type_disables.sql', 'r') as f:
127+
sql = f.read()
128+
129+
db = get_db_session()
130+
try:
131+
db.execute(text(sql))
132+
db.commit()
133+
print('Migration executed successfully')
134+
except Exception as e:
135+
print(f'Migration failed: {e}')
136+
db.rollback()
137+
finally:
138+
db.close()
139+
"
140+
```
141+
142+
## 注意事项
143+
144+
1. **向后兼容性**:现有的实体类型配置不会受到影响
145+
2. **权限控制**:只有超级管理员可以管理全局实体类型
146+
3. **数据一致性**:租户禁用实体类型不会影响其他租户
147+
4. **性能考虑**:禁用检查在每次检测时都会执行,但查询效率较高
148+
149+
## 测试建议
150+
151+
1. **功能测试**
152+
- 测试租户禁用/启用系统实体类型
153+
- 测试租户内实体类型重名检查
154+
- 测试管理员全局实体类型管理
155+
156+
2. **权限测试**
157+
- 测试普通租户无法管理全局实体类型
158+
- 测试超级管理员可以管理全局实体类型
159+
160+
3. **数据一致性测试**
161+
- 测试租户禁用不影响其他租户
162+
- 测试管理员修改全局实体类型影响所有租户
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- 添加language字段到tenants表
2+
-- 创建时间: 2025-01-27
3+
4+
-- 添加language字段
5+
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS language VARCHAR(10) DEFAULT 'en' NOT NULL;
6+
7+
-- 添加注释
8+
COMMENT ON COLUMN tenants.language IS 'User language preference';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- 添加租户级别的实体类型禁用功能
2+
-- 创建时间: 2025-01-27
3+
4+
-- 租户实体类型禁用表
5+
CREATE TABLE IF NOT EXISTS tenant_entity_type_disables (
6+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
7+
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
8+
entity_type VARCHAR(100) NOT NULL, -- 实体类型代码,如 ID_CARD_NUMBER_SYS
9+
disabled_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
10+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
11+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
12+
13+
-- 确保每个租户对每个实体类型只能有一条禁用记录
14+
UNIQUE(tenant_id, entity_type)
15+
);
16+
17+
-- 创建索引
18+
CREATE INDEX IF NOT EXISTS idx_tenant_entity_type_disables_tenant_id ON tenant_entity_type_disables(tenant_id);
19+
CREATE INDEX IF NOT EXISTS idx_tenant_entity_type_disables_entity_type ON tenant_entity_type_disables(entity_type);
20+
21+
-- 添加注释
22+
COMMENT ON TABLE tenant_entity_type_disables IS '租户实体类型禁用表';
23+
COMMENT ON COLUMN tenant_entity_type_disables.tenant_id IS '租户ID';
24+
COMMENT ON COLUMN tenant_entity_type_disables.entity_type IS '被禁用的实体类型代码';
25+
COMMENT ON COLUMN tenant_entity_type_disables.disabled_at IS '禁用时间';

backend/database/models.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Tenant(Base):
1616
is_verified = Column(Boolean, default=False) # Whether the email has been verified
1717
is_super_admin = Column(Boolean, default=False) # Whether to be a super admin
1818
api_key = Column(String(64), unique=True, nullable=False, index=True)
19+
language = Column(String(10), default='en', nullable=False) # User language preference
1920
created_at = Column(DateTime(timezone=True), server_default=func.now())
2021
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
2122

@@ -355,3 +356,22 @@ class DataSecurityEntityType(Base):
355356

356357
# Association relationships
357358
tenant = relationship("Tenant")
359+
360+
class TenantEntityTypeDisable(Base):
361+
"""Tenant entity type disable table"""
362+
__tablename__ = "tenant_entity_type_disables"
363+
364+
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
365+
tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=False, index=True)
366+
entity_type = Column(String(100), nullable=False, index=True) # Entity type code, such as ID_CARD_NUMBER_SYS
367+
disabled_at = Column(DateTime(timezone=True), server_default=func.now())
368+
created_at = Column(DateTime(timezone=True), server_default=func.now())
369+
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
370+
371+
# Association relationships
372+
tenant = relationship("Tenant")
373+
374+
# Unique constraint
375+
__table_args__ = (
376+
UniqueConstraint('tenant_id', 'entity_type', name='_tenant_entity_type_disable_uc'),
377+
)

0 commit comments

Comments
 (0)