bun run doctor, and provisioning checks its own work
the tenth install in a row with something new wrong, and the pattern behind them is not the individual faults. every step in provisionOsAccount is deliberately non-fatal — a member whose account provisioned fine should not be rolled back because their shell config failed. that is right, and it means "nothing reported an error" is a far weaker statement than it reads as. the acl-mask bug was the sharp version: a clean provisioning run, every named entry correct, and an account that could reach nothing. it was found by a person three days later, through a file browser message three steps removed from the cause. so provisioning now VERIFIES rather than assuming, and it verifies by making the same readdir the file browser makes. deliberately not by inspecting the acl: reading getfacl and reasoning about masks is exactly how this was missed, because the acl looked right. a check that tests something adjacent to the failure is how you get a green report and a broken server. a failed check is reported FIRST, ahead of keys and shells — an account that cannot read its own home is broken in a way that working ssh does not make up for. and `bun run doctor` for the nine servers that already exist: same check across every account, plus the one that is invisible by construction — a confined grant held by an account with no linux user, which sits in the table, shows as ticked in the UI, and resolves to nothing. read-only, so it is safe on a production box. exits 1, so it can gate the end of a setup run. same posture as assertPermissionTotality, except this reports instead of refusing to boot: one broken member must not stop the platform serving everyone else.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { UserRole } from 'officerdb';
|
||||
import { updateUser } from 'officerdb';
|
||||
import { ensureOsUser, hardenOwnerHome, osUserHome, reassertHomeMask } from '@@/os-user';
|
||||
import { checkOsAccount } from '@@/os-user-verify';
|
||||
import { provisionSshAccess } from '@@/os-user-ssh';
|
||||
import { seedShellConfig } from '@@/os-user-shell';
|
||||
import { provisionClaudeCli } from '@@/os-user-claude';
|
||||
@@ -140,6 +141,18 @@ export async function provisionOsAccount(params: {
|
||||
const mask = await reassertHomeMask(osUserHome(params.email));
|
||||
if (!mask.ok) console.warn(`[users] ${params.email}: ${mask.error}`);
|
||||
|
||||
// And then CHECK it, rather than trusting that no step reported failure.
|
||||
//
|
||||
// Every step above is non-fatal by design, so "nothing returned an error" is a much weaker statement
|
||||
// than it looks — the ACL-mask bug produced a clean run and an account that could reach nothing. This
|
||||
// makes the same call the file browser makes, which is the only version of the question that cannot be
|
||||
// satisfied by something merely looking correct.
|
||||
//
|
||||
// Reported first when it fails, ahead of keys and shells: an account that cannot read its own home is
|
||||
// broken in a way that no amount of working SSH makes up for.
|
||||
const verified = await checkOsAccount(params.email, account.osUser);
|
||||
if (!verified.ok) console.warn(`[provision] ${params.email}: ${verified.problem}`);
|
||||
|
||||
// The Linux account is recorded either way: it exists, it is confined, and a member's terminal can run as
|
||||
// it. Only the keys are missing, and that is what the error says.
|
||||
const sshPublicKey = ssh.ok ? ssh.publicKey : null;
|
||||
@@ -151,16 +164,18 @@ export async function provisionOsAccount(params: {
|
||||
for (const step of [claude, shell, postgres, docker]) {
|
||||
if (step && !step.ok) console.warn(`[users] ${params.email}: ${step.error}`);
|
||||
}
|
||||
const error = !ssh.ok
|
||||
? ssh.error
|
||||
: !claude.ok
|
||||
? claude.error
|
||||
: !shell.ok
|
||||
? shell.error
|
||||
: postgres && !postgres.ok
|
||||
? postgres.error
|
||||
: docker && !docker.ok
|
||||
? docker.error
|
||||
: null;
|
||||
const error = !verified.ok
|
||||
? verified.problem
|
||||
: !ssh.ok
|
||||
? ssh.error
|
||||
: !claude.ok
|
||||
? claude.error
|
||||
: !shell.ok
|
||||
? shell.error
|
||||
: postgres && !postgres.ok
|
||||
? postgres.error
|
||||
: docker && !docker.ok
|
||||
? docker.error
|
||||
: null;
|
||||
return { osUser: account.osUser, sshPublicKey, error };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user