Changelog
All notable changes to EasyAudit CLI will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.3.1] 2026-05-14
Added
- Config-driven processor directories (
processorDirskey inconfig/easyaudit.json): map ofnamespace → directoryconsumed byScanner::getProcessors(). Lets sponsor overlays register additional processor namespaces — or replace the built-in set entirely — without subclassingScanner. A present, non-empty map replaces the built-in default (EasyAudit\Core\Scan\Processor→src/Core/Scan/Processor); an empty map ({}, shipped as a placeholder in the default config) or an absent key falls back to it. Relative paths resolve against the directory of the config file; missing directories are skipped silently at scan time.getProcessors()is also promoted fromprivatetoprotectedso subclassing remains a fallback extension path.
[1.3.0] 2026-05-14
Added
- SpecificClassInjection —
statefulBuilderInjectionrule: flags direct constructor injection of stateful Magento framework builders (Magento\Framework\Api\FilterBuilder,Magento\Framework\Api\Search\FilterGroupBuilder,Magento\Framework\Api\SortOrderBuilder). Recommends the matching*Factory+create()per-method pattern.SearchCriteriaBuilderis intentionally excluded as the canonical public API. Severity: note. - Glossary system (
data/{lang}/glossary.json+src/Core/Glossary/GlossaryLoader): language-indexed concept definitions (term, Magento-contextualizedshortDefinition, optional links). Shipsenonly — unavailable languages fall back toen(GlossaryLoader::FALLBACK_LANGUAGE);LanguageNotAvailableExceptionis only thrown when the fallback itself is missing. The free repo emitsconceptsannotations on rule output but does not consume them in any reporter; sponsor reporters (MD, glossary HTML) pick them up via upstream sync. - Per-rule concept annotations on processors:
AbstractProcessorexposes aCONCEPTSconstant projected into the defaultgetReport().AroundPlugins,CountOnCollection,ProxyForHeavyClasses, andSpecificClassInjectionare annotated. Multi-rule processors emit per-rule slugs (viaRULE_CONFIGSentries or a per-ruleIdmap).tests/Unit/Core/Glossary/GlossaryIntegrityTestwalks every processor by reflection and asserts that every referenced slug exists indata/en/glossary.json. - Reporter configuration (
config/easyaudit.json+src/Service/Config.php): runtime registry mapping output format → reporter FQCN, plus adefaultFormatkey.Config::load()validates that each FQCN implementsReporterInterfaceand caches the result. PHAR build now bundles theconfig/directory (box.json). HtmlReporter::renderLongDescription(string $escapedText, array $rule): string: no-op extension hook that sponsor’sGlossaryHtmlReporteroverrides to inject autolinked concept tooltips into already-escaped paragraph text. The escape-then-inject ordering is mandatory.FixerInterface(src/Service/FixerInterface.php): backend abstraction for the fix pipeline.Apinow implements it;FixApplydepends on the interface instead of the concrete class.getRemainingCredits()may returnnullto signal that the active backend does not track credits —FixApplythen skips credit prompts, balance display, and the post-run cost summary. Enables local/offline fixers to plug in without touchingFixApply.- Configurable command registry and fixer in
bin/easyaudit: command list and fixer FQCN are now read fromConfig::load()(commandsandfixerkeys), with the same built-in defaults as before. Sponsor overlays can register additional commands or swap the fixer backend without forking the entry point. - Composer-aware autoloader in
bin/easyaudit: prefersvendor/autoload.phpwhen installed as a Composer dependency (vendor/crealoz/easyaudit-cli/bin/easyaudit) or from a source checkout. Falls back to the hand-rolled PSR-4 loader for the PHAR build, where Composer’svendor/is not bundled. Combined with thecomposer.jsonchanges, this allows installing the CLI ascomposer require crealoz/easyaudit-cli. Scanner::getMode()/Scanner::setMode(?string): scan-mode signal that commands set before callingScanner::run(). Processors can read it to tune behavior for a specific feature (e.g. amplifying severity on checkout-critical files in acheckout-auditrun).nullis the default, general-purpose scan.Paths::cacheDir(string $subdir = ''): XDG_CACHE_HOME-aware cache directory helper. Resolves to$XDG_CACHE_HOME/easyaudit(falling back to$HOME/.cache/easyaudit, then the system temp dir), creates the optional sub-directory on first use with mode0700, and throwsRuntimeExceptionon failure.- SARIF multi-location findings:
SarifReporternow splits a finding whosefilefield contains comma-separatedpath:linesegments into one SARIF location per segment. The outerstartLineis0in that case and each segment carries its own line. Used byAroundPlugins::deepPluginStackso SARIF consumers see one location per plugin di.xml declaration. AbstractPreparer::getMappedRule(): reintroduced as aprotectedhelper returning the mapped rule name for a given ruleId. Was removed in 1.2.0 as unused; now used by the fixer code path.
Changed
Scancommand — reporter dispatch is now config-driven: the hardcodedmatch($format)overJsonReporter|SarifReporter|HtmlReporteris replaced bynew $class()against theconfig/easyaudit.jsonmap. Allowed--formatvalues, the default format, and--helptext are all derived from the loaded config. Adding a new reporter is now a one-line edit toconfig/easyaudit.json— no change toScan.phpor any other core file is required. This is also the extension point sponsor builds use to swap inGlossaryHtmlReporter/ registerMdReporterwithout forkingScan.php.composer.json— package metadata for distribution:typechanged fromprojecttolibrary,licensechanged fromproprietaryto MIT, and abinentry (bin/easyaudit) was added. The CLI can now be installed as a Composer dependency and exposes theeasyauditexecutable viavendor/bin/easyaudit.AroundPlugins::deepPluginStack— per-plugin di.xml locations with line numbers: previously the finding pointed at the first di.xml file withline: 1. It now emits the full list of di.xml declarations that participate in the stack — every<plugin>node on the target across global/frontend/adminhtml scopes — encoded as comma-separateddiFile:lineNosegments. The message format also tightened from… — plugins: …to… Plugins: ….PluginRegistry— DOM-based parsing: rewritten fromSimpleXMLElementtoDOMDocument/DOMXPathso each<plugin>entry now carries its sourceline(getLineNo()). The plugin entry shape gained a requiredline: intfield. Only direct<plugin>children of each<type>are collected (xpath was already constrained, but the DOM walk makes it explicit).FixApply— credit-aware UX is now optional:$creditsRemainingis nullable; when the active fixer returnsnullfromgetRemainingCredits(), credit prompts, the “Credits remaining” line, and the real-cost summary are all suppressed.checkCreditsAndConfirm()return type is nowint|false|null. ThetotalFilescount is computed beforecalculateCost()so cost estimation sees the correct total.HtmlReporter— line column for multi-location findings: whenstartLineis0(multi-location finding such asdeepPluginStack), the Line cell now renders—instead of a misleading0. Long-description rendering also receives the rule array so therenderLongDescriptionextension hook has the concept slugs.Api::getRemainingCredits()return type tightened: now declared?arrayto match theFixerInterfacecontract. Docblocks onrequestFilefix,getRemainingCredits, andgetAllowedTypewere aligned with the interface’sarray{…}shapes.docs/processors.md: rule count updated from 37 to 38;SpecificClassInjectionseverity row gainsNotefor the new builder rule.psalm.xmlissue handlers:UnusedClasssuppression extended tosrc/Core/Report/andsrc/Core/Glossary/(reporter and glossary classes are resolved by FQCN strings);PossiblyUnusedMethodsuppression extended tosrc/Core/Report/,src/Service/Config.php, andsrc/Service/Paths.php.
[1.2.0] 2026-05-01
Added
- 6 new XML-integrity processors (27 total):
- AnonymousApiExposure — flags
webapi.xmlroutes exposed to anonymous callers without a justifying XML comment - BrokenAcl — detects admin menu entries that reference ACL resources not defined in any
acl.xml - CronIntegrity — detects
crontab.xmljobs whose instance class or method does not exist - GetWriteAntipattern — flags
webapi.xmlroutes where the HTTP verb does not match the semantics of the target service method (e.g.GETon asave*()method) - IndexerCircular — detects circular dependencies declared between indexers across
indexer.xmlfiles - OrphanedCronGroup — detects
crontab.xmljobs placed in a group that nocron_groups.xmldefines
- AnonymousApiExposure — flags
Graphutility (src/Core/Scan/Util/Graph.php) — cycle detection on directed adjacency lists via iterative 3-color DFS, with canonicalized output. Used byIndexerCircularand reusable for any future dependency-graph processorClasses::isImportUsed()— detects whether an imported FQCN is actually referenced in the file body (type hint, instanceof, static call, extends/implements, docblock, direct FQCN reference). Optional$ignoreParentPassthroughflag treats constructor parameters that are forwarded untouched toparent::__construct()as non-usage, enabling sub-class-aware detection- Multi-arg rejection in CLI:
scanandfix-applynow error out when given more than one positional argument instead of silently using the last one.Args::parse()return type changed:restis nowarray<int, string>instead ofstring
Changed
- UseOfObjectManager — useless-import detection rewritten: replaces the previous “imported but no usage tracked” heuristic with
Classes::isImportUsed(..., ignoreParentPassthrough: true). A subclass that importsObjectManagerInterfaceonly to type-hint a parameter forwarded toparent::__construct()is now correctly flagged as a useless import — previously masked by the parent passthrough - AroundPlugins —
deepPluginStackseverity raised frommediumtohigh. Deep around-plugin chains are a real performance and debugging hazard, not a stylistic concern - CountOnCollection — constructor parsing hoisted:
analyzeFile()andmapCollectionReturningMethods()no longer each re-parse the same constructor; parsing happens once inprocess()and is passed in. Minor speedup on large files where both code paths run - SpecificClassInjection — class-file cache: repeated reads of the same target class file (during
extendsClass()checks forAbstractModel/AbstractExtensibleModel) are now cached per-scan, avoiding redundant disk I/O when the same parent class is inspected for many injection sites - HtmlReporter — CSS cached statically:
report.cssis loaded once per process and now throwsRuntimeExceptionif missing instead of silently producing an unstyled report - Api — replaces
echowithCliWriter::info()for the “calling API” log line
Fixed
Content::getLineNumber()not-found return: changed from-1to0for consistency with caller expectations across the codebase. Callers that need to detect “not found” should now check=== 0
Removed
AbstractPreparer::getMappedRule()— unusedMagentoFrameworkPlugin::getFoundCount()override — redundant;AbstractProcessor’s default is now used
[1.0.9] 2026-04-16
Fixed
- Fix-apply: proxy patches not generated: Rule ID mapping mismatch between Scanner and FixApply prevented proxy findings (
noProxyUsedInCommands,noProxyUsedForHeavyClasses) from reaching the fixer. Scanner checked fixable types using the processor’s ruleId (e.g.,noProxyUsedInCommands) while the API returns the mapped name (proxyConfiguration). Both Scanner and FixApply now resolve mapped rule names viaPreparerInterface::MAPPED_RULESbefore checking fixable types — consistent with whatAbstractPreparer::isRuleFixable()already does - ProxyForHeavyClasses no longer recommends Proxy for Collections: Collections are stateful and need a fresh instance per use — the correct pattern is
CollectionFactory, not\Proxy.SpecificClassInjectionalready flags this correctly withcollectionMustUseFactory. Removed'Collection'from heavy class patterns and added an explicitTypes::isCollectionType()guard inisHeavyClass()
Added
- Result consolidation: All processors now merge consecutive-line findings for the same file into a single entry (e.g., two proxy issues on lines 15-16 become one entry with
startLine: 15,endLine: 16). Non-consecutive findings remain separate. Messages are joined with line breaks, metadata entries are collected into arrays, and severity takes the highest value. Consolidation logic lives inAbstractProcessor::consolidateResults()and is applied in all 13 processors that can produce per-file duplicates - SARIF
endLinesupport: Region objects now includeendLinewhen it differs fromstartLine, per the SARIF 2.1.0 spec - HTML line ranges: The Line column now displays ranges (e.g.,
15-16) for consolidated findings, and messages render with<br>separators
Changed
- DiPreparer:
processFiles()now handles both consolidated metadata (array of entries) and single-entry metadata, ensuring fix-apply works correctly with consolidated reports - FixApply
selectRules(): Interactive rule selection and credit cost lookup now use mapped rule names, fixing proxy rules not appearing in the--fix-by-rulemenu
[1.0.8] 2026-04-13
Added
- Magento Version Security Check: Detects known security vulnerabilities based on the Magento version found in
composer.lock. Uses offline security bulletin data (data/security/) covering Magento 2.4.3 through 2.4.8. Includestools/update-security-bulletins.phpto refresh bulletin data - Detailed processor descriptions: All 21 processors now include structured
longDescriptionwith Impact, Why change, and How to fix sections - HTML report: formatted descriptions: Long descriptions render with bold labels (Impact, Why change, How to fix) instead of plain short descriptions
Changed
- Default output format: Changed from
jsontohtml - JSON output optimized for fixer: When format is
json, report entries are stripped ofname,shortDescription,longDescription, and per-filemessageto reduce payload size and improve fixer processing. Security check is skipped in JSON mode. Only fixable rules are included. - PHAR build:
data/directory now included in distribution (box.json) - Processor documentation (
docs/processors.md): Rewritten with per-rule detail, rule counts, and structured explanations
Removed
$onlyFixableparameter inScanner::run(): Replaced by format-driven$fixerReadylogic
[1.0.7] 2026-03-19
Added
- Deep plugin stack detection (
deepPluginStackrule in AroundPlugins): Detects when 2+ around plugins intercept the same method on a target class, creating a deep call stack that amplifies performance overhead and complicates debugging. Uses newInterceptorandPluginRegistryutilities to analyze generated interceptor files and di.xml plugin mappings - Stateful model injection detection (
statefulModelInjectionrule in SpecificClassInjection): Detects direct injection of classes extendingAbstractModelorAbstractExtensibleModel— these hold mutable state and should use a Factory to create fresh instances Severityenum (src/Core/Scan/Severity.php): Centralized severity model with three levels (HIGH, MEDIUM, LOW) and SARIF mapping (toSarif())Interceptorutility (src/Core/Scan/Util/Interceptor.php): Analyzes Magento’s generated interceptor files to extract intercepted method namesPluginRegistryutility (src/Core/Scan/Util/PluginRegistry.php): Parses all di.xml files to build plugin-to-target class mappings, enabling cross-plugin analysis- Generated code auto-detection: Scanner now detects non-empty
generated/code/directories in Magento installations and exposes the path viaScanner::getGeneratedPath()for advanced analysis - CountOnCollection: phtml detection now works for blocks that inject a Collection directly (not via CollectionFactory) and return it from a method
Changed
- Severity model overhaul: Replaced SARIF-style severity names (
error/warning/note) with internal model (high/medium/low) throughout all processors, reporters, and utilities. SARIF output maps back to spec levels automatically (high→error,medium→warning,low→note) - HtmlReporter: Summary cards and filtering now use HIGH/MEDIUM/LOW labels and corresponding CSS classes
- SpecificClassInjection: Severity recalibrated —
collectionandrepositoryrules changed fromerrortohigh,resourceModelandgenericClassfromwarningtomedium - AroundPlugins: Severity recalibrated —
aroundWithoutProceedfromerrortohigh,aroundWithProceedfromwarningtomedium - Formater::formatError(): Default severity changed from
warningtomedium - CliWriter::resultLine(): Severity parameter now accepts
high/medium/low - Scan command: Exit code logic uses new severity keys (
high/mediuminstead oferrors/warnings)
Removed
collectionWithChildrenrule (SpecificClassInjection): Removed — thecollectionrule now covers all cases without requiring child class detectionrepositoryWithChildrenrule (SpecificClassInjection): Removed — therepositoryrule now covers all cases without requiring child class detection
[1.0.6] 2026-03-13
Fixed
- AroundPlugins: Fixed callable detection for multi-line function signatures — around plugins with parameters spanning multiple lines (common with complex type hints) are now correctly detected and classified
- AroundPlugins: Callable parameter is now identified by position (always the second parameter per Magento convention) instead of heuristic name/type matching — eliminates false negatives when the callable has a non-standard name or no type hint
- AroundPlugins: Callable invocation detection now matches
$proceed(instead of$proceed();— correctly handles calls with arguments (e.g.,$proceed($product, $request)) - Functions::getFunctionContent(): Fixed inner content extraction for multi-line signatures — parameter lines before the opening brace are no longer included in the function body
Changed
- FixApply: Added
--formatoption (default:git) passed through to the API for patch format selection - FixApply: Absolute paths in diffs are now normalized to relative paths for
git applycompatibility
[1.0.5] 2026-03-10
Added
- InlineStyles processor (21st processor): Detects inline CSS (
style=""attributes and<style>blocks) in phtml/html templates — flags CSP violations and maintainability issues. Email and PDF templates are excluded as they legitimately require inline CSS - HTML file scanning: Scanner now collects
.htmlfiles alongside phtml for template analysis
Fine-tuning after benchmark
Processors were tested against a real Magento 2 codebase. The following changes reduce false positives and improve detection accuracy.
New utilities
Classes::isControllerClass(): Detects Magento controller classes (Action, HttpGet/PostActionInterface, Backend Action)Classes::getParentConstructorParams(): Extracts parameter names passed toparent::__construct()Classes::isParentPassthrough(): Shared utility to check if a constructor param is forwarded toparent::__construct()— used by SpecificClassInjection and UseOfRegistryContent::getLineNumber()$afterLineparameter: Optional parameter to skip matches before a given line — enables reporting constructor arg lines instead of property linesModules::isEmailTemplate(): Detects files in/email/directoriesModules::isPdfTemplate(): Detects files in/pdf/,/invoice/,/shipment/,/creditmemo/directories
Processor improvements
- AroundPlugins: Around plugins using
$proceed()conditionally (ternary, if/else, short-circuit&&/||) are no longer flagged — conditional execution is a legitimate around plugin pattern.try/catch/finallyblocks and closing braces are now treated as structural lines when classifying before/after plugins - AdvancedBlockVsViewModel: Suffix-based exclusion (
*Url,*Html) replaces redundant entries inallowedMethods. Threshold lowered from 5 to 1 suspicious call - HardWrittenSQL: Setup/Patch files are no longer skipped entirely — SQL is still detected but severity is reduced to
note - UseOfObjectManager: Now skips
Setup/Patch,Console/Command, andTestpaths entirely (legitimate ObjectManager usage). Detects variable-argument OM usage (->get($variable)). Config classes (extendingMagento\Framework\Config\Data) get reduced severity (note) for variable-argument usage since the real fix is to use Factory types in configuration XML - UseOfRegistry: Registry injected only to pass to
parent::__construct()(no active->registry()/->register()/->unregister()calls) is no longer flagged - SpecificClassInjection: Setup directories are now skipped.
AbstractModelandAbstractExtensibleModeladded to ignored substrings.Builder,Emulation,Reader,Service,Settingsadded to legitimate suffixes. Collection injection insideAbstractModelsubclasses is no longer flagged (legitimate$resourceCollectionpattern). Line numbers now report constructor arg position instead of property declaration - SameModulePlugins: Line numbers now use the plugged class (target) instead of the plugin class — prevents duplicate lines when the same plugin targets multiple classes
- ProxyForHeavyClasses: Controller classes are now skipped (non-shared, always execute their dependencies)
- Cacheable: Admin (
/adminhtml/) and email template layouts are now skipped (caching not applicable) - Scanner:
Testdirectory (singular, Magento convention) added to default exclusions alongsideTests - Classes::getConstructorParameters(): Now strips inline comments (
//and/* */) from constructor body before parsing, preventing misidentified parameters - Classes::parseConstructorParameters(): Added validation to skip tokens that aren’t valid class names (comments, array syntax, variables)
Fixes
- SpecificClassInjection: Parent constructor params were never excluded due to
$prefix mismatch ($contextvscontext) — fixed viaClasses::isParentPassthrough() - SameModulePlugins: Two
<type>nodes with the same plugin class no longer report the same line number - AdvancedBlockVsViewModel: Fixed
Array to string conversionerror when building data crunch message - Psalm: Added
CliWriter.phptoPossiblyUnusedMethodsuppression list
[v1.0.4] - 2026-03-06
Added
- Multi-select rule fixing:
--fix-by-rulenow supports comma-separated input (e.g.,1,3,5) andallto select every fixable rule at once - Credit cost display: Rule selection menu now shows the credit cost per file for each rule
- Path-based exclude patterns:
--excludenow supports patterns with/that match relative path prefixes (e.g.,--exclude=app/code/SomeVendor), in addition to simple basename matching - Clickable report path: Report file path in CLI output is now a clickable hyperlink (OSC 8) in supported terminals (PHPStorm, iTerm2, GNOME Terminal, Windows Terminal, etc.)
- HTML report sponsor link: Footer now links to the GitHub repository and includes a sponsor link
Removed
--all-magentoflag:vendor/is now always excluded when scanning — no option to include it (too slow, not useful for static analysis)
Changed
PreparerInterface::prepareFiles():$selectedRuleparameter changed from?stringto?array($selectedRules) to support multi-rule selectionFixApply: When multiple rules are selected, patches use the default layout (patches/{path}/File.patch); single-rule selection keeps the rule-specific layout (patches/{ruleId}/{path}/File.patch)
[v1.0.3] - 2026-03-04
Fixed
- Lazy service instantiation: All services (
Scanner,Api,Logger) are now created lazily inside the command registry — fixes config directory error when runningscanin Docker without a home directory
Changed
- Dockerfile: Added
WORKDIR /workspaceso default report output lands inside the mounted volume - Docker documentation: All examples now include
--user "$(id -u):$(id -g)"for correct file ownership
[v1.0.2] - 2026-03-04
Added
- Magento root auto-detection: When scanning a Magento installation root, EasyAudit now detects it automatically (2+ indicators:
bin/magento,nginx.conf.sample,app/etc/env.php,generated/,pub/) and displays the list of auto-excluded directories - Default exclusion of Magento noise directories:
vendor,generated,var,pub,setup,lib,dev,phpserver,updateare now always excluded — no need to pass--excludemanually - Interactive vendor prompt: When a Magento root is detected in interactive mode, the user is asked whether to include the
vendor/directory in the scan (default: no) --all-magentoflag: In CI/CD environments, pass--all-magentoto includevendor/in the scan (auto-excluded by default)Scanner::isMagentoRoot()public static method for Magento root detection
Fixed
--excludenow matches directory basenames: Previously,--exclude=customonly matched full paths; now it correctly skips directories by name during recursive scanning
[v1.0.1] - 2026-03-04
Fixed
- Content::removeComments: Now throws
InvalidArgumentExceptiononpreg_replacefailure instead of silently returning null — prevents downstream errors on malformed files - CollectionInLoop: Gracefully handles
removeCommentsfailures with a warning instead of crashing the scan - HardWrittenSQL: Gracefully handles
removeCommentsfailures with a warning instead of crashing the scan - Content::findApproximateLine: Moved
preg_replacefor needle normalization outside the loop — minor performance improvement
Added
- PHAR provenance attestation in release workflow via
actions/attest-build-provenance@v2 - Security & Privacy documentation (
docs/security.md) - CliWriter: Overridable
$stderrstream for testability
Changed
- README updated with privacy notice and 20 processors count
[v1.0.0] - 2026-02-27
Added
- DeprecatedEscaper processor: Detects deprecated
$block->escapeHtml()/$this->escapeHtml()usage in phtml templates — should use$escaper->escapeHtml()instead (Magento 2.4+ best practice)
[v0.6.2] - 2026-02-19
Changed
- Documentation updates
[v0.6.1] - 2026-02-16
Fixed
- ltrim fix in path handling
[v0.6.0]
Added
- Content-Security-Policy meta tag in HTML reports — restricts scripts, styles, and external resources to prevent XSS in report files
- New legitimate suffixes in
SpecificClassInjection:Pool,Logger, andConfigsuffixes are no longer flagged as concrete class injections - Expanded
Classes::BASIC_TYPES— now includesobject,callable,iterable,void,never,self,static,parent,true,false, PHP standard classes (DateTime,DateTimeImmutable,Closure,stdClass,JsonSerializable), and exception types (Throwable,Exception,RuntimeException) - New tests for
SpecificClassInjection: Pool/Logger/Config suffix handling, PHP standard class detection, nullable basic type handling
Fixed
- HtmlReporter: Added
ENT_SUBSTITUTEflag to allhtmlspecialchars()calls — prevents silent data loss on malformed UTF-8 sequences in file paths and messages - Classes utility: Nullable type hints (e.g.
?int,?string) are now properly stripped before basic-type checking, preventing false positives in constructor analysis
Changed
- Release workflow fixes (v0.5.1)
[v0.5.0]
Changed
- Release workflow: Replaced
Notify middleware webhookstep with version-aligned deployment — CLI release now checks middleware readiness and triggers symlink switch via deploy webhook before publishing, ensuring CLI and middleware versions are always in sync
Fixed
- UseOfObjectManager: Metadata now distinguishes
getvscreatecalls —injectionsvalues changed from$propertyNameto['property' => $propertyName, 'method' => 'get'|'create']so the middleware fixer can inject a Factory forcreate()calls instead of always generating singleton DI - SpecificClassInjection: Removed
str_contains($className, 'Model')guard that prevented collection, repository, resource model, and API interface detection when the containing class was outside aModelnamespace (e.g., controllers, services, helpers) - SpecificClassInjection: Collection check now inspects the injected parameter class instead of the containing class, fixing misclassification of collections as resource models
- SpecificClassInjection: Added
$shouldCheckModelcascade to prevent double-detection (collections/repositories inResourceModelnamespace no longer also flagged as resource model injections) - SpecificClassInjection: Legitimate resource model injections (in repositories, in other resource models) no longer fall through to the generic
specificClassInjectionrule
[v0.4.0]
Added
- 3 new processors (19 total):
- CollectionInLoop: Detects N+1 query patterns (model/repository loading inside loops)
- CountOnCollection: Detects
count()on collections instead ofgetSize() - DiAreaScope: Detects plugins/preferences in global
di.xmltargeting area-specific classes
- 6 new utility classes for shared logic across processors:
DiScope: DI scope detection, XML loading, and class area detectionTypes: Type checking helpers (isCollectionType,isRepository,isResourceModel,hasApiInterface, etc.)Modules: Module extraction, file grouping, anddi.xmllookupFunctions: Function content extraction and brace block parsingXml: Safe XML loading with libxml error suppression- Extended
ClasseswithfindClassDeclarationLine,isFactoryClass,isCommandClass,derivePropertyName - Extended
ContentwithremoveComments,findApproximateLine
- Console Command tests (ScanTest, FixApplyTest, AuthTest, ActivateSelfSignedTest)
- Unit tests for all new processors and utilities (CollectionInLoop, CountOnCollection, DiAreaScope, DiScope, Types, Modules, Functions, Classes)
- Expanded tests for existing processors (Helpers, NoProxyInCommands, Preferences, ProxyForHeavyClasses, SpecificClassInjection, UseOfObjectManager, UseOfRegistry)
Changed
- Preferences processor now scope-aware: duplicate preferences in different scopes (e.g.,
frontend/di.xmlvsadminhtml/di.xml) are no longer flagged as conflicts - Refactored 10 processors to use shared utility classes instead of inline logic (Types, Modules, Content, Functions, Classes)
- Moved support classes from
src/Support/tosrc/Service/(Env,Paths,ProjectIdentifier) - Constructor injection in all Console Commands (Scan, FixApply) replacing static instantiation — enables mocking in tests
- Scanner now uses injected dependency instead of hardcoded
Apiinstantiation - Code coverage increased from 77% to 92.82% (2521/2716 lines), 750 tests
- Excluded untestable infrastructure files from coverage (
Api.php,Env.php,Auth.php) - Psalm 5 static analysis integrated:
- Fixed redundant casts, missing return paths, dead code, docblock mismatches
- Configured
psalm.xmlwith issue handlers for auto-discovered classes and runtime constants
- Developer Guide documentation:
- Writing Processors — architecture, step-by-step guide, best practices, testing
- Utilities Reference — all 8 utility classes with method signatures and examples
Fixed
- AuthTest no longer writes test credentials to real config directory (uses temp
XDG_CONFIG_HOME)
Removed
src/Support/namespace (replaced bysrc/Service/)
[0.3.0] - 2026-02-09
Added
- HTML report format (
--format=html):- Self-contained single-file dashboard with inline CSS
- Color-coded summary cards (Total, Errors, Warnings, Notes)
- Collapsible rule sections with severity badges and file tables
- Interactive filtering: click any summary card to filter rules by severity
- Print-to-PDF support with
@media printstyles (4 cards on one row, all rules expanded)
- GitHub Pages documentation site:
- Custom layout with responsive navigation and mobile hamburger menu
- Dark teal (
#142d37) header/footer matching report branding - Deployed via
deploy-docs.ymlGitHub Actions workflow - “Buy Fixer Credits” CTA link in navigation
- 17 new unit test files covering Args, Filenames, HtmlReporter, ExternalToolMapping, Scanner, ClassToProxy, CliWriter, Paths, Version, and multiple processors (AroundPlugins, AdvancedBlockVsViewModel, PaymentInterfaceUseAudit, SpecificClassInjection, Classes, Content, Formater, Functions)
Changed
SpecificClassInjectionprocessor refactored: inlined private methods (addGenericClassWarning,addModelWithInterfaceError,addResourceModelError,guessInterfaceName,printResults), reduced duplicateClasses::getChildren()calls per parameter- Documentation overhaul across 16 files:
- Added summary table to processors.md with all 16 rules at a glance
- Added table of contents to cli-usage.md, request-pr.md, github-actions.md, and fixtures README
- Fixed exit code capture bug in all 7 CI/CD platform docs (
EXIT_CODE=$?replaced with|| EXIT_CODE=$?pattern forset -ecompatibility) - Fixed
upload-sarifaction version inconsistency (standardized to@v4) - Replaced 45-line paid PR workflow YAML in README with concise summary + link
- Reorganized fixtures README from session-based to category-based headings
- Added breadcrumb navigation to all CI/CD platform docs
- Removed broken Jenkins “Fail on Errors” example (kept correct
returnStatusapproach) - Fixed PR template markdown formatting
Fixed
- Improved ObjectManager detection for fixing (better identification of actual usages vs imports)
- Fixed class name comparison in
UseOfRegistryandSpecificClassInjectionprocessors (leading backslash normalization)
[0.2.0] - 2026-02-05
Added
CliWriterservice for centralized CLI output formatting:- Colored output methods:
success(),error(),warning(),info() - Inline color helpers:
green(),blue(),bold() - Progress bar with credits display
- Menu item rendering for interactive selection
- Result line with severity icons
- Colored output methods:
- New exceptions for better error handling:
CliExceptionwith exit code supportCouldNotPreparePayloadExceptionfor payload preparation failuresCurlResponseExceptionfor API response errorsRuleNotAppliedExceptionfor rule selection errorsNoChildrenExceptionfor class hierarchy queries
AbstractPreparerbase class for payload preparers with shared logic- Rule mapping via
MAPPED_RULESconstant for proxy configuration rules phpcs.xmlconfiguration for PSR-12 code style enforcement- Required PHP extensions declared in
composer.json:ext-curl,ext-libxml,ext-simplexml - Codecov token authentication in GitHub Actions workflow
Changed
FixApplycommand completely refactored:- Extracted into smaller focused methods
- Uses
CliWriterfor all output - Proper exception handling instead of exit codes
- Better separation of concerns
UseOfObjectManagerprocessor improved detection:- Now correctly identifies useless imports vs actual usage
- Won’t false-positive on unrelated
->get()or->create()calls - Uses class constants for ObjectManager patterns
- Leverages
Classesutility for constructor analysis
SpecificClassInjectionprocessor simplified:- Consolidated 7 result arrays into
resultsByCategorywithRULE_CONFIGS - Single
addViolation()method replaces multiple add methods - Uses
CliWriter::resultLine()for output
- Consolidated 7 result arrays into
- Payload preparers now extend
AbstractPreparer:GeneralPreparerandDiPreparershare common logic- Throws typed exceptions instead of
RuntimeException
UnusedModulesprocessor improved config.php detection:- Now traverses up from scan path until config.php is found
- Removed hardcoded relative path guessing
Authcommand simplified option parsing usingArgsutilityArgsutility refactored withparseLongOption()andparseShortFlags()methods- Exit code now respects exception code via
$e->getCode() ?: 1 - All processors updated for PSR-12 compliance (line length ≤150)
Removed
creditscommand (unused, stub only)fix-plancommand (unused, stub only)- Redundant checks like
hasChildren()andgetChildren()in SpecificClassInjection (usesClasses::getChildren()) - Removed implicit
EnvAuthExceptionthrow when credentials are empty
Fixed
- ObjectManager useless import detection no longer triggers API fix attempts
- PSR-12 violations across all source files
- Missing newlines at end of files
[0.1.2] - 2026-02-03
Added
- Direct
curldownload command in README and CLI docs for easier PHAR installation
Changed
- Format validation:
scancommand now validates--formatoption and shows error for unknown formats (onlyjsonandsarifare supported) - Updated
actions/checkoutfrom v4 to v6 in all documentation examples - Default format is now explicitly
json(was implicitly text before)
Fixed
- Docker: Added
easyauditwrapper script so the command works inside containers (CI/CD workflows usingcontainer: image)
Removed
textoutput format removed (console output is always displayed regardless of format)
[0.1.1] - 2026-02-03
Added
- Version compatibility system for CLI-Middleware communication:
- New
Versionclass withVERSIONandHASHconstants --version/-vCLI flag to display version informationX-CLI-VersionandX-CLI-Hashheaders sent with all API requestsUpgradeRequiredExceptionfor handling HTTP 426 (Upgrade Required) responses
- New
- Automated release workflow:
- GitHub Actions builds PHAR with embedded version and SHA-512 hash
- Webhook notification to middleware for version registration
- Automatic GitHub Release creation with PHAR artifact
- Docker image tagging with version numbers
Changed
- Dockerfile simplified: Now uses PHAR distribution instead of copying source files
- Removed unused imports and variables across multiple files
FixApplyrefactored to use instance property for error tracking
Removed
- Deleted
src/Core/Scan/Util/Fixable.php(unused) - Removed metadata section from
box.json
[0.1.0] - 2026-01-27
Added
- GitHub repository templates:
- Bug report and feature request issue templates (YAML forms)
- Pull request template
- Issue template chooser with contact links
- Dependabot configuration for Composer and GitHub Actions
- Code coverage with Codecov integration in CI workflow
- CI/CD documentation for multiple platforms:
- GitHub Actions, GitLab CI, Azure DevOps
- Jenkins, CircleCI, Travis CI, Bitbucket Pipelines
- MIT License file
- CI/CD environment detection for API requests:
- New
CiEnvironmentDetectorservice detects 7 CI providers X-CI-ProviderandX-CI-Identityheaders sent with API requests- Supports GitHub Actions, GitLab CI, Azure DevOps, CircleCI, Jenkins, Travis CI, Bitbucket Pipelines
- New
- Interactive
--fix-by-rulemode for fix-apply command:- Select which rule to fix via interactive menu
- Patches organized into rule-specific subdirectories (
patches/{ruleId}/...) - Sequenced filenames for multiple patches per file (
File-2.patch,File-3.patch) - Relative path preservation in patch output structure
ClassToProxyservice with 220+ heavy Magento classes:- Shared detection between
ProxyForHeavyClassesandSpecificClassInjectionprocessors - Includes repositories, resource connections, config readers, session handlers, etc.
- Shared detection between
- New ignored patterns in
SpecificClassInjection:- Classes ending with
ProviderorResolver - All
Magento\Frameworkclasses - Catalog visibility/status classes, sales order config, store manager, etc.
- Classes ending with
- New
Filenames::getRelativePath()andFilenames::getSequencedPath()utility methods - Integration test suite in phpunit.xml
- Tests for
ClassToProxyintegration inSpecificClassInjectionTest
Changed
SpecificClassInjectionnow skips CLI commands (Symfony Console) entirelyProxyForHeavyClassesusesClassToProxyservice instead of hardcoded listPreparerInterface::prepareFiles()now accepts optional$selectedRuleparameter- Removed
CollectionandResourceModelfrom pattern-based heavy class detection (now uses explicit list)
Fixed
- Reduced false positives in
SpecificClassInjectionfor legitimate Magento patterns - Removed redundant
isRegistry()andisFileSystem()checks (covered byClassToProxy)
[0.0.8] - 2025-01-13
Added
- Colorful scan output with severity indicators (red for errors, yellow for warnings, blue for info)
- Visual header with processor names in cyan for better readability
- Class hierarchy detection in SpecificClassInjection processor
- New rules for classes with children requiring manual fix:
collectionWithChildrenMustUseFactoryrepositoryWithChildrenMustUseInterface
- ExternalToolMapping for issues fixable by external tools (php-cs-fixer suggestions)
- Progress bar in FixApply command
- Echo output for all processor rules showing issue counts
- New
PreparerInterfacewithGeneralPreparerandDiPreparerfor payload preparation - Dedicated
Loggerservice for error and debug logging Filenamesutility class for path sanitization
Changed
- Scanner output now displays processor names instead of identifiers
- Improved FixApply command with file-by-file processing
- Refactored
FixApplyto use class properties for better state management - Extracted payload preparation logic into dedicated preparer classes
- Simplified progress bar rendering using class properties
Fixed
- Helpers processor echo statements moved from getReport() to process() for consistency
[0.0.7] - 2024-11-06
Added
- 12 new processors for code quality analysis:
- AroundPlugins
- MagentoFrameworkPlugin
- NoProxyInCommands
- SameModulePlugins
- HardWrittenSQL
- SpecificClassInjection
- UseOfRegistry
- UseOfObjectManager
- Preferences
- Cacheable
- BlockViewModelRatio
- UnusedModules
- Output formats: JSON, SARIF, Text
- Docker support (ghcr.io/crealoz/easyaudit:latest)
- PHAR distribution
- GitHub Code Scanning integration via SARIF output
[0.0.3] - [0.0.6] - 2024-09-25 to 2024-10-02
No user-facing changes.
[0.0.2] - 2024-09-25
Added
- Initial release of EasyAudit CLI