Contributing
Thanks for helping out. This project has one job: tell a developer, before they switch to a persistent worker, which parts of their code will carry state from one request into the next — and be right often enough to be trusted.
Getting set up
Section titled “Getting set up”git clone https://github.com/goktugcy/worker-safety.gitcd worker-safetycomposer installcomposer ci # lint + static analysis + testsIndividual steps:
composer test # PHPUnitcomposer analyse # PHPStan at max levelcomposer lint # PHP-CS-Fixer, no changes writtencomposer lint:fix # PHP-CS-Fixer, writes changesAll three must be green before a pull request can be merged. PHPStan runs at
max with no baseline, and there is no ignore list — if a change needs one,
that is worth discussing in the pull request first.
The false-positive rule
Section titled “The false-positive rule”A scanner that cries wolf gets uninstalled. Concretely:
- “I saw a static, therefore it is a bug” is not acceptable. A finding must
be able to explain, in the
detailstext, why this code can leak state. - Prefer a lower severity over a missing distinction. If a rule cannot tell a dangerous case from a benign one, report the uncertain case at a lower severity and say why in the message.
- Every rule needs a
safe.phpfixture that must produce zero findings, not just apositive.phpthat produces some.
If you are unsure whether something is a real risk, open an issue with the code sample before writing the rule.
Adding a rule
Section titled “Adding a rule”- Pick the next free
WSxxxid and add it toWorkerSafety\Rule\RuleId. - Add the rule class:
- framework-independent →
src/Rule/BuiltIn/ - framework-specific →
src/Framework/<Framework>/Rule/, withrequiresFrameworkset in itsRuleDefinition.
- framework-independent →
- Extend
AbstractRuleand implementdefinition()plus whichever lifecycle hooks you need:nodeTypes()+enterNode()— per-node checks.beginFile()/finishFile()— per-file aggregation, e.g. reporting one finding per global variable instead of one per write.finishProject()— anything that needs the whole project, reading the semantic model fromProjectContext::index(). This is how a rule can correlate a container binding in one file with a class declared in another while the project is still parsed only once.
- Register it in
WorkerSafety\Rule\RuleRegistryFactory(or in the framework adapter’srules()). - Add
tests/Fixtures/WSxxx/{positive,safe,edge}.phpand a test that asserts findings and severities throughAnalyzerHarness. - Document the rule in the README table.
Rules must not need their own AST pass. If you find yourself wanting one, the
information probably belongs in the semantic index
(src/Ast/Index/, populated by IndexCollectingVisitor) so every rule can use it.
Hard constraints
Section titled “Hard constraints”- Never execute, include, autoload or evaluate analyzed code. The scanner reads source into an AST and nothing else. This is the guarantee that makes it safe to run against untrusted repositories, and it is covered by a test.
- No framework dependency in the core.
composer.jsonrequiresnikic/php-parserand two small Symfony components. Laravel and Symfony support lives behindFrameworkAdapter. - The
Findingmodel stays free of AST types. A future runtime analyzer will emit the same objects into the same reporters. - Target PHP 8.2: no typed class constants, no 8.3+ syntax.
Commit and pull request hygiene
Section titled “Commit and pull request hygiene”-
One logical change per pull request.
-
Update
CHANGELOG.mdunder## [Unreleased]. -
If you change the configuration template, regenerate the example file:
Terminal window php -r 'require "vendor/autoload.php"; file_put_contents("worker-safety.example.yaml", WorkerSafety\Config\ConfigurationTemplate::render());'A test fails if the two drift apart.
Reporting a false positive
Section titled “Reporting a false positive”Open an issue with:
- The smallest code sample that triggers it.
- The finding as printed by
vendor/bin/worker-safety scan --no-ansi. - Why the code is actually safe under a worker.
False-positive reports are the most valuable issues this project can receive.