Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design:
pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.port; python -m emrg
```

Python: `uv run pytest tests/ -v` (488) — import check: `uv run python -c "from emrg.client.app import run_client"`
Python: `uv run pytest tests/ -v` (489) — import check: `uv run python -c "from emrg.client.app import run_client"`
GUI: `cd emrg/gui && npm test` (86: 22 daemon_client + 22 app-commands + 17 renderer smoke + 15 i18n + 7 integration + 3 commands) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js`
CI: `uv run pytest` + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ EMRG doesn't just keep up — it catches up on its own.
git clone https://github.com/argszero/emrg.git
cd emrg
uv sync # install deps
uv run pytest tests/ -v # run tests (currently 488 items)
uv run pytest tests/ -v # run tests (currently 489 items)
uv run python -m emrg # launch TUI
# CI includes actionlint workflow gate (#444): workflow parse errors fail PR CI

Expand Down
5 changes: 4 additions & 1 deletion emrg/server/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@

# 字符串值内联凭据模式(保守匹配,宁多勿漏)
_INLINE_SECRET_PATTERNS = (
_re.compile(r"(sk-[A-Za-z0-9_\-]{8,})"), # OpenAI/DeepSeek/Anthropic 密钥
# sk- 密钥:sk- 后必须 ≥16 位纯字母数字(OpenAI/DeepSeek),或 sk-proj-(OpenAI 项目)
# 或 sk-ant-apiNN-(Anthropic)—— 排除 "task-evolution" 等路径片段误伤
_re.compile(r"(sk-(?:proj-)?[A-Za-z0-9]{16,})"),
_re.compile(r"(sk-ant-api[0-9]+-[A-Za-z0-9]{16,})"), # Anthropic
_re.compile(r"(gh[pousr]_[A-Za-z0-9]{20,})"), # GitHub PAT / OAuth / gist token
_re.compile(r"(xox[baprs]-[A-Za-z0-9\-]{10,})"), # Slack token
_re.compile(r"(AKIA[0-9A-Z]{16})"), # AWS access key id
Expand Down
37 changes: 33 additions & 4 deletions tests/test_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,9 @@ def test_redact_masks_sensitive_keys():
def test_redact_inline_secrets_in_strings():
"""字符串值内联凭据(sk-/ghp_/Bearer/JWT)被遮蔽。"""
from emrg.server.daemon import _redact
# bash command 内联 API key
assert "sk-1234567890abcdef" not in str(_redact({"command": "export OPENAI_API_KEY=sk-1234567890abcdef; curl x"}))
# bash command 内联 API key(拼接构造,避免 push protection 拦截)
k = "sk-" + "a1b2c3d4" * 4
assert k not in str(_redact({"command": f"export OPENAI_API_KEY={k}; curl x"}))
# GitHub token 嵌在 URL
assert "ghp_" not in str(_redact({"command": "git push https://x-access-token:ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@github.com/r.git"}))
# Bearer + JWT
Expand All @@ -551,9 +552,37 @@ def test_redact_base64_encoded_token_blob():


def test_redact_no_false_positive_on_normal_strings():
"""普通字符串/短 sk- 前缀不被误伤。"""
"""普通字符串/短 sk- 前缀/路径片段不被误伤。"""
from emrg.server.daemon import _redact
assert _redact({"command": "echo hello world", "path": "/tmp/a.txt"}) == {
"command": "echo hello world", "path": "/tmp/a.txt"}
# 短密钥(<8 位)不匹配 sk- 模式 → 保留
# 短密钥(<16 位)不匹配 sk- 模式 → 保留
assert "sk-abc" in _redact({"command": "echo sk-abc"})["command"]
# 路径片段 "task-evolution-*" 含 "sk-evolution"(12 位)→ 不得误伤(#513 修复)
assert "task-evolution-233-emrg-3193bc65.memory" in _redact(
{"command": "ls task-evolution-233-emrg-3193bc65.memory"})["command"]
assert "grep -r sk-evolution ~/scm" in _redact(
{"command": "grep -r sk-evolution ~/scm"})["command"]


def test_redact_real_key_formats_still_masked():
"""真实密钥格式(sk- 16+ 位 / sk-proj- / sk-ant-apiNN-)仍被遮蔽。

密钥在源码中用拼接构造(避免字面量触发 GitHub push protection 扫描,
20260806-2353 教训:32 位纯 hex 的假密钥被识别为 DeepSeek 真密钥而拦截推送)。
"""
from emrg.server.daemon import _redact
# OpenAI sk- + 48 字母数字
openai = "sk-" + "A1b2C3d4" * 6
assert openai not in str(_redact(
{"command": f"export OPENAI_API_KEY={openai}; curl x"}))
# DeepSeek sk- + 32 位
ds = "sk-" + "0a1b2c3d" * 4
assert ds not in str(_redact(
{"command": f"export DEEPSEEK={ds}; curl x"}))
# OpenAI 项目密钥 sk-proj-(裸值,无 key= 前缀)
proj = "sk-proj-" + "AbCdEfGh" * 6
assert "sk-proj-" not in _redact({"command": f"echo {proj}"})["command"]
# Anthropic sk-ant-apiNN-(裸值)
ant = "sk-ant-api03-" + "Q2xjbHVkZ" * 4
assert "sk-ant-" not in _redact({"command": f"echo {ant}"})["command"]
Loading