diff --git a/.changeset/secure-network-symlink-fix.md b/.changeset/secure-network-symlink-fix.md new file mode 100644 index 0000000..68d389d --- /dev/null +++ b/.changeset/secure-network-symlink-fix.md @@ -0,0 +1,5 @@ +--- +"secure-network": patch +--- + +Fix intermittent DNS failures on GitHub-hosted runners caused by /etc/resolv.conf being a symlink to a tmpfs file managed by systemd-resolved. chattr +i is a no-op on tmpfs, so systemd-resolved could overwrite the file after setup. The symlink is now removed before writing, creating a real file on /etc (ext4) that chattr can lock. diff --git a/actions/secure-network/secure-network.js b/actions/secure-network/secure-network.js index 22e1fa9..59431d8 100644 --- a/actions/secure-network/secure-network.js +++ b/actions/secure-network/secure-network.js @@ -546,6 +546,21 @@ async function main() { } console.log("Redirecting DNS to local Unbound resolver..."); + // On Ubuntu with systemd-resolved, /etc/resolv.conf is a symlink to + // /run/systemd/resolve/stub-resolv.conf on tmpfs. Writing through the symlink + // lets systemd-resolved silently overwrite our change, and chattr +i is a + // no-op on tmpfs (unsupported filesystem). Remove any existing symlink/file + // first so we create a real file on /etc (ext4), where chattr can lock it. + try { + if (fs.lstatSync("/etc/resolv.conf").isSymbolicLink()) { + fs.unlinkSync("/etc/resolv.conf"); + console.log( + " Removed /etc/resolv.conf symlink (was managed by systemd-resolved).", + ); + } + } catch (_) { + /* not a symlink or doesn't exist — proceed */ + } fs.writeFileSync("/etc/resolv.conf", "nameserver 127.0.0.1\n"); // resolv.conf.bak is kept until process exit; the exit handler restores it on error.