fix(files): the editor never reaches Codeman's own .env by another spelling, and a save keeps the file's group (#797)

The four review items of #797, applied at merge.

The editor's name rule lowercases, the data dir's .env pattern did not:
.codeman/.ENV passed both, and on a case-insensitive filesystem (the macOS
default) that is ~/.codeman/.env, the login file codeman attach reads. A
session whose workspace is the home folder could open and save it. The
pattern is case-insensitive now, pinned in the blocklist table and on the
three editor routes.

A save writes a new file and renames it over the old one, so the file took
the server's own group: a 0640 .env owned you:www-data came back you:you
and the web server lost read access. The save now puts the old user and
group back where the account may (best effort), and the wiki says mode
and group instead of permissions.

Tests: an .env in an outside worktree is refused on edit=1 and PUT too,
now that the editor's own gate lets dotenv through; the comment on why
.env.example is blocked for downloads and attachments is back.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-11 20:25:37 +01:00
1 parent 18b309fc02
commit 59d4bbca2d
7 files changed
+89 -6

No files matched your search

+9
View File
@@ -25,6 +25,10 @@ const dotenvPaths: Array<[string, string]> = [
['dotenv', '/srv/app/.env'],
['local dotenv', '/srv/app/.env.local'],
['suffixed dotenv', '/srv/app/.env.production'],
// Deliberate: `.env.*` is blocked wholesale for downloads and attachments, so even a
// committed `.env.example` is refused rather than risking the one repo whose "example"
// holds a live key. Only the File Viewer editor lifts it (`allowDotenv`), and only for
// a file the same user already reads in the preview.
['a dotenv example', '/srv/app/.env.example'],
['nested dotenv', '/srv/app/sub/dir/.env'],
];
@@ -151,6 +155,11 @@ describe('isSensitivePath', () => {
'/home/u/.codeman-dev/.env',
'/home/u/.codeman-beta/.env',
'/srv/x/.codeman/.env',
// The editor's name rule lowercases, and on a case-insensitive filesystem (the macOS
// default) these two ARE the file above.
'/home/u/.codeman/.ENV',
'/home/u/.CODEMAN/.env',
'/home/u/.Codeman-Dev/.Env',
])('blocks %s', (path) => {
expect(isSensitivePath(path, options)).toBe(true);
});