chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
export type ProviderKind = "vulnerability" | "provenance";
|
||||
|
||||
const MEMORY_MAX = 1_073_741_824;
|
||||
const TASKS_MAX = 64;
|
||||
const STOP_TIMEOUT_MS = 5_000;
|
||||
const RUNTIME_GRACE_MS = 10_000;
|
||||
const UNIT_NAME = /^ca-provider-(?:vulnerability|provenance)-[1-9][0-9]*-[0-9a-f]{24}\.scope$/u;
|
||||
const UNIT_NONCE = /^[0-9a-f]{24}$/u;
|
||||
const ENVIRONMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
||||
const ENFORCEMENT_GATE = [
|
||||
'cgroup_path=""',
|
||||
"while IFS=: read -r hierarchy controllers candidate; do",
|
||||
' if [ "$hierarchy" = 0 ] && [ -z "$controllers" ]; then cgroup_path=$candidate; fi',
|
||||
"done < /proc/self/cgroup",
|
||||
'if [ -z "$cgroup_path" ]; then',
|
||||
" printf '%s\\n' 'provider cgroup enforcement failed: unified cgroup v2 membership is required' >&2",
|
||||
" exit 125",
|
||||
"fi",
|
||||
'case "$cgroup_path" in',
|
||||
' */"$0") ;;',
|
||||
" *)",
|
||||
" printf '%s\\n' 'provider cgroup enforcement failed: unit membership is invalid' >&2",
|
||||
" exit 125",
|
||||
" ;;",
|
||||
"esac",
|
||||
"cgroup_root=/sys/fs/cgroup$cgroup_path",
|
||||
"require_cgroup_value() {",
|
||||
' actual=$(/bin/cat "$cgroup_root/$1") || {',
|
||||
" printf 'provider cgroup enforcement failed: cannot read %s\\n' \"$1\" >&2",
|
||||
" exit 125",
|
||||
" }",
|
||||
' if [ "$actual" != "$2" ]; then',
|
||||
" printf 'provider cgroup enforcement failed: %s is %s, expected %s\\n' \"$1\" \"$actual\" \"$2\" >&2",
|
||||
" exit 125",
|
||||
" fi",
|
||||
"}",
|
||||
`require_cgroup_value memory.max ${MEMORY_MAX}`,
|
||||
"require_cgroup_value memory.swap.max 0",
|
||||
`require_cgroup_value pids.max ${TASKS_MAX}`,
|
||||
"require_cgroup_value cpu.max '100000 100000'",
|
||||
'exec "$@"',
|
||||
].join("\n");
|
||||
|
||||
export function formatProviderCgroupUnitName(
|
||||
kind: ProviderKind,
|
||||
supervisorPid: number,
|
||||
nonce: string,
|
||||
): string {
|
||||
if (!Number.isSafeInteger(supervisorPid) || supervisorPid <= 0 || !UNIT_NONCE.test(nonce)) {
|
||||
throw new TypeError("provider cgroup unit identity is invalid");
|
||||
}
|
||||
const unit = `ca-provider-${kind}-${supervisorPid}-${nonce}.scope`;
|
||||
assertUnit(unit);
|
||||
return unit;
|
||||
}
|
||||
|
||||
export function systemdRunProviderArguments(
|
||||
unit: string,
|
||||
timeoutMs: number,
|
||||
cpuSeconds: number,
|
||||
nodeExecutable: string,
|
||||
wrapperScript: string,
|
||||
reportPath: string,
|
||||
reportDev: number,
|
||||
reportIno: number,
|
||||
): string[] {
|
||||
assertUnit(unit);
|
||||
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > Number.MAX_SAFE_INTEGER - RUNTIME_GRACE_MS) {
|
||||
throw new TypeError("provider cgroup runtime is invalid");
|
||||
}
|
||||
if (!Number.isSafeInteger(cpuSeconds) || cpuSeconds <= 0) {
|
||||
throw new TypeError("provider cgroup CPU limit is invalid");
|
||||
}
|
||||
if (
|
||||
!nodeExecutable.startsWith("/") || !wrapperScript.startsWith("/") ||
|
||||
!reportPath.startsWith("/") || reportPath.includes("\0") ||
|
||||
!Number.isSafeInteger(reportDev) || reportDev <= 0 ||
|
||||
!Number.isSafeInteger(reportIno) || reportIno <= 0
|
||||
) {
|
||||
throw new TypeError("provider scope wrapper path is invalid");
|
||||
}
|
||||
return [
|
||||
"--user",
|
||||
"--scope",
|
||||
"--collect",
|
||||
"--quiet",
|
||||
"--expand-environment=no",
|
||||
`--unit=${unit}`,
|
||||
`--property=MemoryMax=${MEMORY_MAX}`,
|
||||
"--property=MemorySwapMax=0",
|
||||
`--property=TasksMax=${TASKS_MAX}`,
|
||||
"--property=CPUQuota=100%",
|
||||
"--property=CPUQuotaPeriodSec=100ms",
|
||||
"--property=KillMode=control-group",
|
||||
"--property=SendSIGKILL=yes",
|
||||
`--property=TimeoutStopSec=${STOP_TIMEOUT_MS}ms`,
|
||||
`--property=RuntimeMaxSec=${timeoutMs + RUNTIME_GRACE_MS}ms`,
|
||||
"--",
|
||||
"/bin/sh",
|
||||
"-eu",
|
||||
"-c",
|
||||
ENFORCEMENT_GATE,
|
||||
unit,
|
||||
nodeExecutable,
|
||||
wrapperScript,
|
||||
String(cpuSeconds),
|
||||
reportPath,
|
||||
String(reportDev),
|
||||
String(reportIno),
|
||||
];
|
||||
}
|
||||
|
||||
export type ProviderScopeFrame = Readonly<{
|
||||
bwrapInput: Buffer;
|
||||
reportPath: string;
|
||||
reportDev: number;
|
||||
reportIno: number;
|
||||
}>;
|
||||
|
||||
export function encodeProviderScopeFrame(input: ProviderScopeFrame): Buffer {
|
||||
if (
|
||||
!Buffer.isBuffer(input.bwrapInput) || input.bwrapInput.byteLength === 0 ||
|
||||
!input.reportPath.startsWith("/") || input.reportPath.includes("\0") ||
|
||||
!Number.isSafeInteger(input.reportDev) || input.reportDev <= 0 ||
|
||||
!Number.isSafeInteger(input.reportIno) || input.reportIno <= 0
|
||||
) {
|
||||
throw new TypeError("provider scope frame is invalid");
|
||||
}
|
||||
const payload = Buffer.from(JSON.stringify({
|
||||
bwrapInputBase64: input.bwrapInput.toString("base64"),
|
||||
reportPath: input.reportPath,
|
||||
reportDev: input.reportDev,
|
||||
reportIno: input.reportIno,
|
||||
}));
|
||||
const frame = Buffer.allocUnsafe(4 + payload.byteLength);
|
||||
frame.writeUInt32BE(payload.byteLength, 0);
|
||||
payload.copy(frame, 4);
|
||||
return frame;
|
||||
}
|
||||
|
||||
export function encodeProviderBwrapInput(
|
||||
arguments_: readonly string[],
|
||||
environment: Readonly<Record<string, string | undefined>>,
|
||||
): Buffer {
|
||||
if (arguments_.some((argument) => argument.includes("\0"))) {
|
||||
throw new TypeError("provider bwrap argument is invalid");
|
||||
}
|
||||
const entries = Object.entries(environment).sort(([left], [right]) =>
|
||||
left < right ? -1 : left > right ? 1 : 0,
|
||||
);
|
||||
if (entries.some(([name, value]) =>
|
||||
!ENVIRONMENT_NAME.test(name) || value === undefined || value.includes("\0")
|
||||
)) {
|
||||
throw new TypeError("provider bwrap environment is invalid");
|
||||
}
|
||||
const input = ["--clearenv"];
|
||||
for (const [name, value] of entries) input.push("--setenv", name, value ?? "");
|
||||
input.push(...arguments_);
|
||||
return Buffer.from(`${input.join("\0")}\0`);
|
||||
}
|
||||
|
||||
export function systemctlKillProviderArguments(unit: string): string[] {
|
||||
assertUnit(unit);
|
||||
return ["--user", "kill", "--kill-whom=all", "--signal=SIGKILL", unit];
|
||||
}
|
||||
|
||||
function assertUnit(unit: string): void {
|
||||
if (!UNIT_NAME.test(unit)) throw new TypeError("provider cgroup unit name is invalid");
|
||||
}
|
||||
Reference in New Issue
Block a user