Skip to content

ci: add first-party CLA action (replaces archived contributor-assistant) - #6

Merged
evgsentrium merged 11 commits into
productionfrom
cla-action
Jul 3, 2026
Merged

ci: add first-party CLA action (replaces archived contributor-assistant)#6
evgsentrium merged 11 commits into
productionfrom
cla-action

Conversation

@andamasov

Copy link
Copy Markdown
Member

What

First-party node24 JS action at .github/actions/cla/ implementing the exact CLA-check subset the fleet uses (spec + plan both dual-gated Codex+agy). Does NOT change cla-reusable.yml — the swap is a follow-up PR after a canary e2e.

Covers: committer collection with per-role unlinked-identity rules (web-flow/noreply@github.com exemptions), trim-safe allowlist, signature match by numeric id against signatures/version1/cla.json (schema + byte format unchanged — 2-space indent, no trailing newline, verified against production), single marker+bot-author status comment with legacy contributor-assistant adoption + non-blocking dedupe, byte-exact sign/recheck comment flows with idempotent SHA-retried signature writes, workflow-scoped PR-head unblock re-run (the mechanism behind today's run_attempt: 2 flips), file bootstrap, closed/non-PR no-ops. All-signed PRs get NO bot comment (edit-only-if-exists, matching upstream UX).

Tests: 52, node:test, mocked octokit, no network. CI: action-ci.yml (tests + dist freshness via git status --porcelain, SHA-pinned checkout/setup-node, persist-credentials: false).

Notable decisions

  • Deps pinned to CommonJS majors @actions/core@^1.11.1 + @actions/github@^6.0.0: current 3.x/9.x majors are ESM-only (type: module), conflicting with the CJS design constraint. Known npm-audit findings via @actions/http-client@2.xundici@5 accepted (client talks only to api.github.com); ESM/dep modernization is an explicit follow-up.
  • 422 kept in the signature-write retry alongside 409: a concurrent bootstrap create returns 422 ("sha wasn't supplied"), and refetch+retry is exactly what recovers it.

Why

contributor-assistant/github-action is archived (read-only since 2026-03) — frozen code on a merge-blocking fleet-wide check across ~56 repos.

Rollout (after this PR)

Canary e2e on a throwaway branch + vyos/gh-action-test, then a one-line swap PR in cla-reusable.yml. Rollback at any point = revert to the SHA-pinned archived action.

Advances: IS-580

🤖 Generated by robots

andamasov added 9 commits July 3, 2026 08:52
Deps pinned to the CommonJS majors (@actions/core@^1.11.1,
@actions/github@^6.0.0): the current 3.x/9.x majors are ESM-only
(type: module), which conflicts with the plan's node24 CommonJS
constraint. Known npm-audit findings via @actions/http-client@2.x ->
undici@5 are accepted for now (client talks only to api.github.com);
the ESM/dep-modernization is an explicit follow-up.

Advances: IS-580

🤖 Generated by [robots](https://vyos.io)
Serialization mirrors the live cla.json byte format (2-space indent,
no trailing newline — verified against production).

🤖 Generated by [robots](https://vyos.io)
… check

- Wrap the CLI entry in try/catch so a missing required input reaches
  core.setFailed instead of a raw stack trace.
- dist-freshness check uses git status --porcelain (catches new
  untracked files under dist/, not only modified tracked ones).
- Kept 422 in the signature-write retry deliberately: a concurrent
  bootstrap create returns 422 (sha wasn't supplied) and the
  refetch+retry path is exactly what recovers it (spec §4.5).

🤖 Generated by [robots](https://vyos.io)
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: d8f0c5b5-01e1-41bb-919d-732d0d86d0d2

📥 Commits

Reviewing files that changed from the base of the PR and between ac773ff and 3190c7f.

⛔ Files ignored due to path filters (1)
  • .github/actions/cla/dist/index.js is excluded by !**/dist/**, !**/dist/**
📒 Files selected for processing (5)
  • .github/actions/cla/src/committers.js
  • .github/actions/cla/src/signatures.js
  • .github/actions/cla/test/committers.test.js
  • .github/actions/cla/test/main.test.js
  • .github/actions/cla/test/signatures.test.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • ansible/ansible (manual)
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/actions/cla/test/committers.test.js
  • .github/actions/cla/test/signatures.test.js
  • .github/actions/cla/src/signatures.js
  • .github/actions/cla/src/committers.js
  • .github/actions/cla/test/main.test.js
📜 Recent review details
🧰 Additional context used
🔍 Remote MCP Context7

Relevant PR review context

  • The action is a Node.js v24 JavaScript action; GitHub Docs show runs.using: 'node24' with a main entry file as the standard setup for this runtime.
  • The PR’s commit collection should be paginated: GitHub Docs say GET /repos/{owner}/{repo}/pulls/{pull_number}/commits supports per_page up to 100, and the endpoint can list up to 250 commits for a PR.
  • The rerun helper matches documented Actions behavior: GitHub Docs include a re-run failed jobs endpoint for a workflow run (POST /actions/runs/{run_id}/rerun-failed-jobs).
  • For file writes, GitHub Docs on the Contents API note updates are done via PUT with base64 content and commit metadata; the prior research also noted 409/422 conflict cases are expected around concurrent updates., [::previous_research::]
  • The PR tests explicitly cover the currently implemented edge cases around:
    • allowlist parsing being trim-safe and case-insensitive,
    • ignoring web-flow and noreply@github.com committers,
    • adopting legacy status comments,
    • retrying signature writes on 409 and 422. [::user_context::]

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added an automated CLA check for pull requests, including status comments and recheck handling.
    • Contributors can now be marked as exempt through an allowlist.
  • Bug Fixes

    • Improved handling of existing CLA comments to update the latest valid comment and remove duplicates.
    • Added support for retrying CLA signature updates when conflicts occur.
  • Tests

    • Expanded coverage for CLA events, comment updates, signature matching, and rerun behavior.

Walkthrough

Adds a GitHub Action for CLA checks with webhook parsing, signature matching and updates, status comment management, rerun triggering, test coverage, and a pull-request CI workflow.

Changes

CLA Action Implementation

Layer / File(s) Summary
Action metadata
.github/actions/cla/action.yml, .github/actions/cla/package.json, .github/actions/cla/.gitignore
Defines the Node 24 action entrypoint, required and optional inputs, package metadata/scripts/dependencies, and ignores node_modules/ in the action workspace.
Constants and event parsing
.github/actions/cla/src/constants.js, .github/actions/cla/src/context.js, .github/actions/cla/test/constants.test.js, .github/actions/cla/test/context.test.js
Adds shared CLA phrases/markers and webhook parsing for pull_request_target and issue_comment, with tests for exact constants and check/sign/recheck/noop routing.
Committers and signatures
.github/actions/cla/src/committers.js, .github/actions/cla/src/signatures.js, .github/actions/cla/test/committers.test.js, .github/actions/cla/test/signatures.test.js
Collects PR commit authors/committers, applies allowlists, reads and matches stored signatures, and appends new signatures with conflict retries and idempotency checks.
Status comment handling
.github/actions/cla/src/comment.js, .github/actions/cla/test/comment.test.js, .github/actions/cla/test/fixtures/legacy-comment.md
Formats CLA status comments and upserts marker or legacy bot comments, including duplicate cleanup and failure handling.
Workflow rerun trigger
.github/actions/cla/src/rerun.js, .github/actions/cla/test/rerun.test.js
Finds the latest prior workflow run for the PR head and reruns failed jobs, with skip and fallback paths covered by tests.
Main orchestration
.github/actions/cla/src/main.js, .github/actions/cla/test/main.test.js
Connects context parsing, committer collection, signature updates, comment upserts, failure handling, and rerun triggering in the action entrypoint.
CI workflow
.github/workflows/action-ci.yml
Runs install, tests, and build-freshness checks for the CLA action on pull requests touching the action files.

Related PRs: None identified.

Suggested labels: ci, github-actions, new-feature

Suggested reviewers: None identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Summarizes the new first-party CLA action replacing archived contributor-assistant.
Description check ✅ Passed Describes the CLA action, tests, and CI additions in .github/actions/cla/ and .github/workflows/action-ci.yml.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch cla-action

Comment @coderabbitai help to get the list of available commands.

@andamasov
andamasov marked this pull request as ready for review July 3, 2026 06:14

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
.github/actions/cla/src/signatures.js (1)

22-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unreachable throw lastError at line 47.

With attempt <= 3 and the retry guard attempt < 3, the third attempt's failure always falls to throw e; inside the catch (line 44) — the loop never exits normally, so throw lastError; after the loop can never execute. Harmless today but confusing for future maintainers reasoning about the retry-limit enforcement.

🧹 Optional cleanup
-  let lastError;
   for (let attempt = 1; attempt <= 3; attempt += 1) {
     const cur = await loadSignatures(octokit, cfg);
     if (cur.entries.some((e) => e.id === entry.id)) return { written: false, reason: 'already-signed' };
     const next = { signedContributors: [...cur.entries, entry] };
     const params = {
       owner: cfg.owner,
       repo: cfg.repo,
       path: cfg.path,
       branch: cfg.branch,
       message: `@${entry.name} has signed the CLA in ${calling.owner}/${calling.repo}#${entry.pullRequestNo}`,
       content: Buffer.from(JSON.stringify(next, null, 2)).toString('base64'),
     };
     if (cur.sha) params.sha = cur.sha;
     try {
       await octokit.rest.repos.createOrUpdateFileContents(params);
       return { written: true };
     } catch (e) {
-      lastError = e;
       if ((e.status === 409 || e.status === 422) && attempt < 3) continue;
       throw e;
     }
   }
-  throw lastError;
 }
🤖 Prompt for 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.

In @.github/actions/cla/src/signatures.js around lines 22 - 48, The final throw
in appendSignature is unreachable because the retry loop always either returns
or throws inside the catch on the last attempt. Simplify the retry flow in
signatures.js by removing the dead post-loop `throw lastError` and keeping the
`octokit.rest.repos.createOrUpdateFileContents` error handling in the existing
`catch` block, with `attempt`/`lastError` only used if you still need retry
state.
.github/actions/cla/src/committers.js (1)

25-35: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Allowlist matching is case-sensitive.

parseAllowlist/filterAllowlisted compare logins with exact-case Set.has. GitHub logins are case-preserving but effectively case-insensitive at signup, so a casing mismatch between the configured allowlist and the API-reported login silently defeats the exemption — the test fixture at .github/actions/cla/test/committers.test.js:58 already has to list both copilot and Copilot to work around this. Normalizing both sides to lower case removes the need for duplicate entries and avoids future misses when a new bot login is added with only one casing.

♻️ Suggested normalization
 function parseAllowlist(raw) {
-  return new Set(String(raw || '').split(',').map((s) => s.trim()).filter(Boolean));
+  return new Set(String(raw || '').split(',').map((s) => s.trim().toLowerCase()).filter(Boolean));
 }

 function filterAllowlisted(accounts, allow) {
   const out = new Map();
   for (const [id, login] of accounts) {
-    if (!allow.has(login)) out.set(id, login);
+    if (!allow.has(login.toLowerCase())) out.set(id, login);
   }
   return out;
 }
🤖 Prompt for 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.

In @.github/actions/cla/src/committers.js around lines 25 - 35, The allowlist
check in parseAllowlist/filterAllowlisted is case-sensitive, so matching GitHub
logins can be missed when casing differs. Normalize allowlist entries and
account logins to a consistent case, ideally lower case, before storing and
comparing them in the Set/Map logic. Update the matching flow in parseAllowlist
and filterAllowlisted so login exemptions work regardless of casing and
duplicate entries like Copilot/copilot are unnecessary.
🤖 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 @.github/actions/cla/src/context.js:
- Around line 8-23: The recheck path in context parsing currently accepts any
exact RECHECK_PHRASE comment, which lets untrusted commenters trigger reruns.
Update context.js in the issue_comment handling to gate the `recheck` action by
trusted actor checks, such as PR author or approved collaborator association,
before returning `{ kind: 'recheck' }`. Make sure main.js only reaches
triggerPrHeadRerun for recheck events that passed this authorization in
context.js.

In @.github/actions/cla/src/signatures.js:
- Around line 1-10: The loadSignatures() helper is assuming repos.getContent
always returns base64-encoded file content, which breaks once the signatures
file exceeds the contents API threshold. Update loadSignatures() to use the raw
media type or the blobs API when fetching the file, and keep the
JSON.parse(Buffer.from(...)) path only for confirmed base64 content. Use the
existing loadSignatures, octokit.rest.repos.getContent, and
res.data.content/res.data.sha flow to locate the fix, and make the non-base64
case fail explicitly instead of silently parsing bad data.

---

Nitpick comments:
In @.github/actions/cla/src/committers.js:
- Around line 25-35: The allowlist check in parseAllowlist/filterAllowlisted is
case-sensitive, so matching GitHub logins can be missed when casing differs.
Normalize allowlist entries and account logins to a consistent case, ideally
lower case, before storing and comparing them in the Set/Map logic. Update the
matching flow in parseAllowlist and filterAllowlisted so login exemptions work
regardless of casing and duplicate entries like Copilot/copilot are unnecessary.

In @.github/actions/cla/src/signatures.js:
- Around line 22-48: The final throw in appendSignature is unreachable because
the retry loop always either returns or throws inside the catch on the last
attempt. Simplify the retry flow in signatures.js by removing the dead post-loop
`throw lastError` and keeping the
`octokit.rest.repos.createOrUpdateFileContents` error handling in the existing
`catch` block, with `attempt`/`lastError` only used if you still need retry
state.
🪄 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: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 693ad824-807b-43c6-b1b0-e146c3406d46

📥 Commits

Reviewing files that changed from the base of the PR and between 7745c7c and 8380c34.

⛔ Files ignored due to path filters (3)
  • .github/actions/cla/dist/index.js is excluded by !**/dist/**, !**/dist/**
  • .github/actions/cla/dist/licenses.txt is excluded by !**/dist/**, !**/dist/**
  • .github/actions/cla/package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (19)
  • .github/actions/cla/.gitignore
  • .github/actions/cla/action.yml
  • .github/actions/cla/package.json
  • .github/actions/cla/src/comment.js
  • .github/actions/cla/src/committers.js
  • .github/actions/cla/src/constants.js
  • .github/actions/cla/src/context.js
  • .github/actions/cla/src/main.js
  • .github/actions/cla/src/rerun.js
  • .github/actions/cla/src/signatures.js
  • .github/actions/cla/test/comment.test.js
  • .github/actions/cla/test/committers.test.js
  • .github/actions/cla/test/constants.test.js
  • .github/actions/cla/test/context.test.js
  • .github/actions/cla/test/fixtures/legacy-comment.md
  • .github/actions/cla/test/main.test.js
  • .github/actions/cla/test/rerun.test.js
  • .github/actions/cla/test/signatures.test.js
  • .github/workflows/action-ci.yml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • ansible/ansible (manual)
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
.github/workflows/**

⚙️ CodeRabbit configuration file

.github/workflows/**: Rollout 1c (Phorge T8943, 2026-05-30) renamed default branches fleet-wide: release-train repos current -> rolling; vyos/.github and other non-release-train repos current -> production. (1) Reusable-workflow refs of the form vyos/.github/.github/workflows/<name>.yml@production are CORRECT and canonical. Do NOT suggest changing @production to @current: current is the OLD name, retained only as a temporary bake-period alias and slated for removal. Any AGENTS.md still saying "reusables pinned to @current" or "current (rolling)" is stale post-1c and must not drive review suggestions. (2) In the mirror caller pr-mirror-repo-sync.yml, permissions: contents: read is INTENTIONAL: the central reusable workflow performs all push/PR writes with the vyos-bot GitHub App installation token (minted via the get-token action), not the inherited GITHUB_TOKEN. Do NOT suggest broadening the caller's permissions to contents: write / pull-requests: write.

Files:

  • .github/workflows/action-ci.yml
🪛 ast-grep (0.44.0)
.github/actions/cla/test/comment.test.js

[warning] 7-7: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(path.join(__dirname, 'fixtures', 'legacy-comment.md'), 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename)

🔍 Remote MCP

Relevant docs-backed context:

  • GitHub metadata syntax explicitly supports JavaScript actions with runs.using: 'node24', and runs.main is the file executed by that runtime. (docs.github.com)
  • The PR commits endpoint is GET /repos/{owner}/{repo}/pulls/{pull_number}/commits; per_page is capped at 100, so pagination is needed for large PRs. The example response includes author/committer objects with login and id fields. (docs.github.com)
  • GitHub’s Contents API Create or update file contents requires sha when updating an existing file, uses base64 content, defaults branch to the repo default branch, and can return 409 or 422; GitHub also warns that parallel create/update and delete requests conflict. (docs.github.com)
  • Workflow runs can be re-run, including failed jobs, up to 30 days after the original run; the rerun-failed-jobs endpoint requires run_id and returns 201 Created. (docs.github.com)
  • GitHub’s JavaScript action guide says to install @actions/core and @actions/github, and not to commit node_modules/. (docs.github.com)
🔇 Additional comments (24)
.github/actions/cla/action.yml (2)

27-29: Summary says "composite Action"; manifest defines a JavaScript action.

runs.using: 'node24' with runs.main: 'dist/index.js' is a JavaScript action, not a composite action (runs.using: 'composite' + steps). The AI-generated summary's description doesn't match the actual manifest shape.


1-30: LGTM!

.github/actions/cla/package.json (1)

1-19: LGTM!

.github/actions/cla/.gitignore (1)

1-2: LGTM!

.github/actions/cla/src/constants.js (1)

1-8: LGTM!

.github/actions/cla/test/constants.test.js (1)

1-12: LGTM!

.github/actions/cla/src/context.js (1)

3-25: LGTM!

.github/actions/cla/test/context.test.js (1)

1-53: LGTM!

.github/workflows/action-ci.yml (2)

1-21: LGTM!

Also applies to: 28-38


22-27: 🩺 Stability & Availability

No action needed. .github/actions/cla/package-lock.json is present, so npm ci and cache-dependency-path point at a real lockfile.

			> Likely an incorrect or invalid review comment.
.github/actions/cla/src/committers.js (1)

1-23: LGTM!

.github/actions/cla/test/committers.test.js (1)

1-71: LGTM!

.github/actions/cla/src/signatures.js (1)

12-20: LGTM!

.github/actions/cla/test/signatures.test.js (1)

1-99: LGTM!

.github/actions/cla/src/comment.js (1)

36-83: Marker/legacy dedup and TOCTOU cleanup logic looks correct.

Bot-authorship check on Line 40 correctly guards against spoofed markers; newest-marked-wins with duplicate cleanup (Lines 47-49, 75-81) and legacy adoption fallback (Lines 50-55) match the documented spec (§4.1-§4.4) and are covered by the test suite. Non-404 errors on delete are surfaced via warn rather than swallowed (Line 79), and 404s on both update/delete are treated as already-resolved states.

One edge case: if updateComment throws a non-404 error (Line 62-63), the function re-throws before reaching the duplicate-cleanup loop (Lines 75-81), so stale duplicates aren't pruned on that run. This is self-healing on the next successful run, so not flagging as a blocking issue.

.github/actions/cla/test/comment.test.js (1)

1-133: LGTM!

.github/actions/cla/test/fixtures/legacy-comment.md (1)

1-1: LGTM!

.github/actions/cla/src/rerun.js (2)

4-6: 🎯 Functional Correctness

Confirm event: 'pull_request_target' filter matches the reusable workflow's actual trigger once wired in.

Octokit method names/params (getWorkflowRun, listWorkflowRuns with workflow_id/event/head_sha, reRunWorkflowFailedJobs with fallback to reRunWorkflow) match the documented REST API surface. However, candidate lookup is hardcoded to event: 'pull_request_target' (Line 5), coupling correctness to cla-reusable.yml's trigger config for the CLA check job — that file is intentionally unchanged/out of scope for this PR. If the workflow that ultimately calls this action triggers the CLA check job under a different event name (or via a reusable-workflow indirection that changes the recorded event), no candidate run will ever be found and sign/recheck unblock reruns will silently no-op (status: 'skipped').

Worth a final check against cla-reusable.yml before the planned workflow swap.


1-23: LGTM on the rest of the implementation — clean fallback and error-containment logic (never throws, matches test coverage for 409 fallback and unexpected API exceptions).

.github/actions/cla/test/rerun.test.js (1)

1-79: LGTM!

.github/actions/cla/src/main.js (3)

67-68: 🎯 Functional Correctness

Confirm repoOctokit's token carries actions: write and pull-requests: write once wired into the real workflow.

triggerPrHeadRerun (called here with repoOctokit) invokes reRunWorkflowFailedJobs/reRunWorkflow, and upsertStatusComment invokes issues.createComment/updateComment/deleteComment — both require write-scoped permissions on the token (actions: write for reruns per the REST API docs, pull-requests/issues: write for comments). Since cla-reusable.yml isn't part of this PR and its permissions: block isn't visible here, this can't be confirmed from the provided files. If the reusable workflow only grants contents: read (as intentionally done for the mirror-sync workflow per repo convention), the sign/recheck rerun and comment-posting paths will silently degrade to warnings/status:'failed' (Lines 53-55, 68) rather than hard-failing — worth validating during the canary end-to-end pass mentioned in the PR objectives.


78-79: 📐 Maintainability & Code Quality | 💤 Low value

Verify GITHUB_TOKEN sourcing convention matches action.yml inputs.

ghToken is read directly from process.env.GITHUB_TOKEN rather than via core.getInput(...), while signature-token (Line 89) uses the input mechanism. This is a valid pattern if the calling workflow step sets GITHUB_TOKEN as an env var (matching the archived contributor-assistant action's convention), but action.yml's declared inputs aren't in this review cohort to confirm consistency.


1-70: Orchestration logic is sound.

Context-kind branching (noop/check/sign/recheck), sign-then-reload sequencing (Lines 33-45), fail/pass determination (Line 47), non-fatal comment-upsert handling (Lines 49-55), and scoped rerun triggering only for sign/recheck (Lines 66-69) all match the documented spec and are exercised by the accompanying test suite (all-signed no-comment, unsigned-fails, sign-flow write+rerun, closed/noop, comment-failure resilience).

.github/actions/cla/test/main.test.js (1)

1-198: LGTM!

Comment thread .github/actions/cla/src/context.js
Comment thread .github/actions/cla/src/signatures.js
@andamasov

Copy link
Copy Markdown
Member Author

Adversarial review — 8380c34 — single-provider (Codex) with logged operator waiver — agy unavailable

Provider status: trusted PR (org member) → normal provider set is Codex + agy in parallel. agy failed twice (primary Gemini 3.1 Pro (High) + fallback Gemini 3.5 Flash (High), both backend timeouts); per the agy-unavailable policy the operator granted an explicit waiver to proceed Codex-solo. Recorded here as the auditable waiver note.

Codex verdict: APPROVE. Zero critical issues. Independently verified the 52-test suite passes. Findings:

  1. [single-source: Codex, recommendation] .github/actions/cla/src/signatures.js:43 — the 409/422 retry contract had explicit test coverage only for 409; 422 (concurrent bootstrap create) is part of the settled concurrency contract and deserved its own test.

Disposition: finding 1 fixed in ac773ff (explicit 422 refetch-retry test; suite now 53/53). The only delta between the reviewed head 8380c34 and the current head ac773ff is that test file.


Each finding must receive a fix commit OR a pushback reply in a reply to this comment before merge. See /audit-pr-threads for resolution mechanics.

… case-insensitive allowlist, dead-code cleanup

- loadSignatures fails with an explicit error if the contents API stops
  inlining base64 (file-size threshold) instead of a confusing parse
  crash — the raw/blob-API switch stays a future change (file is ~16 KB).
- Allowlist matching normalized to lower case (GitHub logins are
  case-insensitively unique; the live list's copilot/Copilot duplication
  was a workaround for case-sensitive matching).
- Removed unreachable throw after the append retry loop.

🤖 Generated by [robots](https://vyos.io)
@andamasov

Copy link
Copy Markdown
Member Author

@coderabbitai — disposition of the two 🧹 nitpicks from the review body (no threads to reply in), both addressed in 3190c7f:

  1. Unreachable throw lastError (signatures.js) — fixed: dead post-loop throw and lastError removed; a comment now documents that the last attempt always throws inside the catch.
  2. Case-sensitive allowlist (committers.js) — fixed: both sides normalized to lower case (GitHub logins are case-insensitively unique; the live list's copilot/Copilot duplication was exactly the workaround you'd predict). New unit test covers a case-mismatched exemption; the live-allowlist fixture test now asserts the collapsed set size.

Same commit also carries the loud large-file guard from the inline thread. Suite: 54/54.

@andamasov

Copy link
Copy Markdown
Member Author

Head-map update for the adversarial-review record above: reviewed head 8380c34ac773ff (Codex rec: 422-retry test) → 3190c7f (GitHub-side CodeRabbit round: loud large-file guard, case-insensitive allowlist, dead-code cleanup — see dispositions above). All deltas are gate-driven fixes; suite 54/54, CI green on each push.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
git log --oneline -5
git show 3190c7f --stat 2>/dev/null || echo "commit not found locally"
echo "---signatures.js---"
sed -n '1,60p' .github/actions/cla/src/signatures.js
echo "---committers.js---"
sed -n '1,50p' .github/actions/cla/src/committers.js

Length of output: 5964


@andamasov — verified 3190c7f. Both nitpicks are correctly resolved:

  1. .github/actions/cla/src/signatures.js — the post-loop throw lastError is gone; the retry loop now relies on the catch block re-throwing on the final attempt (or non-409/422 error), with a comment documenting the control flow. Correct — the loop can no longer fall through without returning or throwing.
  2. .github/actions/cla/src/committers.jsparseAllowlist and filterAllowlisted both normalize via .toLowerCase() now, so copilot/Copilot collapse to one allowlist entry. Matches GitHub's case-insensitive login uniqueness.

Also noted the added loadSignatures guard against non-inline base64 content (large-file case) — good defensive addition, and consistent with the "loud large-file guard" you mentioned.

54/54 noted. No further action needed on these two items.

@evgsentrium evgsentrium left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Replacement of the archived contributor-assistant

@evgsentrium
evgsentrium merged commit 243804f into production Jul 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants