Repository navigation
fix(contributor-check): vendor AGT scripts and fail on execution faults - #46
Merged
imran-siddique merged 4 commits intoSep 30, 2026
Conversation
Refs agentrust-io#27 Signed-off-by: Mayur Agnihotri mayur.agnihotri0021@gmail.com
Refs agentrust-io#27 Signed-off-by: Mayur Agnihotri <mayur.agnihotri0021@gmail.com>
Refs agentrust-io#27 Signed-off-by: Mayur Agnihotri <mayur.agnihotri0021@gmail.com>
Refs agentrust-io#27 Signed-off-by: Mayur Agnihotri <mayur.agnihotri0021@gmail.com>
|
❔ Contributor Check: UNKNOWN
Automated check by AgenTrust Contributor Check. |
Member
Author
|
@imran-siddique CI is green: tests and vendor-integrity both pass. The Policy check is the maintainer-approval gate and stays red until review. Worth noting for the thread: this PR was itself labelled needs-review:UNKNOWN by the action on main, with Profile: UNKNOWN and Credential: LOW. That is the same signature as the three rows in the issue table. Whether that particular run hit the transient path or genuinely could not determine a profile is not visible from the outside, and that is the distinction this change is about, because today both produce the same label. |
imran-siddique
approved these changes
Sep 30, 2026
imran-siddique
pushed a commit
that referenced
this pull request
Oct 2, 2026
…bound (#49) `_api` already looped three times, but only a 403 continued the loop. A 5xx raised on the first attempt, and `URLError` was not caught at all, so the `timeout=15` socket timeout, a DNS failure, a reset or a TLS abort propagated straight out of the loop. `URLError` was not even imported. `_count_maintainer_merged` alone walks up to ten PR-detail calls for one candidate, paced half a second apart, and the run makes more calls besides. One blip anywhere in that walk ended the whole check. Since #46 that no longer mislabels anyone, which was the `needs-review:UNKNOWN` symptom in #27; it fails the action instead. But a transient blip still ends a check a retry would have passed. The existing loop now covers the transient cases, with full-jitter exponential backoff capped at 60s, and the bound stays at three attempts: - 404 returns None on the first attempt and is never retried. It is an answer, not a failure. Moved above the 403 branch for readability; the codes are distinct, so behaviour is unchanged. - 403 with Retry-After is honoured, clamped to 5-60s, as before. If it outlasts the bound it raises, and now says it was a rate limit. - 5xx and URLError back off, then raise as themselves. - Every other status raises on the first attempt, unchanged. Each exhausted path prints a line naming its own cause before re-raising. `_run_check` in contributor_check_action.py takes the last stderr line as the CheckExecutionError detail, and upstream's 403 path raised silently, so an exhausted rate limit used to reach a maintainer as a bare `exited 1` with nothing to say whether to wait or re-run. This is a second declared local modification to the vendored copy, so contributor_check.py moves out of the checksum table and the three remaining vendored files stay hash-pinned in CI. vendor/agt/README.md records both modifications and drops the upstream sync framing: AGT is not being invested in and this copy is owned here. 24 tests pass. The eight added cover both outcomes of each transient path, the 404 short-circuit, the attempt bound on every exhausted path, and the backoff cap. Each was checked against a mutated source to confirm it fails when the behaviour it names is removed. Refs: #27 Signed-off-by: Mayur021 <mayur.agnihotri0021@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
An infrastructure fault was being reported as a contributor-risk level.
_run_checkcalledsubprocess.runwithout readingreturncode, went straight tojson.loads(result.stdout), and the bareexcept Exceptionturned the resulting error into"UNKNOWN". BecauseRISK_ORDERis deliberately fail-closed,UNKNOWNoutranksLOW, so a check that could not run labelled established contributors as more suspicious than genuinely low-risk ones. That is the five false flags in #27.This is item 2 of the issue. It does not close #27: item 1, the bounded retry around the profile lookup, still belongs in
_apiinsidecontributor_check.py. Vendoring makes that easier rather than harder, because the retry can now be backported here instead of waiting for an upstream reconciliation.The change
_run_checkreads the return code. A check that could not be executed raisesCheckExecutionError,mainexits non-zero with an::errorannotation, and no comment and no label are applied.UNKNOWNkeeps its upstream meaning of a check that ran and could not determine an answer, and still labels.Before, at upstream
359a6b8:After:
A check that exits 0 reporting
{"risk": "UNKNOWN"}returnsUNKNOWNin both.Vendoring
The scripts now live in
.github/actions/contributor-check/vendor/agt/, copied frommicrosoft/agent-governance-toolkitat359a6b8cf453f95d6bc9caf932057e1e78ccffd9, MIT, licence headers intact.action.ymlno longer checks out that repository at runtime.vendor/agt/README.mdrecords the source commit and a SHA-256 per file, and a CI job verifies those checksums, so a vendored file drifting from upstream fails the build rather than going unnoticed.Five files, not the two named in the issue, and this is the part worth a second opinion.
contributor_check_action.pyresolves the checks it runs as siblings of itself throughPath(__file__).resolve().parent. The action runsprofile,credentialby default andprofile,credential,clusteron dispatch, socredential_audit.pyis invoked on every run andcluster_detect.pyon some.contributor_check.pyreadscontributor_check_allowlist.jsonfrom its own directory and silently grants no exemptions if it is absent. Vendoring only two would leave those siblings missing, and with the return-code change that is a hard failure on every run instead of a silentUNKNOWN. If you would rather keep a narrower vendor and resolve the rest some other way, say so and I will rework it.Tests
.github/actions/contributor-check/tests/test_contributor_check_action.py, 14 tests, run by a new workflow on any change under the action directory.The regression case is the scripts-only shape: a check that exits non-zero with empty stdout, which is what a missing sibling produces and what a
sparse-checkout: scriptsproduced against an upstream shim importing a package outsidescripts/. It assertsCheckExecutionErrorrather thanUNKNOWN.The rest cover a missing script, a zero exit with no output, a genuine
UNKNOWNsurviving unchanged, computed levels passing through,NONEstill normalising toLOW, the output file still being written on failure, the fail-closed ordering itself being untouched, every invokable sibling being present, licence headers intact, and the allowlist parsing and shipping empty.Checked that the tests are load-bearing: restoring the unmodified upstream entrypoint makes 5 of the 14 fail.
Not changed
contributor_check.py,credential_audit.py,cluster_detect.pyand the allowlist are byte-identical to upstream. The risk ordering, the allowlist behaviour and the comment and label paths are untouched. Once this lands, the three issues in the original report are worth re-running to confirm they resolve to a real level.