Skip to content

feat(services/safeline-waf-login): add SafeLine WAF account/password service - #561

Merged
Daemonceltics merged 3 commits into
chaitin:mainfrom
Daemonceltics:pr/safeline-waf-login
Nov 5, 2026
Merged

Daemonceltics merged 3 commits into
chaitin:mainfrom
Daemonceltics:pr/safeline-waf-login

Conversation

@Daemonceltics

Copy link
Copy Markdown
Collaborator

Summary

新增雷池 SafeLine WAF 账号密码登录版只读查询 service:

  • 适用于无 OpenAPI / API-Token 的部署场景,Django CSRF + session 会话认证
  • 方法:Login / GetProfile / GetOverview / SearchDetectLog / GetESIndices
  • 内存会话管理(crypto.randomUUID,TTL 30min),增加 socks5 代理支持

Test plan

  • node scripts/validate-service-package.mjs --service-dir chaitin__safeline-waf-login
  • node --test 单测(mock 上游)

@monkeyscan

monkeyscan Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

PR Title: feat(services/safeline-waf-login): add SafeLine WA...

Commit: 53ad81b

整体评估

本次变更新增雷池 SafeLine WAF 账号密码登录版 OctoBus 服务,包含 5 个 gRPC 方法、内存会话管理、HTTP/SOCKS 传输、配置与密钥 schema、mock 上游及单元测试,并接入根包的 bin 与入口清单。整体结构完整,错误映射和测试覆盖设计较为清晰,但存在若干需要修复后再合入的问题。

总结

整体方向合理,但配置能力与打包依赖存在缺口,部署后可能出现服务不可用或请求静默失败。最需要优先处理的是根包缺少新增运行时依赖,以及自定义 headers 未生效和 HTTP 代理不可用的问题;非代理请求的超时也未覆盖响应体读取。

Findings (4)

  • 🟠 [HIGH] services/package.json:376 — 根包清单未声明新增的 socks-proxy-agent 运行时依赖
  • 🟡 [MEDIUM] services/chaitin__safeline-waf-login/src/safeline-waf-login.js:245 — 非代理请求的超时未覆盖响应体读取
  • 🟡 [MEDIUM] services/chaitin__safeline-waf-login/src/safeline-waf-login.js:249 — proxy_url 配置成 HTTP 代理时会抛错导致所有请求失败
  • 🟡 [MEDIUM] services/chaitin__safeline-waf-login/src/safeline-waf-login.js:404 — 配置项 headers 被完全忽略
Prompt To Fix All With AI
# Review 1

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 232-245

Comment:
非代理请求的超时未覆盖响应体读取

fetchWithTimeout 在 fetch 收到响应头并返回后就在 finally 中清除定时器,而 readJsonResponse 此后才 await res.text() 读取响应体。如果上游先返回响应头、再长时间不发送响应体,配置的 timeoutMs 不会生效,RPC 会一直挂起到 undici 默认的体超时(约 300 秒),造成巡检卡死。

# Review 2

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 249

Comment:
proxy_url 配置成 HTTP 代理时会抛错导致所有请求失败

config.schema.json 与 README 都把 proxy_url 描述为支持 HTTP/SOCKS 代理,但实现无条件执行 new SocksProxyAgent(proxyUrl),该 Agent 只接受 socks/socks4/socks5/socks5h 协议。配置 http:// 代理时构造会抛错且未转换为 gRPC 错误,所有 RPC 都会失败。

# Review 3

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 404

Comment:
配置项 headers 被完全忽略

config.schema.json 和文件头注释都声明支持自定义 HTTP 头,但登录请求与只读请求各自硬编码 headers,合并后的 bindings.headers 在整个实现中从未被读取。用户按配置填写的额外请求头(例如反向代理鉴权头)会被静默丢弃,依赖这些头的部署会直接请求失败。

# Review 4

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/package.json
Line: 376

Comment:
根包清单未声明新增的 socks-proxy-agent 运行时依赖

本次把新服务加入了根包的 files 与 bin,但该服务在模块顶层 import 的 'socks-proxy-agent' 只写在服务本地 package.json 中,根 services/package.json 的 dependencies 和 bundledDependencies 都没有加入该包。以仓库根包安装或打包方式运行(以及从根目录解析模块的测试)时,node_modules 中不存在该模块,服务启动即报 ERR_MODULE_NOT_FOUND,所有 RPC 不可用。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

clearTimeout(timer);
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 非代理请求的超时未覆盖响应体读取

Category: 稳定性与可用性

fetchWithTimeout 在 fetch 收到响应头并返回后就在 finally 中清除定时器,而 readJsonResponse 此后才 await res.text() 读取响应体。如果上游先返回响应头、再长时间不发送响应体,配置的 timeoutMs 不会生效,RPC 会一直挂起到 undici 默认的体超时(约 300 秒),造成巡检卡死。

Problem code:

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
const dispatcher = await createTlsDispatcher(skipTlsVerify);
try {
return await fetch(url, {
...init,
signal: controller.signal,
...(dispatcher ? { dispatcher } : {}),
});
} finally {
clearTimeout(timer);
}
};

Recommendation:
把响应体读取纳入超时中止范围,例如让 AbortController 保持到 res.text() 完成,或在 fetchWithTimeout 内部完成响应体读取。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 232-245

Comment:
非代理请求的超时未覆盖响应体读取

fetchWithTimeout 在 fetch 收到响应头并返回后就在 finally 中清除定时器,而 readJsonResponse 此后才 await res.text() 读取响应体。如果上游先返回响应头、再长时间不发送响应体,配置的 timeoutMs 不会生效,RPC 会一直挂起到 undici 默认的体超时(约 300 秒),造成巡检卡死。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

