把查询送进 Glean 前,拦截空查询与疑似密钥/口令,并检查 datasourcesFilter 类型。减少「把密码搜进日志」事故。
先看清成品
- ok 通过;含 api_key 与错误 filter 类型 → INVALID。
- 3 项 pytest 通过。
合规提醒:Glean 是企业产品,需管理员采购与部署;个人通常不能自助注册。搜索与聊天结果继承各数据源权限,禁止用管理员特权接口绕过 ACL 给无授权用户。Token 等同企业访问权,勿提交公开仓库。本文不编造报价。
运行说明:无公司 Glean 租户。A/B 用本地 mock 演示 Platform Search/Chat 形状;C 为发查询前的脱敏守卫。未连接真实
*-be.glean.com。2026-10-23(Asia/Shanghai)pytest 通过。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
query_guard.py |
查询守卫 |
| 样例 JSON | ok/bad |
test_108c.py |
测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.10+ |
关键事实
| 事实 | 来源 |
|---|---|
| Glean 继承源系统权限,但查询文本仍可能进日志 | 安全实践 |
| 本守卫不能替代企业 DLP | 重要 |
| 过滤器字段名以实例配置为准 | 官方 filters |
文件结构
108-glean-C-src/
├── query_guard.py
├── sample_ok.json
├── sample_bad.json
└── test_108c.py
第 1 步:守卫脚本
#!/usr/bin/env python3
"""Pre-flight guard for Glean queries: block secret exfil patterns and empty queries."""
from __future__ import annotations
import argparse, json, re
from pathlib import Path
SECRETISH = re.compile(r"(?i)(api[_-]?key|password|secret|bearer\s+[a-z0-9]|AKIA[0-9A-Z]{16})")
def validate(obj: dict) -> list[str]:
errs = []
q = (obj.get("query") or obj.get("message") or "").strip()
if not q:
errs.append("query/message 必填")
if SECRETISH.search(q):
errs.append("查询中疑似含密钥/口令,禁止发到企业搜索(先脱敏)")
# datasources filter shape if present
ds = obj.get("datasourcesFilter") or obj.get("datasources")
if ds is not None and not isinstance(ds, list):
errs.append("datasourcesFilter 须为字符串数组")
return errs
def main(argv=None) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("payload_json")
args = ap.parse_args(argv)
obj = json.loads(Path(args.payload_json).read_text(encoding="utf-8"))
errs = validate(obj)
if errs:
print("INVALID")
for e in errs: print("-", e)
return 1
print("OK")
return 0
if __name__ == "__main__":
raise SystemExit(main())
第 2 步:测试
from pathlib import Path
import json, subprocess, sys
from query_guard import validate
HERE = Path(__file__).resolve().parent
def test_ok():
assert validate(json.loads((HERE/"sample_ok.json").read_text())) == []
def test_bad():
assert validate(json.loads((HERE/"sample_bad.json").read_text()))
def test_cli():
assert subprocess.run([sys.executable, str(HERE/"query_guard.py"), str(HERE/"sample_ok.json")]).returncode == 0
第 3 步:运行
$ query_guard
OK
INVALID
- 查询中疑似含密钥/口令,禁止发到企业搜索(先脱敏)
- datasourcesFilter 须为字符串数组
$ pytest -q
... [100%]
3 passed in 0.03s
怎么检查结果?
- OK 退出码 0。
- bad 提示密钥与 filter 类型。
调试示例
「帮我找一下昨天的密码文件名叫什么」。 即便没有明文密钥,也可能触及敏感。改成工单号/文档标题等非秘密标识。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 误报 | 调整正则 | 保留人工 |
| 只要 chat | 同样过守卫 | message 字段 |
| 管理员搜索 | 另有特权接口 | 默认不要用 |
模板规则
- 查询不写密钥。
- 最小数据源过滤。
- 异常查询可审计。
项目资源
| 用途 | 地址 |
|---|---|
| Search(官方) | https://developers.glean.com/api/platform-api/platform-search |
| Quickstart(官方) | https://developers.glean.com/api/platform-api/getting-started |
| Glean 官网 | https://glean.com/ |
先挡住秘密,再按回车搜索。