ci: gate worker-mode state leaks with Igor - #80
Merged
Conversation
Igor reports shared mutable state, which is not the same thing as a leak. The four values it finds here are shared on purpose — Guzzle clients and their connection pools, the derived callback paths, the authenticator's logger, and Symfony's own lazy init of the bundle extension — and igor-baseline.json records each with a written reason. What the gate protects is the difference: state that appears without one. That is the case worth catching. The provider memoization removed in the PKCE work was exactly this shape, and nothing but review would have stopped it coming back. IGOR_VERSION pins the binary the composer bootstrapper fetches, in the Taskfile and the workflow. Igor is pre-1.0 and its rules move between releases, which would move the baseline underneath us.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #80 +/- ##
==========================================
Coverage 99.52% 99.52%
Complexity 205 205
==========================================
Files 15 15
Lines 834 834
==========================================
Hits 830 830
Misses 4 4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Adds Igor as a CI gate for the worker-mode contract documented in #79.
Changes
igor-php/igor-phpas a dev dependency, run through the existingphpfpmcontainer like every other tool here.igor.json— scopes the scan to the bundle's own code and points at the baseline.igor-baseline.json— the four values this bundle shares on purpose, each with a written reason.task analyze:worker,analyze:worker:check,analyze:worker:baseline;analyze:workerjoinspr:actions.Worker mode (Igor)CI job.What it actually gates
Igor reports shared mutable state, which is not the same thing as a leak. Every finding here is deliberate:
$httpClients$redirectUriPaths$loggerBundle::getContainerExtension()So the gate is not "is there shared state" — the answer is yes, four times, on purpose. It is "has shared state appeared that nobody has justified in writing". The baseline format carries a
reasonfield per entry and ships withTODO: Explain why..., so an unjustified addition is visible in review as well as failing the build.That case is worth catching. The provider memoization removed in #77 was exactly this shape — mutable state on a shared service, harmless until a process outlives a request — and nothing but review would have stopped it coming back.
Verified
Then with a property mutation planted in
CliLoginHelper:Reverted, back to exit 0.
analyze:worker:checkalso passes, confirming no baseline entry has gone stale.Decisions worth reviewing
IGOR_VERSIONis set inTaskfile.ymland.github/workflows/php.yaml; they have to be bumped together. I considered a single source but every other version in this repo is pinned per-consumer too, and a workflow cannot read Taskfile vars without extra machinery.markdownlintandprettier, Igor publishes no image — its goreleaser config has nodockers:section. The composer package is a bootstrapper that downloads the Go binary for the current platform, sovendor/bin/igor-phpruns inside the existingphpfpmcontainer. That keeps CLAUDE.md's "never invoke tooling on the host" rule intact with no new image to maintain. The download needs network on first run; it caches undervendor/, which is already gitignored.--no-agent. Igor's richer mode reads a compiled Symfony container. This is a bundle, so there is no application container to read — only the test kernel's, which would be analysing the fixtures rather than the bundle.--no-agentdoes a static scan instead.igor.json, not a CLI path. Unscoped,igor-php .walksvendor/— 717,028 files, about two minutes, 2,305 "project" findings. Withignore_vendorsand theexcludelist it is 24 files in under two seconds.test:matrix. It is a static scan; running it six times across the PHP matrix would tell us the same thing six times.Note
analyze:workeris now part oftask pr:actions, so a local pre-PR run covers it.