filesystem = new Filesystem(); $this->workDir = sys_get_temp_dir().'/get-installer-bootstrap-test-'.bin2hex(random_bytes(6)); $this->filesystem->mkdir($this->workDir); } protected function tearDown(): void { $this->filesystem->remove($this->workDir); } public function testSyncCopiesRepositoryScriptToCache(): void { $repositoryDir = $this->createRepository([ 'install.sh' => "#!/usr/bin/env bash\nprintf 'ok'\n", ]); $mapping = $this->mapping($repositoryDir, 'install.sh'); $synchronizer = $this->synchronizer(); $synchronizer->sync($mapping); self::assertSame(ScriptMapping::SYNC_STATUS_SYNCED, $mapping->getLastSyncStatus()); self::assertNotNull($mapping->getLastSuccessfulSyncAt()); self::assertNull($mapping->getLastSyncError()); self::assertSame('scripts/42.sh', $mapping->getCacheKey()); self::assertSame( "#!/usr/bin/env bash\nprintf 'ok'\n", file_get_contents($this->workDir.'/cache/scripts/42.sh') ); } public function testSyncFailureMarksMappingWithoutTokenLeak(): void { $repositoryDir = $this->createRepository([ 'install.sh' => "#!/usr/bin/env bash\n", ]); $mapping = $this->mapping($repositoryDir, 'missing.sh')->setAccessToken('secret-token'); $synchronizer = $this->synchronizer(); $this->expectExceptionMessage('Git synchronization failed.'); try { $synchronizer->sync($mapping); } finally { self::assertSame(ScriptMapping::SYNC_STATUS_FAILED, $mapping->getLastSyncStatus()); self::assertNotNull($mapping->getLastSyncError()); self::assertStringContainsString('missing.sh', $mapping->getLastSyncError()); self::assertStringNotContainsString('secret-token', $mapping->getLastSyncError()); } } /** @param array $files */ private function createRepository(array $files): string { $repositoryDir = $this->workDir.'/repo'; $this->filesystem->mkdir($repositoryDir); foreach ($files as $path => $content) { $fullPath = $repositoryDir.'/'.$path; $this->filesystem->mkdir(dirname($fullPath)); file_put_contents($fullPath, $content); } $this->runGit(['init'], $repositoryDir); $this->runGit(['config', 'user.email', 'tests@example.com'], $repositoryDir); $this->runGit(['config', 'user.name', 'Tests'], $repositoryDir); $this->runGit(['add', '.'], $repositoryDir); $this->runGit(['commit', '-m', 'Initial commit'], $repositoryDir); $this->runGit(['branch', '-M', 'main'], $repositoryDir); return $repositoryDir; } /** @param list $arguments */ private function runGit(array $arguments, string $cwd): void { $process = new Process(['git', ...$arguments], $cwd); $process->mustRun(); } private function mapping(string $repositoryUrl, string $repositoryFilePath): ScriptMapping { $mapping = (new ScriptMapping()) ->setPublicPath('mcp/graylog/install.sh') ->setRepositoryUrl($repositoryUrl) ->setGitRef('main') ->setRepositoryFilePath($repositoryFilePath) ->setActive(true); return $this->setMappingId($mapping, 42); } private function synchronizer(): GitSynchronizer { return new GitSynchronizer(new CachePathResolver($this->workDir.'/cache', $this->workDir)); } private function setMappingId(ScriptMapping $mapping, int $id): ScriptMapping { $property = new ReflectionProperty(ScriptMapping::class, 'id'); $property->setValue($mapping, $id); return $mapping; } }