Replace NodeJS dict aliases with maps and named field reads

Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
This commit was merged in pull request #24.
This commit is contained in:
Danny Kim
2026-10-20 05:01:49 +00:00
committed by temeddix
parent 32806120b3
commit 063eb09750
42 changed files with 2386 additions and 982 deletions
+54 -41
View File
@@ -1,7 +1,15 @@
import { chmod, chown, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import {
chmod,
chown,
mkdir,
mkdtemp,
readFile,
rm,
writeFile,
} from "node:fs/promises";
import nodePath from "node:path";
import { isMapping } from "#common";
import { field, isMapping } from "#common";
import type { ProfileFailure, ProfileIdentity } from "#profiles";
import { parseCredentials } from "./credentials.ts";
@@ -39,7 +47,12 @@ export interface RuntimeFailure {
export type RuntimeOutcome = RuntimeSuccess | RuntimeFailure;
async function writePrivate(path: string, value: string, uid: number, gid: number): Promise<void> {
async function writePrivate(
path: string,
value: string,
uid: number,
gid: number,
): Promise<void> {
await writeFile(path, value, { mode: 0o600 });
await chmod(path, 0o600);
await chown(path, uid, gid);
@@ -51,49 +64,47 @@ export async function prepareRuntime(
masterKey: string,
): Promise<RuntimeManifest> {
const credentials = await parseCredentials(
await readFile(join(actionPath, "profiles.json"), "utf8"),
await readFile(nodePath.join(actionPath, "profiles.json"), "utf8"),
masterKey,
);
const runtimeDir = await mkdtemp(join(runtimeRoot, "bot-agents-"));
const runtimeDir = await mkdtemp(nodePath.join(runtimeRoot, "bot-agents-"));
try {
await chmod(runtimeDir, 0o711);
const reviewerFile = join(runtimeDir, "reviewer-token");
const reviewerFile = nodePath.join(runtimeDir, "reviewer-token");
await writePrivate(reviewerFile, credentials.reviewerToken, 0, 0);
// One profile at a time, in order, as each claims the next UID.
const profiles = await credentials.profiles.reduce<Promise<RuntimeProfile[]>>(
async (previous, profile, index) => {
const prepared = await previous;
const uid = FIRST_PROFILE_UID + index;
const home = join(runtimeDir, `profile-${index}`);
await mkdir(home, { mode: 0o700 });
await chmod(home, 0o700);
await chown(home, uid, uid);
const tokenFile =
profile.token === undefined || profile.token === "" ? null : join(home, "token");
if (tokenFile !== null && profile.token !== undefined) {
await writePrivate(tokenFile, profile.token, uid, uid);
}
prepared.push({
index,
type: profile.type,
model: profile.model,
uid,
gid: uid,
home,
tokenFile,
});
return prepared;
},
Promise.resolve([]),
);
const profiles: RuntimeProfile[] = [];
for (const [index, profile] of credentials.profiles.entries()) {
const uid = FIRST_PROFILE_UID + index;
const home = nodePath.join(runtimeDir, `profile-${index}`);
await mkdir(home, { mode: 0o700 });
await chmod(home, 0o700);
await chown(home, uid, uid);
const tokenFile =
profile.token === undefined || profile.token === ""
? null
: nodePath.join(home, "token");
if (tokenFile !== null && profile.token !== undefined) {
await writePrivate(tokenFile, profile.token, uid, uid);
}
profiles.push({
index,
type: profile.type,
model: profile.model,
uid,
gid: uid,
home,
tokenFile,
});
}
const manifestPath = join(runtimeDir, "manifest.json");
const manifestPath = nodePath.join(runtimeDir, "manifest.json");
const manifest: RuntimeManifest = {
runtimeDir,
manifestPath,
reviewerFile,
outcomeFile: join(runtimeDir, "outcome.json"),
outcomeFile: nodePath.join(runtimeDir, "outcome.json"),
profiles,
};
await writePrivate(manifestPath, JSON.stringify(manifest), 0, 0);
@@ -107,15 +118,17 @@ export async function prepareRuntime(
function isRuntimeManifest(value: unknown): value is RuntimeManifest {
return (
isMapping(value) &&
typeof value["runtimeDir"] === "string" &&
typeof value["manifestPath"] === "string" &&
typeof value["reviewerFile"] === "string" &&
typeof value["outcomeFile"] === "string" &&
Array.isArray(value["profiles"])
typeof field(value, "runtimeDir") === "string" &&
typeof field(value, "manifestPath") === "string" &&
typeof field(value, "reviewerFile") === "string" &&
typeof field(value, "outcomeFile") === "string" &&
Array.isArray(field(value, "profiles"))
);
}
export async function readRuntimeManifest(path: string): Promise<RuntimeManifest> {
export async function readRuntimeManifest(
path: string,
): Promise<RuntimeManifest> {
const value: unknown = JSON.parse(await readFile(path, "utf8"));
if (!isRuntimeManifest(value)) {
throw new Error(`${path}: invalid runtime manifest`);