Compare commits

...
Author SHA1 Message Date
testclient-admin 74a056e8a5 Merge pull request 'docs: AGENTS.md — PR только через gitea MCP' (#11) from infra/agents-md-mcp-pr-rule into main
Reviewed-on: testclient-admin/playground#11
2026-08-23 16:25:22 +00:00
testclient-admin 5d7cec819b Merge pull request 'Add Level 0 + Level 1 + Level 2 security scanning' (#12) from add-security-scanning into main
Reviewed-on: testclient-admin/playground#12
2026-08-23 16:25:10 +00:00
playground-security-bot 526c2862f6 security: scan results for PR #12
security / scan (pull_request) Skipped
security / review (pull_request) Skipped
security / deep-audit (pull_request) Skipped
2026-08-23 16:13:56 +00:00
playground-security-bot 063faeaa5a security: scan results for PR #12
security / scan (pull_request) Skipped
security / review (pull_request) Skipped
security / deep-audit (pull_request) Skipped
2026-08-23 16:12:26 +00:00
testclient-admin bae21bcff8 Level 0: security scanning for pull requests
security/scan 0 findings, 0 blocking
security / scan (pull_request) Successful in 1m8s
security/review 0 findings, 0 blocking
security / review (pull_request) Successful in 20s
security / deep-audit (pull_request) Skipped
2026-08-23 16:11:13 +00:00
testclient-admin 0103775e5a Level 0: security scanning for pull requests 2026-08-23 16:11:12 +00:00
testclient-admin 4777411360 Level 0: security scanning for pull requests 2026-08-23 16:11:11 +00:00
playground-security-bot 323ebd1e28 security: scan results for PR #11
security / scan (pull_request) Skipped
security / review (pull_request) Skipped
security / deep-audit (pull_request) Skipped
2026-08-23 15:44:02 +00:00
dev1-playground-agent ff68f216ce docs: clarify AGENTS.md — git native, PR via gitea MCP only
security/scan 0 findings, 0 blocking
security / scan (pull_request) Successful in 1m14s
security/review 0 findings, 0 blocking
security / review (pull_request) Successful in 20s
security / deep-audit (pull_request) Skipped
2026-08-23 15:42:43 +00:00
5 changed files with 56 additions and 12 deletions
+44 -8
View File
@@ -154,6 +154,22 @@ jobs:
blocking = [f for f in findings if f["severity"] in policy["block_on"] and f["confidence"] >= policy["min_confidence"]]
blocked = len(blocking) > 0
# Один и тот же коммит может быть провёрен дважды (см. баг
# Gitea с переиспользованием SHA между разными PR — два
# параллельных прогона на идентичный коммит). Статус в
# Gitea хранит только ПОСЛЕДНЮЮ запись по (sha, context),
# так что более поздний, но менее строгий результат тихо
# затирает более ранний блокирующий. Раз уже была
# зафиксирована блокировка на этом коммите — не снимаем
# её молча, только новым коммитом.
prior_failed = False
try:
prior = gitea("GET", f"/repos/{REPO}/commits/{COMMIT_SHA}/statuses")
prior_failed = any(s.get("context") == "security/scan" and s.get("status") == "failure" for s in prior)
except Exception as e:
print(f"не удалось прочитать прежние статусы, продолжаю без sticky-fail: {e}")
sticky = prior_failed and not blocked
outdir = f"security-analysis/findings/pr-{PR_NUMBER or 'manual'}"
os.makedirs(outdir, exist_ok=True)
outpath = f"{outdir}/{int(time.time())}.json"
@@ -177,19 +193,22 @@ jobs:
for f in top:
body += f"**{f['severity'].upper()}** `{f['file']}:{f['line_start']}` — {f['title']} ({f['source']})\n\n"
body += f"Полный список: `{outpath}`\n\n"
if sticky:
body += "🔴 **Merge заблокирован** — этот же коммит уже был помечен как блокирующий в более раннем прогоне; новый прогон нашёл меньше, но старую блокировку это не снимает (нужен новый коммит).\n"
else:
body += "🔴 **Merge заблокирован** — есть находки выше порога `security-analysis/policy.yml`.\n" if blocked else "✅ Порог не превышен.\n"
gitea("POST", f"/repos/{REPO}/issues/{PR_NUMBER}/comments", {"body": body})
gitea("POST", f"/repos/{REPO}/statuses/{COMMIT_SHA}", {
"state": "failure" if blocked else "success",
"state": "failure" if (blocked or sticky) else "success",
"context": "security/scan",
"description": f"{len(findings)} findings, {len(blocking)} blocking",
"description": (f"{len(findings)} findings, {len(blocking)} blocking" + (" (sticky: prior run flagged this commit)" if sticky else "")),
"target_url": f"{SERVER}/{REPO}/src/branch/{HEAD_REF}/{outpath}",
})
print(f"findings: {len(findings)}, blocking: {len(blocking)}")
if blocked:
print(f"findings: {len(findings)}, blocking: {len(blocking)}, sticky: {sticky}")
if blocked or sticky:
sys.exit(1)
PYEOF
@@ -440,6 +459,20 @@ jobs:
blocking = [f for f in findings if f["severity"] in policy["block_on"] and f["confidence"] >= policy["min_confidence"]]
blocked = len(blocking) > 0
# См. аналогичный комментарий в шаге scan: LLM-ревьюер не
# детерминирован, а один коммит может быть провёрен дважды
# параллельно (баг Gitea с переиспользованием SHA между
# PR). Если более ранний прогон на ЭТОМ ЖЕ коммите уже
# нашёл блокирующую находку, более поздний "пустой" ответ
# модели не должен тихо снимать блокировку.
prior_failed = False
try:
prior = gitea("GET", f"/repos/{REPO}/commits/{COMMIT_SHA}/statuses")
prior_failed = any(s.get("context") == "security/review" and s.get("status") == "failure" for s in prior)
except Exception as e:
print(f"не удалось прочитать прежние статусы, продолжаю без sticky-fail: {e}")
sticky = prior_failed and not blocked
outdir = f"security-analysis/findings/pr-{PR_NUMBER or 'manual'}"
outpath = f"{outdir}/{int(time.time())}-review.json"
@@ -467,19 +500,22 @@ jobs:
if f.get("exploit_scenario"):
body += f" сценарий: {f['exploit_scenario']}\n\n"
body += f"Полный список: `{outpath}`\n\n"
if sticky:
body += "🔴 **Merge заблокирован** — этот же коммит уже был помечен как блокирующий в более раннем прогоне ревью; новый прогон ничего не нашёл, но старую блокировку это не снимает (нужен новый коммит).\n"
else:
body += "🔴 **Merge заблокирован** — есть находки выше порога `security-analysis/policy.yml`.\n" if blocked else "✅ Порог не превышен.\n"
gitea("POST", f"/repos/{REPO}/issues/{PR_NUMBER}/comments", {"body": body})
gitea("POST", f"/repos/{REPO}/statuses/{COMMIT_SHA}", {
"state": "failure" if blocked else "success",
"state": "failure" if (blocked or sticky) else "success",
"context": "security/review",
"description": f"{len(findings)} findings, {len(blocking)} blocking",
"description": (f"{len(findings)} findings, {len(blocking)} blocking" + (" (sticky: prior run flagged this commit)" if sticky else "")),
"target_url": f"{SERVER}/{REPO}",
})
print(f"findings: {len(findings)}, blocking: {len(blocking)}")
if blocked:
print(f"findings: {len(findings)}, blocking: {len(blocking)}, sticky: {sticky}")
if blocked or sticky:
sys.exit(1)
PYEOF2
+7 -2
View File
@@ -8,8 +8,13 @@
прямой push всё равно отклонится. Для любой задачи:
1. Создай новую ветку от `main` с понятным именем по задаче.
2. Делай коммиты в неё как обычно.
3. Когда готово — открой pull request в `main` и опиши, что сделано.
2. Делай коммиты в неё как обычно (`git add`, `git commit`, `git push`
обычный нативный git, доступы уже настроены).
3. Когда готово — открой pull request в `main` ЧЕРЕЗ ИНСТРУМЕНТ gitea MCP
(не через git push с параметрами PR, не через веб-логин, не проси
логин/пароль — они не нужны). Открытие PR/issue — это единственная
операция, которая должна идти через MCP; сам git (clone/commit/push)
остаётся обычным.
Дальше pull request проходит автоматическую проверку (security-скан) и
ревью — это не твоя забота, просто открой PR и жди.
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
[]