Files
lixi 4762358f54
CI / ai-gates (push) Failing after 29s
fix(security): 凭证扫描放行依赖注入传参 + 四仓口径更正
`api_key=volcengine.api_key` 这类**依赖注入传参**被 KEY-ASSIGN 判为疑似凭证。
这是规则的真缺口而非代码问题:行里没有任何秘密,而做 DI 的代码到处都是这种
写法——绕过一次就得在每个调用点绕过,那等于把规则废掉。故改规则。

新增 ALLOW_REFERENCE,刻意收得很紧以免开后门:
- 值必须是**未加引号**的小写起首标识符引用(真密钥要么带引号,要么不是标识符形状)
- 只允许**恰好一个点且随即行尾**
- 连字符不在字符集内

对抗性夹具验证(三真三假):
- 拦下 `api_key = "sk-T3Blbk…"`(OpenAI 形态)
- 拦下 `secret_key: "AKID…"`(腾讯云形态)
- 拦下 `auth_token=eyJ….eyJ….Sfl…`(**三段式 JWT——两个点,故不落进放行**)
- 放行 `api_key=lowercase.reference` / `api_key = settings.api_key` / `api_token: config.authToken`
原 5 形态泄漏夹具复验仍 8 条命中,一条不少。

另更正口径:脚本头与 git-workflow.md 仍写「三仓同构」,实际已是四仓——
patbond-ai 是唯一持有 AI 服务商凭证的仓,漏同步它风险最大。四仓 md5 已一致
(4945940093b4b8413b7d3eec8bf6a5ec),四仓 --all 全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 12:18:18 +08:00

177 lines
7.1 KiB
Python

"""火山方舟错误分类的测试。
每个用例对应官方错误码表里的一行或一类。重点在三处**如果搞错只会在生产暴露**
的地方:`QuotaExceeded` 的一码两义、内容安全类必须不可重试、未知码必须偏向
可重试而不是直接判死。
"""
from app.domain.generation import Retry, UserFacing
from app.providers.volcengine.errors import classify
class TestQuotaExceededIsTwoDifferentThings:
"""同一个 code,两种完全不同的处置。只看 code 必然错一半。"""
def test_queue_backlog_is_a_seconds_long_wait(self):
# 官方原文:「当前账号处于排队中状态的任务数已超过限制,请稍后重试。」
result = classify(
"QuotaExceeded", "The request has exceeded the quota. Request ID: x."
)
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.RATE_LIMITED
def test_queue_backlog_recognised_from_chinese_message(self):
result = classify("QuotaExceeded", "当前账号处于排队中状态的任务数已超过限制")
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.RATE_LIMITED
def test_free_trial_exhausted_needs_billing_action(self):
# 官方原文:「免费试用额度已消耗完毕,请前往控制台开通对应模型服务。」
result = classify(
"QuotaExceeded",
"Your account [x] has exhausted its free trial quota for the [y] model.",
)
assert result.retry is Retry.QUOTA
assert result.user_facing is UserFacing.QUOTA_EXHAUSTED
def test_periodic_limit_exhausted_needs_to_wait_for_reset(self):
result = classify(
"QuotaExceeded",
"You have exceeded the 5-hour/weekly/monthly usage quota. It will reset at T.",
)
assert result.retry is Retry.QUOTA
assert result.user_facing is UserFacing.QUOTA_EXHAUSTED
class TestContentRejectionMustNotBeRetried:
"""同样的输入必然同样被拒。重试只会白烧额度再失败。"""
def test_input_image_sensitive(self):
result = classify("InputImageSensitiveContentDetected")
assert result.retry is Retry.NEVER
assert result.user_facing is UserFacing.CONTENT_REJECTED
def test_output_video_sensitive(self):
result = classify("OutputVideoSensitiveContentDetected")
assert result.retry is Retry.NEVER
assert result.user_facing is UserFacing.CONTENT_REJECTED
def test_policy_violation_subcode(self):
result = classify("InputVideoSensitiveContentDetected.PolicyViolation")
assert result.retry is Retry.NEVER
def test_real_person_subcode(self):
result = classify("InputImageSensitiveContentDetected.PrivacyInformation")
assert result.retry is Retry.NEVER
def test_risk_detection_product_codes(self):
assert classify("InputTextRiskDetection").retry is Retry.NEVER
assert classify("OutputImageRiskDetection").retry is Retry.NEVER
def test_but_the_detector_itself_failing_is_retryable(self):
# 风险识别产品请求失败 ≠ 内容真的违规。
result = classify("ContentSecurityDetectionError", "Internal error.")
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.UPSTREAM_UNAVAILABLE
class TestRateLimitFamily:
def test_endpoint_rpm(self):
result = classify("RateLimitExceeded.EndpointRPMExceeded")
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.RATE_LIMITED
def test_model_account_tpm(self):
assert classify("ModelAccountTpmRateLimitExceeded").retry is Retry.BACKOFF
def test_server_overloaded(self):
assert classify("ServerOverloaded").retry is Retry.BACKOFF
def test_request_burst_too_fast(self):
# doubao-seed-2.0 之后版本的突增流量保护码。
assert classify("RequestBurstTooFast").retry is Retry.BACKOFF
def test_images_per_minute(self):
assert classify("ModelAccountIpmRateLimitExceeded").retry is Retry.BACKOFF
class TestQuotaAndBillingFamily:
def test_inference_limit_set_by_account(self):
result = classify("SetLimitExceeded")
assert result.retry is Retry.QUOTA
assert result.user_facing is UserFacing.QUOTA_EXHAUSTED
def test_concurrency_cap_needs_topup(self):
assert classify("InflightBatchsizeExceeded").retry is Retry.QUOTA
def test_account_overdue_is_403_but_same_user_action(self):
# HTTP 状态码不同(403 而非 429),但用户要做的事一样:去充值。
result = classify("AccountOverdueError")
assert result.retry is Retry.QUOTA
assert result.user_facing is UserFacing.QUOTA_EXHAUSTED
def test_model_not_activated(self):
assert classify("ModelNotOpen").retry is Retry.QUOTA
class TestOurOwnFaults:
"""重试无意义,需要人改代码或改配置。"""
def test_bad_api_key(self):
result = classify("AuthenticationError")
assert result.retry is Retry.NEVER
assert result.user_facing is UserFacing.SERVER_ERROR
def test_unknown_model_id(self):
assert classify("InvalidEndpointOrModel.NotFound").retry is Retry.NEVER
def test_invalid_parameter(self):
assert classify("InvalidParameter").retry is Retry.NEVER
def test_task_type_constraint_is_our_parameter_problem(self):
# Seedance 2.5 全模态任务的参数与模型判定的任务类型不兼容。
assert classify("InvalidParameter.TaskTypeConstraint").retry is Retry.NEVER
def test_task_type_mismatch(self):
assert classify("InvalidParameter.TaskTypeMismatch").retry is Retry.NEVER
def test_missing_parameter(self):
assert classify("MissingParameter").retry is Retry.NEVER
def test_payload_too_large(self):
assert classify("RequestTooLarge").retry is Retry.NEVER
class TestUpstreamErrors:
def test_internal_service_error_is_retryable(self):
result = classify("InternalServiceError")
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.UPSTREAM_UNAVAILABLE
class TestUnknownCodesLeanTowardsRetry:
"""厂商在持续新增错误码。把未知码判死会让一次抖动变成用户看到的失败;
重试预算本身有上限,最坏只是多试两次。"""
def test_unknown_code(self):
result = classify("SomeBrandNewCodeVolcengineAddedLastWeek")
assert result.retry is Retry.BACKOFF
assert result.user_facing is UserFacing.UPSTREAM_UNAVAILABLE
def test_missing_code(self):
assert classify(None).retry is Retry.BACKOFF
assert classify("").retry is Retry.BACKOFF
class TestProviderCodeIsAlwaysPreserved:
"""原始码绝不丢弃——排查时它是唯一线索。"""
def test_known_code(self):
assert classify("ServerOverloaded").provider_code == "ServerOverloaded"
def test_unknown_code(self):
assert classify("WeirdCode").provider_code == "WeirdCode"
def test_whitespace_is_trimmed(self):
assert classify(" ServerOverloaded ").provider_code == "ServerOverloaded"