Leave the archive readable by whoever collects from it
Reported as "the folder arrives empty". It was not empty. The folder was 0700 and owned by the account that wrote it, so the account that COLLECTS — an rsync over ssh, a backup agent, anything that is not the writer — could not enter it, and an unreadable directory looks exactly like an empty one. The invoice had been sitting in it the whole time. The cause is that the default follows the process umask, so under a restrictive one 0755 quietly becomes 0700. The permissions are declared on the disk now rather than left to inherit, and a test writes under umask 0077 and asserts the mode — the ordinary umask hides this completely, which is why it was found on a server and not here. Two mistakes of mine on the way to it, both worth recording. I read the folder as the wrong user, got no entries back, and concluded the file had been deleted — it was a permission failure reading as an unprivileged account, not a missing file. And the first fix was a chmod on a variable that does not exist in that method, silenced by an @ so it failed without a word. Flysystem takes its permissions from configuration; a chmod afterwards was the wrong layer even before it was the wrong variable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>feat/granted-plans
parent
79564947d4
commit
132be7fdd5
|
|
@ -148,6 +148,18 @@ final class InvoiceArchive
|
|||
'driver' => 'local',
|
||||
'root' => $target->path,
|
||||
'throw' => false,
|
||||
// Explicit, because the default follows the process umask and a
|
||||
// restrictive one leaves the folder 0700. That is not cosmetic:
|
||||
// whoever COLLECTS from a handover directory is a different account
|
||||
// — an rsync over ssh, a backup agent — and a directory it cannot
|
||||
// enter looks to it exactly like an empty one. Reported as "the
|
||||
// folder arrives empty", with the invoice sitting in it the whole
|
||||
// time.
|
||||
'visibility' => 'public',
|
||||
'permissions' => [
|
||||
'file' => ['public' => 0o644, 'private' => 0o600],
|
||||
'dir' => ['public' => 0o755, 'private' => 0o700],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,3 +216,26 @@ it('does not prune a destination whose mount has gone away', function () {
|
|||
|
||||
expect(is_dir($gone))->toBeFalse();
|
||||
});
|
||||
|
||||
it('leaves the folder readable by whoever collects from it', function () {
|
||||
// Not cosmetic. mkdir's mode is masked by the process umask, and a
|
||||
// restrictive one leaves the folder 0700 — at which point the account that
|
||||
// collects (an rsync over ssh, a backup agent, anything that is not the
|
||||
// account that wrote it) cannot enter it, and an unreadable directory looks
|
||||
// exactly like an empty one. Reported as "the folder arrives empty", with
|
||||
// the invoice sitting in it the whole time.
|
||||
$invoice = anInvoice();
|
||||
$old = umask(0o077);
|
||||
|
||||
try {
|
||||
(new ArchiveInvoice($invoice, $this->target))->handle(app(InvoiceArchive::class));
|
||||
} finally {
|
||||
umask($old);
|
||||
}
|
||||
|
||||
$folder = $this->archive.'/'.now()->format('Y');
|
||||
$file = $folder.'/'.$invoice->number.'.pdf';
|
||||
|
||||
expect(substr(sprintf('%o', fileperms($folder)), -3))->toBe('755')
|
||||
->and(substr(sprintf('%o', fileperms($file)), -3))->toBe('644');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue