-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/file hash generator #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,226 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <?php | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| declare(strict_types=1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace Gared\EtherScan\Console; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use GuzzleHttp\Client; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use GuzzleHttp\Exception\GuzzleException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use GuzzleHttp\RequestOptions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Attribute\AsCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Command\Command; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Helper\Table; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Input\InputArgument; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Input\InputInterface; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use Symfony\Component\Console\Output\OutputInterface; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[AsCommand( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'ether:generate-file-hashes-all-versions', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Generate file hashes for specific file on all versions of etherpad' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class GenerateFileHashesAllVersionsCommand extends Command | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected function configure(): void | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $this | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ->addOption('matches-count', null, InputArgument::OPTIONAL, 'Minimum count of matches for version to be considered valid', 3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ->addArgument('file', InputArgument::REQUIRED, 'File path to check'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected function execute(InputInterface $input, OutputInterface $output): int | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $filePath = $input->getArgument('file'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $countVersionsMatch = $input->getOption('matches-count'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $allInstances = $this->getInstances(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $instanceResults = new InstanceResults(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($this->getAllVersions($allInstances) as $version) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $this->scanVersionInstances($allInstances, $version, $filePath, $instanceResults, $output, $countVersionsMatch); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+31
to
+39
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $listInstances = $instanceResults->getInstancesByVersion(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uksort($listInstances, function ($a, $b) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return version_compare($a, $b); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versionRanges = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table = new Table($output); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->setHeaders(['Version', 'Count Instances', 'File Hashes']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($listInstances as $version => $instances) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHashes = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHashForVersion = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($instances as $instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($instance->fileHash !== null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHashes[] = $instance->fileHash; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHashesWithCount = array_count_values($fileHashes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($fileHashesWithCount as $fileHash => $count) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($count >= $countVersionsMatch) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHashForVersion = $fileHash; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($fileHashForVersion !== null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versionRanges[$fileHashForVersion][] = $version; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versionString = '<info>' . $version . '</info>'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (count($instances) < $countVersionsMatch) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versionString = '<comment>' . $version . '</comment>'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if ($fileHashForVersion === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versionString = '<error>' . $version . '</error>'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->addRow([$versionString, count($instances), ...$fileHashes]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->render(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table = new Table($output); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->setHeaders(['File Hash', 'Minimum Version', 'Maximum Version']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($versionRanges as $fileHash => $versions) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| usort($versions, function ($a, $b) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return version_compare($a, $b); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $minimumVersion = $versions[array_key_first($versions)]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $maximumVersion = $versions[array_key_last($versions)]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->addRow([$fileHash, $minimumVersion, $maximumVersion]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $table->render(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return self::SUCCESS; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param list<array{name: string, scan: array<mixed>}> $allInstances | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private function scanVersionInstances(array $allInstances, string $version, string $file, InstanceResults $instanceResults, OutputInterface $output, int $countVersionsMatchNeeded): void | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $foundMatchesForHash = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $scannedInstances = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($this->getInstancesByVersion($allInstances, $version) as $instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileContent = $this->getFile($instance['name'], $file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $fileHash = $fileContent !== null ? hash('md5', $fileContent) : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $scannedInstances++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $instanceResult = new InstanceResult($instance['name'], $version, $fileHash, $fileContent); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $instanceResults->add($instanceResult); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($instanceResult->fileHash === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $output->writeln('<error>Could not get hash for instance ' . $instance['name'] . '</error>', OutputInterface::VERBOSITY_VERY_VERBOSE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($scannedInstances > 4 && count($foundMatchesForHash) === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($this->matches($instanceResults, $instanceResult, $version)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $output->writeln('Match found for version ' . $version . ' and hash ' . $instanceResult->fileHash); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+116
to
+131
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isset($foundMatchesForHash[$instanceResult->fileHash])) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $foundMatchesForHash[$instanceResult->fileHash] = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $foundMatchesForHash[$instanceResult->fileHash]++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($foundMatchesForHash[$instanceResult->fileHash] === $countVersionsMatchNeeded) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // $output->writeln('<error>Mismatch found for version ' . $version . ' and hashes ' . $fileHash . ' != ' . $lastInstanceResult->fileHash . ' for servers: ' . $instanceResult->name . ', ' . $lastInstanceResult->name . '</error>'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // $output->writeln($lastInstanceResult->name . ': (' . mb_strlen($lastInstanceResult->fileContent) . ') ' . mb_substr($lastInstanceResult->fileContent, 0, 500), OutputInterface::VERBOSITY_DEBUG); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // $output->writeln($instanceResult->name . ': (' . mb_strlen($instanceResult->fileContent) . ') ' . mb_substr($instanceResult->fileContent, 0, 500), OutputInterface::VERBOSITY_DEBUG); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private function matches(InstanceResults $instanceResults, InstanceResult $instanceResult, string $version): bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($instanceResults->getInstancesForVersion($version) as $instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($instance->fileHash === $instanceResult->fileHash) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param list<array{name: string, scan: array<mixed>}> $instances | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param string $version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return list<array{name: string, scan: array<mixed>}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private function getInstancesByVersion(array $instances, string $version): array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $filteredInstances = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($instances as $instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($instance['scan']['version'] === $version) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $filteredInstances[] = $instance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shuffle($filteredInstances); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return $filteredInstances; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param list<array{name: string, scan: array<mixed>}> $instances | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return list<string> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private function getAllVersions(array $instances): array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versions = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach ($instances as $instance) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $version = $instance['scan']['version']; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!in_array($version, $versions, true)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $versions[] = $version; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shuffle($versions); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return $versions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return list<array{name: string, scan: array<mixed>}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private function getInstances(): array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $client = new Client(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $response = $client->get('https://ether-scan.stefans-entwicklerecke.de/api/instances'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $body = (string)$response->getBody(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $data = json_decode($body, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return $data['instances'] ?? []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+198
to
+203
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $client = new Client(); | |
| $response = $client->get('https://ether-scan.stefans-entwicklerecke.de/api/instances'); | |
| $body = (string)$response->getBody(); | |
| $data = json_decode($body, true); | |
| return $data['instances'] ?? []; | |
| try { | |
| $client = new Client([ | |
| RequestOptions::TIMEOUT => 3.0, | |
| RequestOptions::CONNECT_TIMEOUT => 1.0, | |
| ]); | |
| $response = $client->get('https://ether-scan.stefans-entwicklerecke.de/api/instances'); | |
| $body = (string) $response->getBody(); | |
| $data = json_decode($body, true); | |
| if (!is_array($data)) { | |
| return []; | |
| } | |
| $instances = $data['instances'] ?? []; | |
| return is_array($instances) ? $instances : []; | |
| } catch (GuzzleException) { | |
| return []; | |
| } |
Copilot
AI
Feb 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GuzzleHttp\Client in getFile() is configured with 'verify' => false, which disables TLS certificate validation for HTTPS requests to instance URLs. An attacker who can intercept or spoof network traffic (e.g., via DNS poisoning or a malicious proxy) could serve tampered file contents, leading to incorrect hash generation and undermining the integrity of the scan results. Remove the verify override and rely on default certificate verification (or a properly configured CA bundle) so that HTTPS connections are authenticated and protected against man-in-the-middle attacks.
| 'verify' => false, |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||
| <?php | ||||||||
|
||||||||
| <?php | |
| <?php | |
| declare(strict_types=1); |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,47 @@ | ||||||||
| <?php | ||||||||
|
||||||||
| <?php | |
| <?php | |
| declare(strict_types=1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The option is registered using InputArgument::OPTIONAL, but addOption() expects InputOption mode constants (e.g., VALUE_OPTIONAL / VALUE_REQUIRED). With the current code the option may not be parsed as intended on different Symfony versions; switch to Symfony\Component\Console\Input\InputOption and the appropriate VALUE_* constant.