ci(e2e): add local GitHub emulator driver for scm.Driver tests - #4089
ci(e2e): add local GitHub emulator driver for scm.Driver tests#4089waynesun09 wants to merge 1 commit into
Conversation
|
🤖 Finished Review · ✅ Success · Started 2:33 AM UTC · Completed 2:43 AM UTC |
PR Summary by Qodoci(e2e): add local emulate-backed SCM driver for behaviour tests
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
1.
|
| This package deliberately does **not** follow the "Adding an SCM driver" checklist above — it | ||
| is not registered as a `BEHAVIOUR_SCM` value and is not wired into `suite_test.go`. emulate's | ||
| Actions endpoints are REST record-level only (list/get/dispatch/cancel/logs as data); it does | ||
| not execute real workflow YAML. So it can never satisfy `ci.Driver` for scenarios like | ||
| `triage.feature` that assert on real agent execution — pairing it with `BEHAVIOUR_CI=githubactions` | ||
| would silently produce a suite that can never observe what it's supposed to test. Import it |
There was a problem hiding this comment.
2. Architecture rationale stated inline 📜 Skill insight ⚙ Maintainability
The guide explains architectural constraints/behavioral limitations of the emulator driver inline but does not link to an ADR/spec/docs/architecture.md for that context. This violates the requirement to link to architectural references instead of restating them in guides.
Agent Prompt
## Issue description
This guide includes architectural reasoning about why the local emulator cannot satisfy `ci.Driver`, but it does not link to an architectural reference (ADR/spec/`docs/architecture.md`).
## Issue Context
The newly added `scm/emulate` section describes emulator limitations and test-layer intent. Per docs standards, guides should link to architectural references rather than restating them inline.
## Fix Focus Areas
- docs/guides/dev/behaviour-drivers.md[55-60]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
waynesun09
left a comment
There was a problem hiding this comment.
Review
Verdict: request-changes. (Posted as a comment, not a formal GitHub review state — GitHub does not allow requesting changes on your own PR, and this review is running under the PR author's own credentials rather than a separate bot identity.)
Findings
High
- [protected-path]
.github/workflows/scm-emulate.yml— This PR adds a new file under.github/, a protected path per this repo's review policy, and has no linked issue. Human approval is always required for protected-path changes; with no linked issue (only a PR-body reference to ADR 0052 and issue #73, neither of which specifically authorizes this workflow — ADR 0052 calls the underlying Layer 2 testing gap "an open opportunity," not an approved plan, and #73 is about agent-prompt/skill regression evals, not SCM driver infra), this is insufficient context per policy.
Remediation: File or link an issue that authorizes this CI workflow addition (and ideally scopes the whole package — see the related process finding below), or get explicit maintainer sign-off before merging.
Low
-
[api-contract]
e2e/behaviour/drivers/scm/emulate/emulate.go:129—Close()callsProcess.Kill()then returnscmd.Wait(), which returns a non-nil*exec.ExitError("signal: killed") on every clean shutdown since the process was terminated by our own signal. The only caller (TestMain) discards the error, so it's latent today, butClose()is exported and documented as the normal shutdown API — a future caller checking the error will fail spuriously on every successful teardown.
Remediation: Treat a signal-kill exit as success (ignoreWait()'s error, or check thatProcessStatereflects the signal we sent) soClose()only surfaces genuine failures. -
[resource-leak]
e2e/behaviour/drivers/scm/emulate/emulate.go:97-101— ThewaitHealthyfailure path inStartcallsProcess.Kill()and removes the seed file but never callscmd.Wait(), unlikeClose(). This leaks the stderr pipe fd and leaves an un-reaped child for every failedStart(e.g. a slow or unhealthy emulator).
Remediation: Callcmd.Wait()(ignoring its error) afterKill()in this path too, mirroringClose(). -
[edge-case]
e2e/behaviour/drivers/scm/emulate/emulate_test.go:39—TestMain'scontext.WithTimeout(30s)drives both the startup health-check and (viaexec.CommandContextinStart) the subprocess's entire lifetime, since it's the samectx. Harmless with today's two sub-second tests, but as more tests are added to this binary (the docs explicitly invite a future dispatch-routing test), the 30s cap will silently kill the emulator mid-run.
Remediation: Usecontext.Background()(or similar) for the subprocess lifetime, and a separate short-lived context only for the startup health-check loop. -
[injection]
e2e/behaviour/drivers/scm/emulate/emulate.go:77—npx --yes emulate@0.8.0fetches and executes an unscoped npm package on everypull_requestrun (including fork PRs). The version is pinned but not integrity/hash-pinned; blast radius is limited by the job's read-only token and lack of secrets, but a compromised publish under that name/version would still run arbitrary code on the runner.
Remediation: Pin by integrity hash (e.g. install from a committed lockfile withnpm ciinstead ofnpx --yes), or otherwise verify package integrity before execution. -
[process]
e2e/behaviour/drivers/scm/emulate/emulate.go— This is a sizeable standalone addition (5 files, ~430 lines) whose only consumer in this PR is its own test; it's deliberately not wired intosuite_test.goorBEHAVIOUR_SCM. The stated future consumers (a dispatch-routing test,eval/fixtures) don't exist yet. Worth an issue that scopes this package's intended near-term use, both to close this gap and to satisfy the protected-path finding above.
Remediation: File a scoping issue and link it, or get explicit maintainer sign-off that this is intentionally speculative infrastructure.
Info
- [race-condition]
e2e/behaviour/drivers/scm/emulate/emulate.go:159—freePort()'s listen-then-close-then-let-subprocess-bind pattern has a standard TOCTOU race; low impact for a single serial test binary today. - [permission-reduction]
.github/workflows/scm-emulate.yml:33—permissions: contents: readis correctly least-privilege for this job; no action needed. - [secret-exposure]
e2e/behaviour/drivers/scm/emulate/seed.go:13— The//nolint:gosec-annotated token constant is verified to never authenticate against anything but the local emulator; not a real secret. - [architecture-fit]
docs/guides/dev/behaviour-drivers.md:55— The deliberate deviation from the "Adding an SCM driver" checklist is well-reasoned and documented; not a concern.
ReviewClean, well-documented addition of a local GitHub emulator driver for FindingsHigh
Low
Resolved from prior review
Previous runReviewFindingsHigh
Low
Previous runReview — commentClean, well-documented addition of a local GitHub emulator driver for scm.Driver tests. The package reuses the existing FindingsMedium
Low
Overall this is a well-scoped, well-documented PR. The medium finding (Close error handling) is the only item worth addressing before merge; the low findings are suggestions for hardening. Labels: PR adds e2e test driver infrastructure with a new CI workflow Previous runReviewFindingsHigh
Low
Previous run (2)Review — commentClean, well-documented addition of a local GitHub emulator driver for scm.Driver tests. The package reuses the existing FindingsMedium
Low
Overall this is a well-scoped, well-documented PR. The medium finding (Close error handling) is the only item worth addressing before merge; the low findings are suggestions for hardening. Labels: PR adds e2e test driver infrastructure with a new CI workflow |
68834f5 to
a969069
Compare
|
🤖 Finished Review · ✅ Success · Started 2:52 AM UTC · Completed 3:09 AM UTC |
a969069 to
c66eeb3
Compare
|
🤖 Review · |
c66eeb3 to
feffa32
Compare
|
🤖 Review · |
Adds e2e/behaviour/drivers/scm/emulate, a scm.Driver implementation backed by a locally spawned vercel-labs/emulate GitHub instance instead of live GitHub — no pool org, no mint, no secrets. Reuses scm/github's driver unmodified by pointing forge/github.LiveClient at the emulator via WithBaseURL. Standalone by design: not registered as a BEHAVIOUR_SCM value or wired into suite_test.go, since emulate's Actions endpoints are record-level only and can never satisfy ci.Driver for scenarios that assert on real Actions execution. Adds a secret-free CI job (scm-emulate.yml) that runs on plain pull_request, safe for fork PRs since it needs no gate. Assisted-by: Claude Signed-off-by: Wayne Sun <gsun@redhat.com>
feffa32 to
ea15167
Compare
|
🤖 Finished Review · ✅ Success · Started 12:31 PM UTC · Completed 12:45 PM UTC |
|
Closing — no current or near-term consumer for this driver, and every forward integration path it was meant to enable turned out to be solved elsewhere or unworkable:
The driver itself works correctly and surfaced real value along the way: three real bugs in this package ( Not merging speculative test infrastructure with no consumer. Happy to revisit if a concrete task ever needs local GitHub-API-level testing. |
|
🤖 Finished Retro · ✅ Success · Started 1:07 PM UTC · Completed 1:16 PM UTC |
|
PR #4089 added a local GitHub emulator driver for scm.Driver tests (~430 lines, 5 files). The review agent ran 4 times (2 successful, 2 correctly cancelled on intermediate force-pushes), producing high-quality technical reviews that identified 3 real bugs (Close() error handling, resource leak on startup failure, context-timeout coupling). The author fixed all bugs across iterations. However, the PR was ultimately closed unmerged by the author, who concluded that no current or near-term consumer exists for the driver — every integration path it was meant to enable was either already solved elsewhere or architecturally incompatible. The review agent never flagged this fundamental strategic concern despite noting the lack of a linked issue and the speculative nature of the infrastructure. This is a known gap tracked by #849 (strategic fitness evaluation). Additionally, the first review run submitted a formal GitHub review under the PR author's own identity instead of the bot identity — a known issue tracked by #2990. Proposals filed
|
Summary
Adds a
scm.Driverimplementation backed by a locally spawnedvercel-labs/emulateGitHub instance, for tests that only need SCM-level state (issues, labels, comments) — no live GitHub org, no mint, no secrets. Standalone by design: not registered as aBEHAVIOUR_SCMvalue, since emulate's Actions endpoints are record-level only and can never back a realci.Driver.Related Issue
None filed — follow-up on the Layer-2 (mocked-external-dependency) testing gap named in ADR 0052 and loosely tracked under #73.
Changes
e2e/behaviour/drivers/scm/emulate/:Instance/Start/Closespawn a version-pinnednpx emulate@0.8.0subprocess, health-check it via/rate_limit, and wireforge/github.LiveClientat its base URL viaWithBaseURL— reuses the existingscm/githubdriver unmodified..github/workflows/scm-emulate.yml: new secret-free CI job on plainpull_request(nogatedependency, safe for fork PRs), runsgo test -tags behaviourscoped to this package only.docs/guides/dev/behaviour-drivers.md: documents the package and explains why it deliberately does not follow the "Adding an SCM driver" checklist (CI-driver mismatch).Testing
make lintpasses — verified go-fmt, go-vet, pinact (SHA-pin check), and actionlint individually against the changed files (no golangci-lint step in this repo's CI)emulate_test.goexercises create issue → add label → read back → add comment → close, against a real spawned emulator instance; passes locally in under a secondChecklist
!for breaking changes)