const proxiedFetch = (url, { method = 'GET', headers = {}, body } = {}, { timeoutMs, proxyUrl, skipTlsVerify } = {}) => new Promise((resolve, reject) => {
const target = new URL(url);
const mod = target.protocol === 'https:' ? https : http;
const agent = new SocksProxyAgent(proxyUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 proxy_url 配置成 HTTP 代理时会抛错导致所有请求失败

Category: 功能正确性

config.schema.json 与 README 都把 proxy_url 描述为支持 HTTP/SOCKS 代理,但实现无条件执行 new SocksProxyAgent(proxyUrl),该 Agent 只接受 socks/socks4/socks5/socks5h 协议。配置 http:// 代理时构造会抛错且未转换为 gRPC 错误,所有 RPC 都会失败。

Problem code:

const agent = new SocksProxyAgent(proxyUrl);

Recommendation:
改用支持 HTTP 代理的 Agent(如 undici 的 ProxyAgent),或在配置 schema 与 README 中明确限定为 SOCKS,并补充 HTTP 代理用例。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 249

Comment:
proxy_url 配置成 HTTP 代理时会抛错导致所有请求失败

config.schema.json 与 README 都把 proxy_url 描述为支持 HTTP/SOCKS 代理,但实现无条件执行 new SocksProxyAgent(proxyUrl),该 Agent 只接受 socks/socks4/socks5/socks5h 协议。配置 http:// 代理时构造会抛错且未转换为 gRPC 错误,所有 RPC 都会失败。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

}

// 2. 登录(Django CSRF 需要 x-csrftoken 头 + csrftoken cookie + Referer 头匹配 Host)
const headers = { 'content-type': 'application/json', referer: `${baseUrl}/` };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 配置项 headers 被完全忽略

Category: 功能正确性

config.schema.json 和文件头注释都声明支持自定义 HTTP 头,但登录请求与只读请求各自硬编码 headers,合并后的 bindings.headers 在整个实现中从未被读取。用户按配置填写的额外请求头(例如反向代理鉴权头)会被静默丢弃,依赖这些头的部署会直接请求失败。

Problem code:

const headers = { 'content-type': 'application/json', referer: `${baseUrl}/` };

Recommendation:
在 doLogin 和 authenticatedGet 构造 headers 时合并 bindings.headers,并补充对应单元测试。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 404

Comment:
配置项 headers 被完全忽略

config.schema.json 和文件头注释都声明支持自定义 HTTP 头,但登录请求与只读请求各自硬编码 headers,合并后的 bindings.headers 在整个实现中从未被读取。用户按配置填写的额外请求头(例如反向代理鉴权头)会被静默丢弃,依赖这些头的部署会直接请求失败。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

Comment thread services/package.json
"slack__group-robot",
"chaitin__safeline-waf-eliminate-false-positive",
"chaitin__safeline-waf",
"chaitin__safeline-waf-login",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 根包清单未声明新增的 socks-proxy-agent 运行时依赖

Category: 稳定性与可用性

本次把新服务加入了根包的 files 与 bin,但该服务在模块顶层 import 的 'socks-proxy-agent' 只写在服务本地 package.json 中,根 services/package.json 的 dependencies 和 bundledDependencies 都没有加入该包。以仓库根包安装或打包方式运行(以及从根目录解析模块的测试)时,node_modules 中不存在该模块,服务启动即报 ERR_MODULE_NOT_FOUND,所有 RPC 不可用。

Problem code:

"chaitin__safeline-waf-login",

Recommendation:
在 services/package.json 的 dependencies 与 bundledDependencies 中补充 socks-proxy-agent。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/package.json
Line: 376

Comment:
根包清单未声明新增的 socks-proxy-agent 运行时依赖

本次把新服务加入了根包的 files 与 bin,但该服务在模块顶层 import 的 'socks-proxy-agent' 只写在服务本地 package.json 中,根 services/package.json 的 dependencies 和 bundledDependencies 都没有加入该包。以仓库根包安装或打包方式运行(以及从根目录解析模块的测试)时,node_modules 中不存在该模块,服务启动即报 ERR_MODULE_NOT_FOUND,所有 RPC 不可用。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

…service

- 雷池控制台无 OpenAPI 场景:Django CSRF + session 会话认证
- 方法:Login / GetProfile / GetOverview / SearchDetectLog / GetESIndices
- 内存会话管理(crypto.randomUUID,TTL 30min),增加 socks5 代理支持
- export transport and error helpers via _test for unit testing
- cover proxiedFetch socks5 transport with mocked http.request
- cover error mapping, empty body, missing-sessionid and missing-endpoint branches
…ate missing sessionid

The smoke harness synthesizes the mock upstream as an http base URL, which was
fed verbatim to SocksProxyAgent and failed every Connect call with "A socks
protocol must be specified! Got: http:". Only route socks:// URLs through the
agent and fall back to direct for the rest.

Add a smoke fixture targeting Login (the only method that needs no prior
session) and stop rejecting a login whose 200 response omits the sessionid
cookie, so the generic smoke mock can complete the call. Authenticated reads
still surface a missing session as PERMISSION_DENIED on their next call.
@monkeyscan

monkeyscan Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

PR Title: feat(services/safeline-waf-login): add SafeLine WA...

Commit: aa1c50e

整体评估

本轮改动很小,是在上一轮新增 SafeLine WAF 登录服务的基础上,为跑通通用冒烟测试而调整代理 URL 解析、放宽登录 sessionid 校验并新增 Login 冒烟用例。整体结构未变,但这两处兼容性调整触及了代理配置语义与认证成功判定,需要谨慎评估。

总结

本轮引入两项回归:HTTP 代理配置被静默忽略并回退直连,以及登录未拿到 sessionid 时仍返回成功;前者可能让流量绕过既定代理并导致请求失败,后者会掩盖真实的登录失败,建议合入前修复。上一轮仍未解决的 headers 配置被忽略、非代理请求超时未覆盖响应体读取两项问题也依然存在。

Findings (2)

  • 🟠 [HIGH] services/chaitin__safeline-waf-login/src/safeline-waf-login.js:168 — HTTP 代理配置被静默忽略并回退直连
  • 🟡 [MEDIUM] services/chaitin__safeline-waf-login/src/safeline-waf-login.js:426 — 登录未拿到 sessionid 时仍返回成功
Prompt To Fix All With AI
# Review 1

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 163-168

Comment:
HTTP 代理配置被静默忽略并回退直连

resolveProxyUrl 现在只返回 socks 系协议,README 与 config.schema.json 明确支持的 http:// 或 https:// 代理会被解析为空字符串,fetchSafeline 随即走直连。用户配置的代理被静默绕过,既可能因网络隔离导致所有 RPC 失败,也会让本应经代理转发的登录凭据直接发往目标地址。

# Review 2

This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 423-426

Comment:
登录未拿到 sessionid 时仍返回成功

doLogin 删除了 sessionid 缺失时的 PERMISSION_DENIED 校验,现在上游返回 200 但未下发 sessionid(包括空响应体命中默认值的情况)也会被当作登录成功,并把空 sessionid 写入会话。调用方会拿到看似有效却无法通过认证的 session_token,真实登录失败被推迟到后续读取才暴露,定位困难且返回语义错误。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

// Only socks:// schemes are routable through SocksProxyAgent; a plain http(s)
// URL (e.g. the smoke harness synthesizing the mock upstream) is not a proxy.
return /^socks(4a?|5h?)?:\/\//i.test(raw) ? raw : '';
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HTTP 代理配置被静默忽略并回退直连

Category: 安全与隐私

resolveProxyUrl 现在只返回 socks 系协议,README 与 config.schema.json 明确支持的 http:// 或 https:// 代理会被解析为空字符串,fetchSafeline 随即走直连。用户配置的代理被静默绕过,既可能因网络隔离导致所有 RPC 失败,也会让本应经代理转发的登录凭据直接发往目标地址。

Problem code:

const resolveProxyUrl = (bindings = {}) => {
const raw = String(firstDefined(bindings?.proxy_url, bindings?.proxyUrl) || '').trim();
// Only socks:// schemes are routable through SocksProxyAgent; a plain http(s)
// URL (e.g. the smoke harness synthesizing the mock upstream) is not a proxy.
return /^socks(4a?|5h?)?:\/\//i.test(raw) ? raw : '';
};

Recommendation:
继续为 http(s) 代理提供支持(例如使用 undici 的 ProxyAgent),或在配置校验阶段对不支持的协议返回明确的配置错误,而不是静默丢弃;同时补充 http(s) 代理的单元测试。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 163-168

Comment:
HTTP 代理配置被静默忽略并回退直连

resolveProxyUrl 现在只返回 socks 系协议,README 与 config.schema.json 明确支持的 http:// 或 https:// 代理会被解析为空字符串,fetchSafeline 随即走直连。用户配置的代理被静默绕过,既可能因网络隔离导致所有 RPC 失败,也会让本应经代理转发的登录凭据直接发往目标地址。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

// A login that returns 200 with no business error is treated as success even
// when the upstream omits the sessionid cookie (e.g. the smoke harness mock).
// Authenticated reads surface the missing session on their next call, so a
// genuine login failure is still reported as PERMISSION_DENIED at read time.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 登录未拿到 sessionid 时仍返回成功

Category: 功能正确性

doLogin 删除了 sessionid 缺失时的 PERMISSION_DENIED 校验,现在上游返回 200 但未下发 sessionid(包括空响应体命中默认值的情况)也会被当作登录成功,并把空 sessionid 写入会话。调用方会拿到看似有效却无法通过认证的 session_token,真实登录失败被推迟到后续读取才暴露,定位困难且返回语义错误。

Problem code:

// A login that returns 200 with no business error is treated as success even
// when the upstream omits the sessionid cookie (e.g. the smoke harness mock).
// Authenticated reads surface the missing session on their next call, so a
// genuine login failure is still reported as PERMISSION_DENIED at read time.

Recommendation:
保留 sessionid 为空时报 PERMISSION_DENIED 的校验;为跑通冒烟测试,应调整 smoke harness 或 mock 上游返回 sessionid,而不是放宽生产环境的登录成功判定。

Prompt To Fix All With AI
This is a comment left during a code review.
Repository: https://github.com/chaitin/OctoBus
Path: services/chaitin__safeline-waf-login/src/safeline-waf-login.js
Line: 423-426

Comment:
登录未拿到 sessionid 时仍返回成功

doLogin 删除了 sessionid 缺失时的 PERMISSION_DENIED 校验,现在上游返回 200 但未下发 sessionid(包括空响应体命中默认值的情况)也会被当作登录成功,并把空 sessionid 写入会话。调用方会拿到看似有效却无法通过认证的 session_token,真实登录失败被推迟到后续读取才暴露,定位困难且返回语义错误。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix with MonkeyCode
Fix with Claude
Fix with Codex

@Daemonceltics
Daemonceltics merged commit 2e4573b into chaitin:main Nov 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant