P0 security batch: true global admin, quota gates on all spending paths, default quota for quota-less users, fix-review author trust + docker/owner attribution, GitHub App setup issuer binding, real cancel kill, wider shell env exclusion
- CODEX_GLOBAL_ADMINS replaces maintainer-derived global admin; admin endpoints (quotas, sweep, backup, push dispatch) fail-closed 403 when unset, with audit on allow and deny. - continue/followups/messages/retry check both caller and original creator quotas (USD + unpriced token cap), 402 on either overrun. - Quota-less users now get the #86 default quota instead of unlimited; init_db backfills and OAuth create/bind/existing-login branches INSERT OR IGNORE a default row; explicit NULL row stays unlimited. user_quotas added to migration tables. - /fix-review: untrusted authors rejected before dedup claim, no task; trusted tasks force executor=docker, created_by=project owner, owner quota gate, prompt is a fixed template plus a 2000-char excerpt. - GitHub App setup state only issued by global admins, state rows bind issued_by (ALTER-compatible for old DBs), callback rejects issuers no longer in the admin list without consuming the state. - Cancel: popen poll checks DB status every second, Docker path runs a cancel watchdog that kills by container name, write-back is CAS-guarded so late results never overwrite a new status. - SHELL_ENV_EXCLUDE adds *_TOKEN, *_AUTH*, *_CREDENTIAL*, *API_KEY*; comment states the residual risk: same-UID /proc environ remains readable, true isolation needs UID separation or hidepid. - Tests: new cloud/tests/test_p0_security.py (17 cases); old tests updated to the new semantics (admin env, default quota, trusted fix-review author) without weakening any gate.
This commit is contained in:
1 parent
d0ca1f7f60
commit
7091a2d0d2
13 files changed
+1017
-146
No files matched your search
@@ -25,6 +25,7 @@ from cloud.db import connect as _db_connect
|
||||
|
||||
__all__ = [
|
||||
"verify_github_signature",
|
||||
"is_trusted_fix_review_author",
|
||||
"parse_github_pr_comment",
|
||||
"parse_github_check_run",
|
||||
"WebhookDeliveryStore",
|
||||
@@ -110,6 +111,48 @@ def parse_github_pr_comment(payload):
|
||||
}
|
||||
|
||||
|
||||
# GitHub 在 issue_comment / pull_request_review_comment 事件里
|
||||
# 自带 author_association(由 GitHub 设定,不是评论者自填):
|
||||
# OWNER / MEMBER / COLLABORATOR 是仓库可信身份;CONTRIBUTOR
|
||||
# 及以下不是。PR/issue 作者本人评论自己的 PR 也可信(作者
|
||||
# 只能在自己的 PR 上触发,不构成跨仓库免费入口)。
|
||||
_TRUSTED_FIX_REVIEW_ASSOCIATIONS = frozenset(
|
||||
{"OWNER", "MEMBER", "COLLABORATOR"})
|
||||
|
||||
|
||||
def is_trusted_fix_review_author(payload):
|
||||
"""P0 安全批:/fix-review 评论者是否可信。
|
||||
|
||||
只认两条,任一成立即 True,其余一律 False(fail-closed):
|
||||
1. comment.user.author_association 在可信集里;
|
||||
2. 评论者 login 等于 issue 作者或 pull_request 作者。
|
||||
association 缺失且作者比对不上时返回 False——此时不要
|
||||
用 App token 现查协作者(本函数不联网),直接拒单,
|
||||
绝不因“查不到”就放行。这是 GitHub 事件字段校验,不
|
||||
是实时协作者 API 查询,部署文档里必须如实写清这一点。
|
||||
"""
|
||||
if not isinstance(payload, dict):
|
||||
return False
|
||||
comment = payload.get("comment")
|
||||
if not isinstance(comment, dict):
|
||||
return False
|
||||
user = comment.get("user") or {}
|
||||
author = user.get("login")
|
||||
if not author:
|
||||
return False
|
||||
if user.get("author_association") in _TRUSTED_FIX_REVIEW_ASSOCIATIONS:
|
||||
return True
|
||||
issue = payload.get("issue") or {}
|
||||
issue_user = issue.get("user") or {}
|
||||
if author == issue_user.get("login"):
|
||||
return True
|
||||
pull = payload.get("pull_request") or {}
|
||||
pull_user = pull.get("user") or {}
|
||||
if author == pull_user.get("login"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def parse_github_check_run(payload):
|
||||
"""解析 GitHub check_run / check_suite 事件,返回结构化结果或 None。
|
||||
|
||||
|
||||
Reference in new issue
Block a user