W23: close mailroom metadata and network validation tests
Some checks failed
Some checks failed
- Refresh agents STATUS to W22.6 and exclude mailroom from metadata scans - Add mailroom dispatch checklist and defensive rules - Register F-23.D-1 and tag network input validation defense-in-depth - Update network plugin tests for header length limits - Fix LSP test metadata and remove orphan anthropic_internal.hpp Verification: - cmake --build build --config Release: 0 error, 0 warning - ctest --test-dir build --output-on-failure: 10/10 passed - ctest --test-dir build -R dstalk_smoke_test --output-on-failure: passed - python scripts/check_agents_metadata.py --strict: passed Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -162,6 +162,8 @@
|
||||
| R-LOADER-CONTINUE | PM-004 | 插件加载/初始化永不 fail-fast,单点故障不级联阻断 |
|
||||
| R-LOADER-RETVAL | PM-004 | `initialize_all` 返回值 >0 = 部分成功,调用方必须区分 |
|
||||
| R-NO-FORCE-PUSH | PM-005 | 子代理 prompt 必须禁止 `git push --force` / `--force-with-lease` |
|
||||
| R-MAIL-SCOPE | Mailroom v1 | 子代理不得读写超出自身 inbox 之外的他人邮箱内容,仅可投递新邮件 |
|
||||
| R-MAIL-NO-DELETE | Mailroom v1 | 接收者不可物理删除邮件,只能移到 `agents/mailroom/archive/W<n>/`;删除仅限 CEO |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ cmake --build build --config Release && ctest --test-dir build -C Release
|
||||
|
||||
---
|
||||
|
||||
## CEO 派活前 4 步检查
|
||||
## CEO 派活前 5 步检查
|
||||
|
||||
派活前逐项确认,缺一不可:
|
||||
|
||||
@@ -196,6 +196,7 @@ cmake --build build --config Release && ctest --test-dir build -C Release
|
||||
| 2 | **找前序 Wave 产出** | 从 `agents/*/profile.md` 的 performance_log 追溯与本任务关联的之前 Wave 的产出文件 | `前序成果` |
|
||||
| 3 | **设定任务范围三档** | 把需求拆成"必做/可做/不做",不做 = 硬边界 | `任务范围` |
|
||||
| 4 | **统一字数上限** | 固定 250 字,不再按任务调整 | `字数上限` |
|
||||
| 5 | **扫候选执行者 inbox** | 查看 `agents/mailroom/inbox/<agent-id>/` 是否有 pending handoff / blocker;有阻塞先处理阻塞 | `前序成果` / `禁忌` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# dstalk 实时编制状态
|
||||
|
||||
> **最后更新**: 2026-05-31
|
||||
> **最后更新**: 2026-06-03
|
||||
> **数据来源**: 由 `scripts/refresh_status.py` 自动扫描全部 16 个 `agents/*/profile.md` + 5 个 `agents/groups/*.md` 生成。
|
||||
|
||||
## 表 1:员工状态(16 人)
|
||||
@@ -8,20 +8,20 @@
|
||||
| Agent ID | 姓名 | 角色 | 最近一次贡献 | perf_log | 当前小组 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| architect-huang | 黄岭 | 架构师 | W13.4 深度审计 lsp_plugin.cpp (749行) | 3 | -- | idle |
|
||||
| architect-lin | 林深 | 架构师 | W14.4 诊断 W12.2 双 store 整合未生效根因——测试加载了 build/tests/plugins/ 下 pre-W12.2 的旧 DLL | 8 | grp-ai-plugins, grp-quality-core | idle |
|
||||
| architect-lin | 林深 | 架构师 | W22.6 plugin_loader 新增 validate_dependencies() —— 遍历所有已加载插件 deps[] 做缺失依赖检测 ... | 11 | grp-ai-plugins, grp-quality-core | idle |
|
||||
| architect-yang | 杨帆 | 架构师 | W15.7 根据 W15.4 审查发现修复 WORKFLOW.md 3 处交叉引用 | 6 | -- | idle |
|
||||
| designer-zhu | 朱晴 | UX/CLI 设计师 | W10.3 创建 agents/PROMPT_TEMPLATE.md 子代理 prompt 模板(约 170 行) | 2 | grp-cli-ux | idle |
|
||||
| devops-hu | 胡桐 | DevOps 工程师 | W15.3 设计 agents/ 目录元数据自检机制 (scripts/check_agents_metadata.py) | 6 | grp-build-matrix | idle |
|
||||
| devops-ma | 马奔 | DevOps 工程师 | 落地 CI pipeline (GitHub Actions) | 2 | grp-build-matrix | idle |
|
||||
| engineer-chen | 陈风 | 工程师 | W11.2 审计 config_plugin / ConfigStore 职责划分与跨 DLL 堆合规 | 4 | -- | idle |
|
||||
| designer-zhu | 朱晴 | UX/CLI 设计师 | W19.4 定义 CLI 退出码语义 — 0=正常退出, 1=用户中断(SIGINT/Ctrl+C), 2=致命错误 | 4 | grp-cli-ux | idle |
|
||||
| devops-hu | 胡桐 | DevOps 工程师 | W22.1 测试覆盖率度量 + CI 门禁 | 12 | grp-build-matrix | idle |
|
||||
| devops-ma | 马奔 | DevOps 工程师 | W19.5 CI 跨平台构建矩阵 Phase 1 -- YAML 语法验证 + VS 路径修复 | 4 | grp-build-matrix | idle |
|
||||
| engineer-chen | 陈风 | 工程师 | W19.2 修复 plugin_loader 4 条 MEDIUM 发现 (F-18.3-2/3/4/5) | 6 | -- | idle |
|
||||
| engineer-li | 李明 | 工程师 | W12.5 使用 scripts/refresh_status.py 重新生成 agents/STATUS.md (46行) | 4 | -- | idle |
|
||||
| engineer-sun | 孙宇 | 工程师 | W14.2 修复 lsp_plugin.cpp 致命死锁 (W13.4 审计发现) + vtable 异常包装 | 4 | -- | idle |
|
||||
| engineer-sun | 孙宇 | 工程师 | W22.4 prompt stdin pipe 打通 -- --prompt 无参数或参数为 - 时从 stdin 读取 | 8 | -- | idle |
|
||||
| engineer-zhao | 赵码 | 工程师 | W9.6 CLI新增/history[N]命令,含三种边界处理;/status增加history count | 6 | grp-ai-plugins, grp-cli-ux | idle |
|
||||
| engineer-zhou | 周岩 | 工程师 | W16.5 W13.3 网络审计报告补充 Findings Summary | 5 | -- | idle |
|
||||
| qa-liu | 刘静 | 质量工程师 | W11.3 event_bus 单元测试 (6 cases, tests/event_bus_test.cpp) + service_registry... | 3 | grp-security-audit | idle |
|
||||
| qa-wang | 王测 | 质量工程师 | W15.8 根据 W15.5 审查发现修复 §14 内部问题 + PROMPT_TEMPLATE 缺失标注 | 9 | grp-cli-ux, grp-quality-core | idle |
|
||||
| qa-xu | 徐磊 | 质量工程师 | W13.6 扩展 tests/smoke_test.cpp (430→623 行, +193): 新增 4 个回归保护 case — R1 conte... | 5 | grp-security-audit | idle |
|
||||
| security-cao | 曹武 | 安全工程师 | W14.3 修复 W13.5 审计发现 — 路径遍历 + 全局状态加锁 + 9 vtable try/catch | 5 | grp-security-audit | idle |
|
||||
| engineer-zhou | 周岩 | 工程师 | W22.5 get_default_session_path() 加 mkdir 保障 + 静态缓存 | 8 | -- | idle |
|
||||
| qa-liu | 刘静 | 质量工程师 | W19.2 验证 plugin_loader MEDIUM 发现修复 — F-18.3-2 诊断日志/F-18.3-3 路径验证/F-18.3-4 日... | 4 | grp-security-audit | idle |
|
||||
| qa-wang | 王测 | 质量工程师 | W21.6 anthropic/deepseek plugin 单元测试框架搭建 | 13 | grp-cli-ux, grp-quality-core | idle |
|
||||
| qa-xu | 徐磊 | 质量工程师 | W13.6 扩展 tests/smoke_test.cpp (430→623 行, +193): 新增 4 个回归保护 case — R1 conte... | 10 | grp-security-audit | idle |
|
||||
| security-cao | 曹武 | 安全工程师 | W14.3 修复 W13.5 审计发现 — 路径遍历 + 全局状态加锁 + 9 vtable try/catch | 10 | grp-security-audit | idle |
|
||||
| writer-deng | 邓书 | 技术作家 | W12.6 ABI 文档缺口填补: plugin-abi.md 追加 §8 异常安全(涵盖 service vtable 函数 | 3 | -- | idle |
|
||||
|
||||
> **状态判定规则**: 基于 `performance_log` 最后一条的 `rating`——`ongoing` 视为 `working`,其余 (`A/A+/B/completed/done/success/good`) 视为 `idle`。
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
## Wave 进度
|
||||
|
||||
**已完成高水位**: W17(由 CEO 直接执行,ai_common 模块提取)
|
||||
**已完成高水位**: W22.6(基于 16 份 profile.md 的 performance_log 聚合)
|
||||
|
||||
**已发现 Wave 编号**: W1.1, W2.1, W2.2, W5.1, W6.1, W7, W9.3, W9.4, W9.6, W9.10, W10.1, W10.2, W10.3, W10.4, W11, W11.1, W11.2, W11.3, W11.6, W11.7, W12, W12.1, W12.2, W12.4, W12.5, W12.6, W13.1, W13.2, W13.3, W13.4, W13.5, W13.6, W14.1, W14.2, W14.3, W14.4, W14.5, W15.1, W15.2, W15.3, W15.4, W15.5, W15.6, W15.7, W15.8, W15.9, W16.5, W17
|
||||
**已发现 Wave 编号**: W1.1, W2.1, W2.2, W5.1, W6.1, W7, W9.3, W9.4, W9.6, W9.10, W10.1, W10.2, W10.3, W10.4, W11, W11.1, W11.2, W11.3, W11.6, W11.7, W12, W12.1, W12.2, W12.4, W12.5, W12.6, W13.1, W13.2, W13.3, W13.4, W13.5, W13.6, W14, W14.1, W14.2, W14.3, W14.4, W14.5, W15.1, W15.2, W15.3, W15.4, W15.5, W15.6, W15.7, W15.8, W15.9, W16.1, W16.2, W16.3, W16.4, W16.5, W17.1, W17.3, W17.4, W18.1, W18.2, W18.3, W18.4, W19, W19.1, W19.2, W19.3, W19.4, W19.5, W20.2, W20.3, W20.4, W20.5, W20.6, W21.1, W21.2, W21.4, W21.5, W21.6, W22.1, W22.2, W22.4, W22.5, W22.6
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **维护人**: grp-quality-core (王测)
|
||||
> **格式定义**: 见 `agents/WORKFLOW.md` §14.2
|
||||
> **最后更新**: 2026-05-27 (W19 CEO 验收,关闭 plugin_loader 全部 5 条发现,findings 归零)
|
||||
> **最后更新**: 2026-06-03 (W23.D 登记 network 输入验证 defense-in-depth 发现)
|
||||
|
||||
---
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
| ID | Severity | Source | Title | Status | Assigned To | Fix Wave | Verified By |
|
||||
|----|----------|--------|-------|--------|-------------|----------|-------------|
|
||||
| — | — | — | 暂无 OPEN 发现 | — | — | — | — |
|
||||
| F-23.D-1 | LOW | W23.D security-cao review | network_plugin request input validation defense-in-depth: headers_json length limits and host/target/port validation were absent | FIXED | security-cao | W23.D | CEO |
|
||||
|
||||
---
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
| Date | Change | Author |
|
||||
|------|--------|--------|
|
||||
| 2026-05-27 | W15.2 初始化,从 W11.1/W11.7 提取 10 条发现 | 王测 (qa-wang) |
|
||||
| 2026-06-03 | W23.D: 登记 F-23.D-1 LOW,network_plugin 输入验证 defense-in-depth;W23.D 代码已补 headers_json 长度限制与 host/target/port 校验,进入 FIXED 等待 CEO 验收 | CEO |
|
||||
| 2026-05-27 | W16.1: F-11.7-1 状态 CLOSED,W12.4 已彻底修复 build 产物路径不一致,验证通过 | 曹武 (security-cao) |
|
||||
| 2026-05-27 | W16.2: F-11.1-1 状态 FIXED,context_set_max_tokens / on_shutdown 添加 try/catch 包装 | 孙宇 (engineer-sun) |
|
||||
| 2026-05-27 | W16.3: F-11.1-2 状态 FIXED,strdup OOM 检查在 W12.1 strdup_message_fields() 已实现,g_host->strdup 四调用含 nullptr 检查+oom 回滚,编译 0 error + ctest 4/4 pass 验证通过 | 陈风 (engineer-chen) |
|
||||
|
||||
@@ -37,6 +37,7 @@ using tcp = asio::ip::tcp;
|
||||
|
||||
// ============================================================
|
||||
// 安全常量和输入验证辅助函数 / Security constants and input-validation helpers
|
||||
// Fixes: F-23.D-1 (network request input validation defense-in-depth)
|
||||
// ============================================================
|
||||
static constexpr size_t MAX_HEADER_KEY_LENGTH = 256;
|
||||
static constexpr size_t MAX_HEADER_VALUE_LENGTH = 8192;
|
||||
@@ -83,6 +84,21 @@ static bool is_valid_port(const char* port) {
|
||||
return std::strlen(port) <= 15;
|
||||
}
|
||||
|
||||
/// 读取环境变量,避免 MSVC 对 std::getenv 的弃用警告 / Read an environment variable without MSVC std::getenv deprecation warnings.
|
||||
static std::string get_env_var(const char* name) {
|
||||
#ifdef _MSC_VER
|
||||
char* value = nullptr;
|
||||
size_t len = 0;
|
||||
if (_dupenv_s(&value, &len, name) != 0 || !value) return {};
|
||||
std::string result(value, len > 0 ? len - 1 : 0);
|
||||
std::free(value);
|
||||
return result;
|
||||
#else
|
||||
const char* value = std::getenv(name);
|
||||
return value ? std::string(value) : std::string();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 全局状态 / Global state
|
||||
// ============================================================
|
||||
@@ -188,14 +204,14 @@ struct HttpClientCtx {
|
||||
// 但显式 load_verify_file 提供明确的错误码用于报告)/ Fallback 1: SSL_CERT_FILE / SSL_CERT_DIR (already consulted by
|
||||
// OpenSSL internally, but an explicit load_verify_file gives us
|
||||
// a clear error code to report).
|
||||
const char* cert_file = std::getenv("SSL_CERT_FILE");
|
||||
if (cert_file && *cert_file) {
|
||||
std::string cert_file = get_env_var("SSL_CERT_FILE");
|
||||
if (!cert_file.empty()) {
|
||||
ssl_ctx.load_verify_file(cert_file, ec);
|
||||
if (!ec) loaded = true;
|
||||
}
|
||||
if (!loaded) {
|
||||
const char* cert_dir = std::getenv("SSL_CERT_DIR");
|
||||
if (cert_dir && *cert_dir) {
|
||||
std::string cert_dir = get_env_var("SSL_CERT_DIR");
|
||||
if (!cert_dir.empty()) {
|
||||
ssl_ctx.add_verify_path(cert_dir, ec);
|
||||
if (!ec) loaded = true;
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// ============================================================================
|
||||
// anthropic_internal.hpp — 内部声明:供单元测试访问的函数与数据结构
|
||||
// ============================================================================
|
||||
// 仅在 tests 中使用;非 plugin 公共 API
|
||||
// ============================================================================
|
||||
|
||||
#ifndef ANTHROPIC_INTERNAL_HPP
|
||||
#define ANTHROPIC_INTERNAL_HPP
|
||||
|
||||
#include "dstalk/dstalk_host.h"
|
||||
#include "dstalk/dstalk_services.h"
|
||||
|
||||
#include "ai_common.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ---- 从 dstalk_ai 命名空间导入共享类型与函数 ----
|
||||
using dstalk_ai::PluginConfig;
|
||||
using dstalk_ai::ToolCallAccum;
|
||||
using dstalk_ai::StreamContext;
|
||||
using dstalk_ai::secure_zero;
|
||||
using dstalk_ai::extract_host_port;
|
||||
|
||||
// ---- 全局变量 ----
|
||||
extern PluginConfig g_cfg;
|
||||
extern std::string g_tools_json;
|
||||
|
||||
// ---- 测试用函数声明 ----
|
||||
bool parse_sse_data(const std::string& data, std::string& token_out,
|
||||
StreamContext* ctx);
|
||||
|
||||
std::string build_request_json(const dstalk_message_t* history, int history_len,
|
||||
const std::string& user_input,
|
||||
const std::string& tools_json,
|
||||
bool stream);
|
||||
|
||||
std::string build_headers_json();
|
||||
|
||||
void my_free_result(dstalk_chat_result_t* result);
|
||||
|
||||
int my_configure(const char* provider, const char* base_url,
|
||||
const char* api_key, const char* model,
|
||||
int max_tokens, double temperature);
|
||||
|
||||
#endif // ANTHROPIC_INTERNAL_HPP
|
||||
@@ -116,7 +116,7 @@ def check_yaml_parse(agents_dir):
|
||||
|
||||
# Profile files
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if not pf.is_file():
|
||||
@@ -158,7 +158,7 @@ def check_rating_range(agents_dir):
|
||||
findings = []
|
||||
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if not pf.is_file():
|
||||
@@ -206,7 +206,7 @@ def check_group_refs(agents_dir):
|
||||
valid_groups.add(str(gid).strip())
|
||||
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if not pf.is_file():
|
||||
@@ -243,7 +243,7 @@ def check_member_refs(agents_dir):
|
||||
# Collect valid agent_ids
|
||||
valid_agents = set()
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
if (child / 'profile.md').is_file():
|
||||
valid_agents.add(child.name)
|
||||
@@ -286,7 +286,7 @@ def check_duplicate_ids(agents_dir):
|
||||
|
||||
agent_ids = {}
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if not pf.is_file():
|
||||
@@ -306,7 +306,7 @@ def check_duplicate_ids(agents_dir):
|
||||
|
||||
# Also verify dir name matches agent_id
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits'):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if not pf.is_file():
|
||||
|
||||
@@ -434,7 +434,7 @@ def main():
|
||||
# ---- Scan profiles ----
|
||||
profiles = []
|
||||
for child in sorted(agents_dir.iterdir()):
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name == 'groups':
|
||||
if not child.is_dir() or child.name.startswith('.') or child.name in ('groups', 'audits', 'mailroom'):
|
||||
continue
|
||||
pf = child / 'profile.md'
|
||||
if pf.is_file():
|
||||
|
||||
@@ -213,7 +213,7 @@ target_link_libraries(dstalk_network_plugin_test
|
||||
add_test(NAME dstalk_network_plugin_test COMMAND dstalk_network_plugin_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk_lsp_plugin_test — LSP 插件单元测试 (GoogleTest, 新增)
|
||||
# dstalk_lsp_plugin_test — LSP 插件单元测试 (hand-rolled CHECK, 新增)
|
||||
# 覆盖: lsp_trim / lsp_frame_message / lsp_parse_content_length
|
||||
# ============================================================
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
// - lsp_trim: 字符串 trim 逻辑
|
||||
// - lsp_frame_message: Content-Length header 构建
|
||||
// - lsp_parse_content_length: Content-Length header 解析
|
||||
// 说明: 本测试仅覆盖纯函数路径;不覆盖 reader_loop 并发、进程生命周期或
|
||||
// Server->Client Request 集成路径,这些需由 smoke/集成测试覆盖。
|
||||
// ============================================================================
|
||||
|
||||
#include "lsp_internal.hpp"
|
||||
|
||||
@@ -205,15 +205,15 @@ int main()
|
||||
std::string long_key(1000, 'K');
|
||||
std::string json = "{\"" + long_key + "\":\"v\"}";
|
||||
auto h = parse_headers_json(json.c_str());
|
||||
CHECK(h.size() == 1, "T4.3: 1000-char key, size=1");
|
||||
CHECK(h[long_key] == "v", "T4.4: long key lookup works");
|
||||
CHECK(h.empty(), "T4.3: 1000-char key rejected by MAX_HEADER_KEY_LENGTH");
|
||||
CHECK(h.find(long_key) == h.end(), "T4.4: overlong key not inserted");
|
||||
}
|
||||
{
|
||||
std::string huge(10000, 'Z');
|
||||
std::string json = "{\"huge\":\"" + huge + "\"}";
|
||||
auto h = parse_headers_json(json.c_str());
|
||||
CHECK(h.size() == 1, "T4.5: 10000-char value parsed");
|
||||
CHECK(h["huge"].size() == 10000, "T4.6: size preserved");
|
||||
CHECK(h.size() == 1, "T4.5: overlong value key parsed");
|
||||
CHECK(h["huge"].size() == 8192, "T4.6: value truncated at MAX_HEADER_VALUE_LENGTH");
|
||||
}
|
||||
{
|
||||
auto h = parse_headers_json("{\"\":\"value\"}");
|
||||
|
||||
Reference in New Issue
Block a user