ci: bootstrap trusted AI review verifier - #174
Conversation
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughДобавлен скрипт проверки exact-head AI-review evidence для PR: он опрашивает GitHub, сопоставляет свежие запросы review с review/status доказательствами CodeRabbit и Codex, затем завершает workflow успехом или ошибкой. ChangesПроверка контракта AI-review
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels: ci, automation, review-contract 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
PR Summary by QodoCI: bootstrap trusted AI review verifier script
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
🚦 Roby’s Lighthouse contractMobile
Hard assertions: ✅ · Regression: ✅ Desktop
Hard assertions: ✅ · Regression: ✅ D.1 runs in observability mode. The final gate is enabled only after the reviewed baseline commit. |
|
@coderabbitai review Exact head: d8992bf |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 174 --repo safal207/robys-coffee-house-demo --json headRefOid,headRefName,files,commits -q '{headSha: .headRefOid, files: [.files[].path]}'Length of output: 424
✅ Action performedReview finished.
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
11 rules 1.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/verify-ai-review-contract.cjs`:
- Around line 85-104: The polling loop in verify-ai-review-contract.cjs is
re-fetching all comments, reviews, and statuses on every iteration, which
creates unnecessary API load. Update the Promise.all call to use incremental
fetching for github.rest.issues.listComments by passing a since value derived
from headUpdateAnchor, while keeping the existing created_at filtering in
freshRequest for correctness. Leave the reviews and commit statuses logic intact
unless there is an equivalent safe incremental filter available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d29a6904-84cd-4dde-b8b4-7405b70d1597
📒 Files selected for processing (1)
scripts/verify-ai-review-contract.cjs
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
- GitHub Check: profiles / profile (mobile)
- GitHub Check: profiles / profile (desktop)
- GitHub Check: VISUAL-001 screenshot diff
- GitHub Check: verify
- GitHub Check: DAST-001 passive web scan
⚠️ CI failures not shown inline (2)
GitHub Actions: Bot review disposition contract / REVIEW-LEDGER exact-head findings: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
GitHub Actions: Bot review disposition contract / 0_REVIEW-LEDGER exact-head findings.txt: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
🧰 Additional context used
📓 Path-based instructions (1)
scripts/**
⚙️ CodeRabbit configuration file
scripts/**: Ищи недетерминированность, небезопасную работу с путями и shell quoting,
скрытое ослабление проверок, сетевые зависимости, утечки секретов и случаи,
когда проверка может ложно завершиться успешно.
Files:
scripts/verify-ai-review-contract.cjs
🔇 Additional comments (5)
scripts/verify-ai-review-contract.cjs (5)
3-11: Проверка casing review.state и commit status API подтверждена — работает как задумано.Убедился через документацию GitHub, что
review.stateдействительно возвращается в верхнем регистре ("PENDING","DISMISSED"), поэтому сравнения вisSubmittedActiveReviewкорректны и не создают ложно-успешного прохождения pending/dismissed ревью. Также подтверждено, что CodeRabbit публикует именно классический commit status (не Checks API) через настройкуreviews.commit_status, так что обращение кlistCommitStatusesForRefвалидно.Also applies to: 26-32, 128-135
106-135: 🎯 Functional CorrectnessАсимметрия timing-условий: review требует порядок после запроса, status — нет.
Для
codeRabbitReviewжёстко требуетсяsubmittedTimeOf(review) >= codeRabbitRequestAt(ревью после запроса). ДляcodeRabbitStatusусловие слабее —createdTimeOf(status) >= headUpdateAnchor, без привязки кcodeRabbitRequestAt. Это значит, что автоматический успешный status, созданный CodeRabbit сразу после пуша (до того как доверенный мейнтейнер вообще написал@coderabbitai review <sha>), всё равно засчитывается как доказательство, как только позже появится любой валидный trusted-запрос с этим SHA — даже если status логически не связан с этим запросом.Судя по описанию PR ("commit status created in the same head-update window"), это может быть намеренным упрощением (status генерируется автоматически при пуше, а не по команде). Стоит подтвердить, что это осознанный компромисс, а не пропущенная проверка порядка.
145-149: 🩺 Stability & Availability | ⚡ Quick winФинальный
core.setFailedне содержит причину транзиентных ошибок.В
catchошибки только логируются черезcore.warningи теряются к моменту итоговогоsetFailed(строка 191-193). Если 15 минут подряд падает, например,getWorkflowRunиз-за нехватки прав илиpulls.listReviewsиз-за rate limit, итоговое сообщение об ошибке будет говорить про "trusted exact-head review", хотя реальная причина — API-ошибка. Это усложняет диагностику сбоев обязательного review-гейта.As per path instructions for
scripts/**: "Ищи ... случаи, когда проверка может ложно завершиться успешно" — здесь обратный риск: ложно неинформативный отказ, маскирующий инфраструктурную проблему.💡 Предложение: сохранять последнюю ошибку и включать её в setFailed
for (let attempt = 1; attempt <= POLL_ATTEMPTS; attempt += 1) { let codeRabbitRequestAt = 0; let codeRabbitReview; let codeRabbitStatus; let nativeCodexReview; + let lastError; try { ... } catch (error) { + lastError = error; core.warning( `Transient GitHub API error (${attempt}/${POLL_ATTEMPTS}): ${error.message}`, ); } ... } core.setFailed( - "Require a trusted exact-head `@coderabbitai` review request created after the immutable head-update anchor and native CodeRabbit evidence for that same head: either a submitted active review after the request or a successful bot-authored automatic commit status created in the same head-update window.", + "Require a trusted exact-head `@coderabbitai` review request created after the immutable head-update anchor and native CodeRabbit evidence for that same head: either a submitted active review after the request or a successful bot-authored automatic commit status created in the same head-update window." + + (lastError ? ` Last API error: ${lastError.message}` : ""), );Also applies to: 191-193
Source: Path instructions
34-53: Утилиты нормализации и построения exact-head паттерна — корректны.
commandLinesOfиcontainsExactHeadдают безопасный от ReDoS и от частичного совпадения SHA механизм (граница по не-hex символам), а использованиеcreated_atвместоupdated_atво всех местах (createdTimeOf,latestCreatedTime) корректно закрывает сценарий редактирования старого комментария для имитации свежего запроса.
55-61: 🩺 Stability & AvailabilityПроверьте trigger workflow и
permissionsтокена. Скрипт падает безcontext.payload.pull_request.head.sha; если job не запускается наpull_request/pull_request_target, это будет постоянный false-negative. Дляactions.getWorkflowRun,pulls.listReviews,issues.listCommentsиrepos.listCommitStatusesForRefнужныactions: read,pull-requests: read,issues: read,statuses: read— иначе проверка будет ложно проваливаться.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/verify-ai-review-contract.cjs`:
- Around line 49-57: `isPermissionError()` is treating every 403 as a fatal
permission failure, which causes valid GitHub API rate-limit responses to stop
polling. Update the logic in `isPermissionError` to distinguish true
access-denied cases from primary rate-limit 403s by checking the response
headers and/or message text, and only return true for actual permission problems
while allowing rate-limit 403s to be retried.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 31dc7af9-7929-4495-ae0b-40877fe03016
📒 Files selected for processing (1)
scripts/verify-ai-review-contract.cjs
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
- GitHub Check: profiles / profile (desktop)
- GitHub Check: VISUAL-001 screenshot diff
- GitHub Check: verify
- GitHub Check: ios-route-webkit
- GitHub Check: DAST-001 passive web scan
⚠️ CI failures not shown inline (2)
GitHub Actions: Bot review disposition contract / 0_REVIEW-LEDGER exact-head findings.txt: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
GitHub Actions: Bot review disposition contract / REVIEW-LEDGER exact-head findings: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
🧰 Additional context used
📓 Path-based instructions (1)
scripts/**
⚙️ CodeRabbit configuration file
scripts/**: Ищи недетерминированность, небезопасную работу с путями и shell quoting,
скрытое ослабление проверок, сетевые зависимости, утечки секретов и случаи,
когда проверка может ложно завершиться успешно.
Files:
scripts/verify-ai-review-contract.cjs
🔇 Additional comments (1)
scripts/verify-ai-review-contract.cjs (1)
95-95: LGTM!Also applies to: 112-149
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Disposition: accepted Corrections: permission failures now fail immediately with required scopes; comments are filtered with |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/verify-ai-review-contract.cjs`:
- Around line 53-56: Treat all non-rate-limit 403 responses as fatal permission
failures in the 403 classifier. Update the logic in the 403 handling path around
the existing message match so that only rate limit, secondary rate, and abuse
detection messages are treated as transient, while any other 403 seen by the
helper is considered a hard auth/permission error and causes immediate failure
instead of retrying.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 9a356f3c-3e9e-45f6-85b1-ded44a82f4c3
📒 Files selected for processing (1)
scripts/verify-ai-review-contract.cjs
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
- GitHub Check: profiles / profile (desktop)
- GitHub Check: profiles / profile (mobile)
- GitHub Check: verify
- GitHub Check: VISUAL-001 screenshot diff
- GitHub Check: DAST-001 passive web scan
⚠️ CI failures not shown inline (2)
GitHub Actions: Bot review disposition contract / REVIEW-LEDGER exact-head findings: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
GitHub Actions: Bot review disposition contract / 0_REVIEW-LEDGER exact-head findings.txt: ci: bootstrap trusted AI review verifier
Conclusion: failure
##[group]Run actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: const owner = context.repo.owner;
const repo = context.repo.repo;
const payloadPr = context.payload.pull_request;
const issuePr = context.payload.issue?.pull_request;
const prNumber = payloadPr?.number ?? (issuePr ? context.payload.issue.number : null);
if (!prNumber) {
core.notice('Event is not associated with a pull request.');
return;
}
const pr = (await github.rest.pulls.get({ owner, repo, pull_number: prNumber })).data;
const head = pr.head.sha.toLowerCase();
const [reviewComments, reviews, issueComments] = await Promise.all([
github.paginate(
github.rest.pulls.listReviewComments,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.pulls.listReviews,
{ owner, repo, pull_number: prNumber, per_page: 100 },
),
github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: prNumber, per_page: 100 },
),
]);
const reviewHeads = new Map(
reviews.map((review) => [review.id, review.commit_id?.toLowerCase()]),
);
const reviewBots = new Set([
'chatgpt-codex-connector',
'chatgpt-codex-connector[bot]',
'coderabbitai',
'coderabbitai[bot]',
'github-advanced-security',
'github-advanced-security[bot]',
]);
const trustedAssociations = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const exactHeadBody = (body) => new RegExp(`(^|[^0-9a-f])${head}([^0-9a-f]|$)`, 'i').test(body ?? '');
const timeOf = (item) => Math.max(
0,
...[item.submitted_at, item.created_at, item.updated_at]
.map((value) => Date.parse(value ?? 0))
.filter(Number.isFinite),
);
const isDispositionReply = (reply) => {
const body = (reply.body ?? '').replaceAll('`', '');
const disposition = /^Disposition:\s*(accepted|rejected-with-evidence|superseded)\s*$/im.test(body);
const exactHead = new RegExp(`^Head:\\s*${head}\\s*$`, 'im').test(body);
const maintainer = trustedAssociations.has(reply.author_as...
🧰 Additional context used
📓 Path-based instructions (1)
scripts/**
⚙️ CodeRabbit configuration file
scripts/**: Ищи недетерминированность, небезопасную работу с путями и shell quoting,
скрытое ослабление проверок, сетевые зависимости, утечки секретов и случаи,
когда проверка может ложно завершиться успешно.
Files:
scripts/verify-ai-review-contract.cjs
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Bootstrap-Exception: BOOTSTRAP_NOT_ON_DEFAULT_BRANCH The current default-branch AI workflow cannot securely validate a verifier that does not yet exist on the default branch. Repository policy explicitly requires merging the bootstrap first and testing it on the next PR. Scope is one verifier file; exact-head CodeRabbit status is successful; every review thread is resolved; security, CodeQL, ZAP, visual, WebKit, Lighthouse, runtime, traceability, reviewdog, and route-preflight checks are green. PR #173 remains blocked until it executes this verifier from its immutable base SHA. |
|
/merge-ready f9d99f6 |
Summary
Bootstrap the AI review verifier onto the trusted default branch before product PR #173 is allowed to execute it.
This PR intentionally adds exactly one file:
scripts/verify-ai-review-contract.cjsTrust boundary
PR #173 currently checks out and executes its verifier from the PR head. That is self-referential: a pull request can modify the code that decides whether the same pull request passed its mandatory review gate.
After this bootstrap PR is merged, #173 will be changed to check out the verifier from its immutable base SHA/default branch instead of the untrusted PR head.
Verifier contract
The bootstrapped verifier:
CodeRabbitcommit status created in the same head-update window;Scope boundary
No product, CSS, service-worker, visual, generated, or integrity-manifest files are changed.
Merge order
main.