stop creating the container bind-mount directory too
~/.local/dockers existed only so a rootless container's inner uid could traverse to a bind source. No daemon, no need. Commented out with its reasoning intact in confineUserTree. .local itself stays — it is not Docker's. The claude installer targets ~/.local/bin, and the comment above it records that directory being created root-owned and blocking the install. Nothing to change in deprovisionOsAccount: it never called os-user-docker.ts. Its only Docker-shaped part is capturing /etc/subuid before userdel, which already treats a missing entry as normal and is worth keeping for any rootless tooling. Verified: transpiles. No test referenced composeDir. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+43
-31
@@ -369,7 +369,17 @@ export async function confineUserTree(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── One directory where container bind mounts can live ──
|
// ── One directory where container bind mounts can live: DISABLED 2026-08-13, code kept ──
|
||||||
|
//
|
||||||
|
// `~/.local/dockers` existed only for rootless Docker, and members no longer get a daemon — see the
|
||||||
|
// commented-out step in api/users/provision-os.ts. Creating a blessed bind-mount directory for a daemon
|
||||||
|
// that is not there is a promise about container storage the platform no longer keeps.
|
||||||
|
//
|
||||||
|
// `.local` itself STAYS. It is not Docker's: the `claude` installer targets `~/.local/bin`, and the
|
||||||
|
// paragraph below is the record of that directory being created root-owned and blocking it.
|
||||||
|
//
|
||||||
|
// The reasoning is kept in full because turning containers back on means uncommenting the block, not
|
||||||
|
// rediscovering why 711 and why the ACLs come off.
|
||||||
//
|
//
|
||||||
// The default ACLs above are inherited by everything created in the home afterwards, including
|
// The default ACLs above are inherited by everything created in the home afterwards, including
|
||||||
// `default:other::---`. A rootless container's INNER uid is neither the service user nor the member —
|
// `default:other::---`. A rootless container's INNER uid is neither the service user nor the member —
|
||||||
@@ -416,37 +426,39 @@ export async function confineUserTree(params: {
|
|||||||
]);
|
]);
|
||||||
if (!madeLocalDir.ok) return { ok: false, error: `could not create ${localDir}: ${madeLocalDir.out}` };
|
if (!madeLocalDir.ok) return { ok: false, error: `could not create ${localDir}: ${madeLocalDir.out}` };
|
||||||
|
|
||||||
const composeDir = join(home, '.local', 'dockers');
|
// const composeDir = join(home, '.local', 'dockers');
|
||||||
const madeComposeDir = await run([
|
// const madeComposeDir = await run([
|
||||||
'sudo',
|
// 'sudo',
|
||||||
'-n',
|
// '-n',
|
||||||
'install',
|
// 'install',
|
||||||
'-d',
|
// '-d',
|
||||||
'-o',
|
// '-o',
|
||||||
String(params.uid),
|
// String(params.uid),
|
||||||
'-g',
|
// '-g',
|
||||||
String(params.gid),
|
// String(params.gid),
|
||||||
// 711, not 700, and this is the whole point of the directory. A container's inner uid is `other`, so it
|
// // 711, not 700, and this is the whole point of the directory. A container's inner uid is `other`, so
|
||||||
// needs `x` HERE to reach a bind source inside — 700 blocks the path before any ACL matters. `r` stays
|
// // it needs `x` HERE to reach a bind source inside — 700 blocks the path before any ACL matters. `r`
|
||||||
// off, so nothing can list it. Safe because the home above is 700: no other account can traverse this
|
// // stays off, so nothing can list it. Safe because the home above is 700: no other account can
|
||||||
// far in the first place, and the only uids that get here are the member's own containers.
|
// // traverse this far in the first place, and the only uids that get here are the member's own
|
||||||
'-m',
|
// // containers.
|
||||||
'711',
|
// '-m',
|
||||||
composeDir,
|
// '711',
|
||||||
]);
|
// composeDir,
|
||||||
if (!madeComposeDir.ok) return { ok: false, error: `could not create ${composeDir}: ${madeComposeDir.out}` };
|
// ]);
|
||||||
|
// if (!madeComposeDir.ok) return { ok: false, error: `could not create ${composeDir}: ${madeComposeDir.out}` };
|
||||||
// `-b`, not `-k`: remove ACCESS entries as well as defaults, leaving plain POSIX modes.
|
|
||||||
//
|
//
|
||||||
// `-k` alone left `mask::---` behind — inherited named entries with every permission masked off, reading
|
// // `-b`, not `-k`: remove ACCESS entries as well as defaults, leaving plain POSIX modes.
|
||||||
// as `user:pastilhas:rwx #effective:---`. An ACL that says one thing and means another is worse than no
|
// //
|
||||||
// ACL, and container storage is the one place in the home that wants ordinary mode bits and nothing else.
|
// // `-k` alone left `mask::---` behind — inherited named entries with every permission masked off,
|
||||||
//
|
// // reading as `user:pastilhas:rwx #effective:---`. An ACL that says one thing and means another is worse
|
||||||
// AFTER the recursive grant above, or what it just set is re-inherited here.
|
// // than no ACL, and container storage is the one place in the home that wants ordinary mode bits and
|
||||||
const stripped = await run(['sudo', '-n', 'setfacl', '-R', '-b', composeDir]);
|
// // nothing else.
|
||||||
if (!stripped.ok) {
|
// //
|
||||||
return { ok: false, error: `could not clear inherited ACLs from ${composeDir}: ${stripped.out}` };
|
// // AFTER the recursive grant above, or what it just set is re-inherited here.
|
||||||
}
|
// const stripped = await run(['sudo', '-n', 'setfacl', '-R', '-b', composeDir]);
|
||||||
|
// if (!stripped.ok) {
|
||||||
|
// return { ok: false, error: `could not clear inherited ACLs from ${composeDir}: ${stripped.out}` };
|
||||||
|
// }
|
||||||
|
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
|||||||
Reference in New Issue
Block a user