fix: firstboot fstab handling — no duplicates, compatible with Asahi sed
Some checks failed
CI/CD / typecheck (push) Failing after 10s
CI/CD / test (push) Failing after 11s
CI/CD / lint (push) Failing after 23s
CI/CD / build (push) Has been skipped
CI/CD / publish-rpm (push) Has been skipped
CI/CD / publish-deb (push) Has been skipped

- Replace sed with grep -v / awk for fstab manipulation (Asahi Fedora's
  sed doesn't support \| delimiter or \? quantifier)
- Use idempotent write_lab_fstab function: removes all old entries first,
  comments out conflicting btrfs subvol entries, adds fresh LVM entries
- Fix sed for SSH hardening: use #* instead of \? (POSIX compatible)
- Tested on Mac Studio: no duplicate fstab entries after multiple runs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michal
2026-04-01 15:40:29 +01:00
parent 87e09af941
commit c49a650888
4 changed files with 37 additions and 25 deletions

View File

@@ -17,7 +17,7 @@ export const enableIscsi: Operation = async (ctx): Promise<OperationResult> => {
const isFedora = osLower.includes("fedora") || osLower.includes("rhel") || osLower.includes("centos");
const pkg = isFedora ? "iscsi-initiator-utils" : "open-iscsi";
const installCmd = isFedora ? `dnf install -y ${pkg}` : `apt-get install -y ${pkg}`;
const installCmd = isFedora ? `sudo dnf install -y ${pkg}` : `sudo apt-get install -y ${pkg}`;
const install = await ctx.ssh.exec(installCmd, { timeoutMs: 120_000 });
if (install.exitCode !== 0) {
@@ -25,7 +25,7 @@ export const enableIscsi: Operation = async (ctx): Promise<OperationResult> => {
}
// Enable and start
await ctx.ssh.exec("systemctl enable --now iscsid", sshOpts(ctx));
await ctx.ssh.exec("sudo systemctl enable --now iscsid", sshOpts(ctx));
return { success: true, changed: true, message: `Installed ${pkg} and enabled iscsid` };
};

View File

@@ -9,8 +9,9 @@ function isServerRole(role: string): boolean {
function generateServerConfig(config: K3sConfig): string {
const tlsSans = [config.hostname, config.ip, ...(config.tlsSans ?? [])];
const serverLine = config.k3sServerUrl ? `server: "${config.k3sServerUrl}"\ntoken: "${config.k3sToken}"\n` : "";
return `# k3s server configuration — CIS hardened
protect-kernel-defaults: true
${serverLine}protect-kernel-defaults: true
secrets-encryption: true
write-kubeconfig-mode: "0640"

View File

@@ -15,8 +15,12 @@ export const installK3sBinary: Operation = async (ctx): Promise<OperationResult>
const alreadyInstalled = version.exitCode === 0;
if (isServer) {
// If joining an existing cluster, pass K3S_URL and K3S_TOKEN
const joinEnv = ctx.config.k3sServerUrl && ctx.config.k3sToken
? `K3S_URL="${ctx.config.k3sServerUrl}" K3S_TOKEN="${ctx.config.k3sToken}"`
: "";
const result = await ctx.ssh.exec(
'curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" INSTALL_K3S_SKIP_SELINUX_RPM=true sh -',
`curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" INSTALL_K3S_SKIP_SELINUX_RPM=true ${joinEnv} sh -`,
{ timeoutMs: 300_000 },
);
if (result.exitCode !== 0) {