#!/usr/bin/env bun
/**
* stig self-hosted runner.
*
* STIG_URL=https://forge.example.com STIG_RUNNER_TOKEN=stig_runner_... bun runner/stig-runner.ts
*
* Polls the forge for queued jobs whose `runs-on` labels match, executes the generated job script
* with bash, streams logs back and uploads artifacts. Requires bash, git and tar on the host.
*/
import { spawn } from "node:child_process";
import { mkdir, rm, stat, writeFile, readFile } from "node:fs/promises";
import { hostname, tmpdir } from "node:os";
import { join } from "node:path";
type ClaimedJob = {
id: string;
name: string;
repository: string;
timeoutMinutes: number;
script: string;
env: Record<string, string>;
};
const SERVER = requireEnv("STIG_URL").replace(/\/$/, "");
const TOKEN = requireEnv("STIG_RUNNER_TOKEN");
const LABELS = (process.env.STIG_RUNNER_LABELS ?? "")
.split(",")
.map((label) => label.trim())
.filter(Boolean);
const WORK_ROOT = process.env.STIG_RUNNER_WORKDIR ?? join(tmpdir(), "stig-runner");
const IDLE_POLL_MS = 5000;
const ERROR_BACKOFF_MS = 15_000;
const LOG_FLUSH_MS = 1000;
const MAX_LOG_CHUNK = 512 * 1024;
const ARTIFACT_MARKER = /^::stig::artifact (\S+) "?(.+?)"?$/;
const KILL_GRACE_MS = 15_000;
const HTTP_NO_CONTENT = 204;
function requireEnv(name: string): string {
const value = process.env[name];