Skip to content

Commit e5dc1e2

Browse files
committed
feat(examples): add shared secret patterns and host-side redaction
1 parent 14a2d43 commit e5dc1e2

4 files changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Code review pipeline package."""
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Host-side redaction. Imports the skill's secret_patterns module so the
7+
sandbox checker and host redaction always share one pattern list."""
8+
import importlib.util
9+
from pathlib import Path
10+
11+
_PATTERNS_PATH = (Path(__file__).resolve().parents[1]
12+
/ "skills" / "code-review" / "scripts" / "secret_patterns.py")
13+
14+
_spec = importlib.util.spec_from_file_location("cr_secret_patterns", _PATTERNS_PATH)
15+
_mod = importlib.util.module_from_spec(_spec)
16+
_spec.loader.exec_module(_mod)
17+
18+
19+
def redact_text(text):
20+
"""Redact all secrets in *text* using the shared skill patterns."""
21+
if not text:
22+
return text
23+
return _mod.redact(text)
24+
25+
26+
def contains_secret(text):
27+
"""Return True when *text* contains at least one secret match."""
28+
return bool(_mod.find_secrets(text or ""))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Secret detection + redaction patterns. Single source of truth for
7+
check_secrets.py (sandbox side) and review/redaction.py (host side)."""
8+
import hashlib
9+
import re
10+
11+
SECRET_PATTERNS = [
12+
("anthropic_key", re.compile(r"sk-ant-[A-Za-z0-9\-]{10,}")),
13+
("openai_key", re.compile(r"sk-[A-Za-z0-9]{20,}")),
14+
("aws_access_key", re.compile(r"AKIA[0-9A-Z]{16}")),
15+
("github_token", re.compile(r"gh[pousr]_[A-Za-z0-9]{20,}")),
16+
("slack_token", re.compile(r"xox[baprs]-[A-Za-z0-9\-]{10,}")),
17+
("jwt", re.compile(r"eyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}(?:\.[A-Za-z0-9_\-]{4,})?")),
18+
("private_key", re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----")),
19+
("bearer_token", re.compile(r"[Bb]earer\s+[A-Za-z0-9._\-]{12,}")),
20+
("url_basic_auth", re.compile(r"[a-z][a-z0-9+.\-]*://[^/\s:@]+:[^@\s]+@")),
21+
("sensitive_assign", re.compile(
22+
r"(?i)(password|passwd|secret|token|api_key|apikey|secret_token|db_password)"
23+
r"\s*[:=]\s*[\"'][^\"']{6,}[\"']")),
24+
]
25+
26+
27+
def find_secrets(text):
28+
"""Return the list of raw secret substrings found in *text*."""
29+
found = []
30+
for _, pattern in SECRET_PATTERNS:
31+
for m in pattern.finditer(text):
32+
found.append(m.group(0))
33+
return found
34+
35+
36+
def _fingerprint(value):
37+
return hashlib.sha256(value.encode("utf-8")).hexdigest()[:8]
38+
39+
40+
def redact(text):
41+
"""Replace every secret match with ***REDACTED-<sha8>*** (stable per value)."""
42+
for _, pattern in SECRET_PATTERNS:
43+
text = pattern.sub(lambda m: "***REDACTED-%s***" % _fingerprint(m.group(0)), text)
44+
return text
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Tests for secret detection and redaction (>=95% detection target)."""
7+
SAMPLE_SECRETS = [
8+
'API_KEY = "sk-abcdefghijklmnopqrstuvwxyz123456"',
9+
'key = "sk-ant-api03-abcdefghijklmnopqrst"',
10+
"aws AKIAIOSFODNN7EXAMPLE",
11+
'token = "ghp_abcdefghijklmnopqrstuvwxyz0123456789"',
12+
"Authorization: Bearer abc123def456ghi789jkl",
13+
"jwt eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.abc123def456",
14+
"-----BEGIN RSA PRIVATE KEY-----",
15+
'password = "hunter2secret"',
16+
'PASSWD: "topsecretvalue"',
17+
'secret = "do-not-leak-me"',
18+
'api_key="deadbeefcafe1234"',
19+
"https://user:p4ssw0rd@db.example.com/prod",
20+
'TOKEN = "9f8e7d6c5b4a39281706f5e4d3c2b1a0"',
21+
'apikey: "0123456789abcdefffff"',
22+
"Bearer xoxb-1234567890-abcdefghij",
23+
'DB_PASSWORD = "prod-db-pass-2026"',
24+
'passwd = "another$ecret!"',
25+
"AKIA0123456789ABCDEF",
26+
'secret_token = "veryhiddenvalue1"',
27+
'ghs_abcdefghijklmnopqrstuvwxyz0123456789',
28+
]
29+
30+
31+
def test_detection_rate_at_least_95_percent():
32+
from review.redaction import contains_secret
33+
detected = sum(1 for s in SAMPLE_SECRETS if contains_secret(s))
34+
assert detected / len(SAMPLE_SECRETS) >= 0.95
35+
36+
37+
def test_redaction_removes_secret_values():
38+
from review.redaction import redact_text
39+
for sample in SAMPLE_SECRETS:
40+
out = redact_text(sample)
41+
assert "***REDACTED-" in out or sample == out, sample
42+
assert "hunter2secret" not in redact_text('password = "hunter2secret"')
43+
assert "AKIAIOSFODNN7EXAMPLE" not in redact_text("aws AKIAIOSFODNN7EXAMPLE")
44+
45+
46+
def test_redaction_is_stable_fingerprint():
47+
from review.redaction import redact_text
48+
a = redact_text("Bearer abc123def456ghi789jkl")
49+
b = redact_text("Bearer abc123def456ghi789jkl")
50+
assert a == b
51+
52+
53+
def test_plain_text_untouched():
54+
from review.redaction import redact_text
55+
text = "def add(a, b):\n return a + b"
56+
assert redact_text(text) == text

0 commit comments

Comments
 (0)