Skip to content

Avoid reusing mutable Symfony Finder instances from dependency injection #90

@coisa

Description

@coisa

Problem

Several services receive a shared Symfony\Component\Finder\Finder instance from dependency injection and then mutate it with calls such as files(), directories(), in(), name(), and depth(). Finder is a mutable iterator builder, so reusing the injected instance can leak criteria between consumers or between repeated command executions in the same process.

Current Behavior

The DI container exposes Finder::class as an injectable service. Commands and synchronizers mutate that instance directly while discovering command classes, resources, Git hooks, or packaged skills.

Expected Behavior

Every operation that needs Finder configuration MUST receive a fresh Finder instance before applying criteria. Consumers SHOULD depend on a small factory abstraction so tests can still mock Finder creation without sharing mutable state.

Failure Surface

Affected code includes Finder consumers in src/Console/Command, src/Console/CommandLoader, and src/Agent/Skills, plus their tests. The bug is most visible when multiple Finder-backed operations execute in one long-lived Composer process.

Proposal

Introduce a FinderFactory abstraction that creates new Finder instances and inject that factory into Finder consumers instead of injecting Finder directly. Keep tests focused by mocking the factory and configuring the returned Finder mock.

Implementation Strategy

  • Add a FinderFactoryInterface and default FinderFactory implementation.
  • Register the factory in DevToolsServiceProvider.
  • Replace direct Finder injection in current consumers with the factory.
  • Request a fresh Finder for each scan before applying criteria.
  • Update tests to assert factory usage and prevent accidental shared Finder mutation.

Non-goals

  • Replacing Symfony Finder with another traversal implementation.
  • Changing which files, directories, commands, hooks, or skills are discovered.
  • Broadly refactoring command execution or service registration beyond Finder creation.

Acceptance Criteria

Functional Criteria

  • Finder-backed operations create a fresh Finder instance before applying mutable criteria.
  • Existing discovery behavior for resources, Git hooks, commands, and packaged skills remains unchanged.
  • The DI container no longer encourages injecting a shared mutable Finder service directly into consumers.

Regression Criteria

  • Unit tests cover Finder factory usage for the updated consumers.
  • Relevant focused tests pass locally.

Architectural / Isolation Criteria

  • Finder creation is isolated behind a small dedicated abstraction.
  • Commands and synchronizers remain orchestration-focused and do not own container-specific construction logic.
  • The change is scoped to Finder construction and the tests needed to validate it.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status

Released

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions