feat(files): add write, mkdir, rename and delete operations

This commit is contained in:
Aditya Tripathi
2026-08-26 13:38:56 +00:00
parent b68462734f
commit d6a39f1a80
2 changed files with 78 additions and 0 deletions
@@ -85,6 +85,56 @@ class ContainerFilesystemService
return (string) base64_decode(trim($encoded), true);
}
public function buildWriteCommand(string $path, string $content): string
{
$escaped = $this->escapePath($path, 'write path');
$b64 = base64_encode($content);
return $this->dockerExecShell("echo {$b64} | base64 -d > {$escaped}");
}
public function buildMkdirCommand(string $path): string
{
$escaped = $this->escapePath($path, 'mkdir path');
return $this->dockerExecShell("mkdir -p -- {$escaped}");
}
public function buildRenameCommand(string $from, string $to): string
{
$escapedFrom = $this->escapePath($from, 'rename source');
$escapedTo = $this->escapePath($to, 'rename target');
return $this->dockerExecShell("mv -- {$escapedFrom} {$escapedTo}");
}
public function buildDeleteCommand(string $path): string
{
$escaped = $this->escapePath($path, 'delete path');
return $this->dockerExecShell("rm -rf -- {$escaped}");
}
public function write(string $path, string $content): void
{
instant_remote_process([$this->buildWriteCommand($path, $content)], $this->server);
}
public function makeDirectory(string $path): void
{
instant_remote_process([$this->buildMkdirCommand($path)], $this->server);
}
public function rename(string $from, string $to): void
{
instant_remote_process([$this->buildRenameCommand($from, $to)], $this->server);
}
public function delete(string $path): void
{
instant_remote_process([$this->buildDeleteCommand($path)], $this->server);
}
public function defaultRoot(): string
{
$escapedContainer = escapeshellarg($this->container);
@@ -123,3 +123,31 @@ it('reads an editable text file', function () {
expect($content)->toBe("hello world\n");
});
it('base64-encodes content in the write command', function () {
$cmd = fsService()->buildWriteCommand('/app/a.txt', "hi\n");
expect($cmd)
->toContain('base64 -d')
->toContain(base64_encode("hi\n"))
->toContain(escapeshellarg('/app/a.txt'));
});
it('builds mkdir, rename and delete commands with escaped paths', function () {
$svc = fsService();
expect($svc->buildMkdirCommand('/app/new dir'))
->toContain('mkdir -p')
->toContain(escapeshellarg('/app/new dir'));
expect($svc->buildRenameCommand('/app/a', '/app/b'))
->toContain('mv')
->toContain(escapeshellarg('/app/a'))
->toContain(escapeshellarg('/app/b'));
expect($svc->buildDeleteCommand('/app/x'))
->toContain('rm -rf')
->toContain(escapeshellarg('/app/x'));
});
it('rejects unsafe paths in mutating builders', function () {
fsService()->buildDeleteCommand('/app/$(reboot)');
})->throws(Exception::class);