fix: dot segments and doubled slashes cannot spell around the data folder refusals (release review)

The refusals of $HOME, ~/.codeman and the checkout compare strings, so
`~/../me` or `<repo>/../repo/data` passed them: the first shares state with a
native install, the second lands in the build context, where `COPY . .` would
bake CLI logins into the image. Doubled slashes are collapsed and any `.` or
`..` segment is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-06 04:29:51 +01:00
1 parent 7ada939182
commit f41e0cc6d4
2 files changed
+24

No files matched your search

+13
View File
@@ -343,6 +343,13 @@ describe('Start-Codeman.sh first run (no docker/.env yet)', () => {
['a relative path', () => 'codeman-data', /absolute path/],
['the checkout, which is the image build context', ({ repo }: { repo: string }) => repo, /copied into the image/],
['a folder inside the checkout', ({ repo }: { repo: string }) => join(repo, 'data'), /copied into the image/],
// join() would resolve these, which is the whole point: the refusals above compare strings.
['HOME spelled through ..', ({ home }: { home: string }) => `${home}/../home`, /without \. or \.\./],
['the checkout spelled through ..', ({ home }: { home: string }) => `${home}/../repo/data`, /without \. or \.\./],
['a path ending in ..', ({ home }: { home: string }) => `${home}/data/..`, /without \. or \.\./],
['a native install spelled through .', ({ home }: { home: string }) => `${home}/./.codeman`, /without \. or \.\./],
['a native install behind a doubled slash', ({ home }: { home: string }) => `${home}//.codeman`, /installed directly/],
['the checkout behind a doubled slash', ({ repo }: { repo: string }) => `${repo}//data`, /copied into the image/],
])('refuses %s as the data folder and writes nothing', (_name, appdata, reason) => {
const r = runStart(['--setup-only'], { appdata });
expect(r.status).toBe(1);
@@ -402,6 +409,12 @@ describe('Start-Codeman.sh first run (no docker/.env yet)', () => {
expect(r.envKind).toBe('symlink');
});
it('keeps a folder name that merely starts with a dot or dots', () => {
const r = runStart(['--setup-only'], { appdata: ({ home }) => `${home}/..data/.state` });
expect(r.status, r.stderr).toBe(0);
expect(envValue(r.env as string, 'CODEMAN_APPDATA_PATH')).toBe(`${r.home}/..data/.state`);
});
it('never rewrites an existing docker/.env', () => {
const existing = '# hand-written\nCODEMAN_PASSWORD=mine-and-only-mine\nCODEMAN_APPDATA_PATH=/x\n';
const r = runStart(['--setup-only'], { existingEnv: existing });