markTestSkipped('Only a root process can change file owners.'); } $this->originalStoragePath = storage_path(); $this->storageRoot = sys_get_temp_dir().'/coolify-ssh-owner-'.uniqid(); File::ensureDirectoryExists($this->storageRoot.'/app/ssh/keys', 0700); chown($this->storageRoot.'/app/ssh', SSH_FILES_TEST_OWNER); chown($this->storageRoot.'/app/ssh/keys', SSH_FILES_TEST_OWNER); app()->useStoragePath($this->storageRoot); config(['filesystems.disks.ssh-keys.root' => $this->storageRoot.'/app/ssh/keys']); Storage::forgetDisk('ssh-keys'); }); afterEach(function () { if (isset($this->storageRoot)) { app()->useStoragePath($this->originalStoragePath); Storage::forgetDisk('ssh-keys'); File::deleteDirectory($this->storageRoot); } }); function makeServerWithPinnedHostKey(): Server { $server = new Server; $server->forceFill(['uuid' => 'owner-test', 'ip' => '10.0.0.5', 'port' => 22, 'user' => 'root']); $server->setRelation('settings', (new ServerSetting)->forceFill([ 'ssh_host_key' => 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl', ])); return $server; } function syncKnownHostsFileFor(Server $server): string { return (new ReflectionMethod(SshMultiplexingHelper::class, 'syncKnownHostsFile'))->invoke(null, $server); } it('gives a known_hosts file that root writes to the owner of the ssh directory', function () { $path = syncKnownHostsFileFor(makeServerWithPinnedHostKey()); expect(fileowner(dirname($path)))->toBe(SSH_FILES_TEST_OWNER) ->and(fileowner($path))->toBe(SSH_FILES_TEST_OWNER); }); it('repairs a known_hosts directory and file that root created before', function () { $server = makeServerWithPinnedHostKey(); $path = syncKnownHostsFileFor($server); chown(dirname($path), 0); chown($path, 0); syncKnownHostsFileFor($server); expect(fileowner(dirname($path)))->toBe(SSH_FILES_TEST_OWNER) ->and(fileowner($path))->toBe(SSH_FILES_TEST_OWNER); }); it('gives a private key file and its lock file that root writes to the owner of the ssh directory', function () { $team = User::factory()->create()->teams()->first(); $privateKey = PrivateKey::create([ 'name' => 'owner-test-key', 'team_id' => $team->id, 'private_key' => PrivateKey::generateNewKeyPair('ed25519')['private_key'], ]); $privateKey->storeInFileSystem(); expect(fileowner($privateKey->getKeyLocation()))->toBe(SSH_FILES_TEST_OWNER) ->and(fileowner($privateKey->getKeyLocation().'.lock'))->toBe(SSH_FILES_TEST_OWNER) ->and(fileperms($privateKey->getKeyLocation()) & 0777)->toBe(0600); });