1 Commits

Author SHA1 Message Date
Danny Kim 7bae0d7237 Centralize encrypted bot profiles
Check / deno (pull_request) Successful in 36s
2026-09-24 05:00:02 +09:00
2 changed files with 26 additions and 6 deletions
+10 -2
View File
@@ -14,6 +14,15 @@ export function agentCommand(
});
}
export function isRunnableProfileProcess(
status: string,
uid: number,
): boolean {
const owner = status.match(/^Uid:\s+(\d+)/m)?.[1];
const state = status.match(/^State:\s+(\w)/m)?.[1];
return owner !== undefined && Number(owner) === uid && state !== "Z";
}
async function profileProcessIds(uid: number): Promise<number[]> {
const ids: number[] = [];
for await (const entry of Deno.readDir("/proc")) {
@@ -21,8 +30,7 @@ async function profileProcessIds(uid: number): Promise<number[]> {
const status = await Deno.readTextFile(`/proc/${entry.name}/status`).catch(
() => null,
);
const owner = status?.match(/^Uid:\s+(\d+)/m)?.[1];
if (owner !== undefined && Number(owner) === uid) {
if (status !== null && isRunnableProfileProcess(status, uid)) {
ids.push(Number(entry.name));
}
}
+16 -4
View File
@@ -1,6 +1,7 @@
import { assertEquals, assertRejects } from "jsr:@std/assert@1";
import {
agentCommand,
isRunnableProfileProcess,
killProfileProcesses,
readProfileFile,
} from "./isolation.ts";
@@ -16,6 +17,11 @@ const profile = (uid: number, home: string): RuntimeProfile => ({
tokenFile: null,
});
Deno.test("zombie process entries are already quiescent", () => {
const status = "State:\tZ (zombie)\nUid:\t20010\t20010\t20010\t20010\n";
assertEquals(isRunnableProfileProcess(status, 20_010), false);
});
Deno.test({
name: "refuses to read a profile result symlink as root",
permissions: { read: true, write: true, sys: ["uid"] },
@@ -81,7 +87,7 @@ Deno.test({
});
Deno.test({
name: "cleanup kills daemonized processes before returning",
name: "cleanup leaves no runnable daemonized process",
permissions: "inherit",
async fn() {
if (Deno.uid() !== 0) return;
@@ -95,9 +101,15 @@ Deno.test({
await killProfileProcesses(selected.uid);
await assertRejects(
() => Deno.stat(`/proc/${pid}`),
Deno.errors.NotFound,
const status = await Deno.readTextFile(`/proc/${pid}/status`).catch(
(error) => {
if (error instanceof Deno.errors.NotFound) return null;
throw error;
},
);
assertEquals(
status === null || !isRunnableProfileProcess(status, selected.uid),
true,
);
},
});