Admit checked restricted artifacts without individual code approvals
This commit is contained in:
+4
-57
@@ -13,62 +13,6 @@ export async function buildService({
|
||||
recordFile,
|
||||
}) {
|
||||
const relative = compiler.artifactPath;
|
||||
if (config.restricted) {
|
||||
if (config.service.entry || pkg.exports.some((e) => e.execution.kind === "remote"))
|
||||
throw Error(
|
||||
"Restricted services require portable snapshot/transaction exports; remote/custom services keep their VM path",
|
||||
);
|
||||
const modules = implementations.filter((i) => i.target === "server");
|
||||
if (modules.length !== 1 || pkg.exports.some((e) => !modules[0].exports.includes(e.id)))
|
||||
throw Error("Restricted service requires exactly one checked portable registry covering all exports");
|
||||
const limits = config.restricted.limits;
|
||||
if (!limits || typeof limits !== "object" || Array.isArray(limits))
|
||||
throw Error("Restricted limits must be an object");
|
||||
if (Object.keys(limits).some((key) => !["deadlineMs", "maxBytes", "maxPortCalls", "maxQueued"].includes(key)))
|
||||
throw Error("Unknown restricted service limit");
|
||||
for (const [key, min, max] of [
|
||||
["deadlineMs", 1, 60000],
|
||||
["maxBytes", 1024, 4194304],
|
||||
["maxPortCalls", 1, 10000],
|
||||
["maxQueued", 0, 64],
|
||||
])
|
||||
if (limits[key] !== undefined && (!Number.isSafeInteger(limits[key]) || limits[key] < min || limits[key] > max))
|
||||
throw Error("Invalid restricted service limit " + key);
|
||||
await fs.mkdir(path.join(output, "bin"), { recursive: true });
|
||||
await fs.mkdir(path.join(output, "share/quixos/service"), { recursive: true });
|
||||
const configFile = "share/quixos/service/restricted.json";
|
||||
const module = modules[0];
|
||||
await fs.writeFile(
|
||||
path.join(output, configFile),
|
||||
JSON.stringify({
|
||||
module: path.relative("share/quixos/service", module.path),
|
||||
registryExport: module.registryExport,
|
||||
exports: module.exports,
|
||||
sdk: [{ name: config.restricted.sdk, path: config.restricted.sdk }],
|
||||
...limits,
|
||||
}),
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(output, "bin/service"),
|
||||
`#!${config.shell}\nservice_root=\${0%/*}/..\nexec ${config.restricted.runtime} "$service_root/${configFile}"\n`,
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
const body = {
|
||||
id: "service",
|
||||
target: "server",
|
||||
compatibility: "quixos-service-v1",
|
||||
path: "bin/service",
|
||||
ports: "quixos-transaction-ports-v1",
|
||||
exports: module.exports,
|
||||
files: [
|
||||
await recordFile("bin/service", "text/x-shellscript"),
|
||||
await recordFile(configFile, "application/json"),
|
||||
...module.files,
|
||||
],
|
||||
};
|
||||
implementations.unshift({ ...body, contentDigest: compiler.implementationDigest(body) });
|
||||
return;
|
||||
}
|
||||
if (pkg.exports.length || config.service.entry) {
|
||||
await fs.mkdir(path.join(output, "bin"), { recursive: true });
|
||||
await fs.mkdir(path.join(output, "share/quixos/service"), { recursive: true });
|
||||
@@ -78,7 +22,10 @@ export async function buildService({
|
||||
throw Error("Custom service entry must be JavaScript; use a separate typed/language build before packaging");
|
||||
serviceEntry = path.join(config.source, relative(config.service.entry));
|
||||
} else {
|
||||
const modules = implementations.filter((implementation) => implementation.target === "server");
|
||||
const modules = implementations.filter(
|
||||
(implementation) =>
|
||||
implementation.target === "server" && implementation.compatibility === "quixos-js-module-v1",
|
||||
);
|
||||
if (pkg.exports.some((entry) => !modules.some((module) => module.exports.includes(entry.id))))
|
||||
throw Error("Generated service does not cover every package export; provide a custom service");
|
||||
if (!modules.length) throw Error("Generated service requires a checked registry");
|
||||
|
||||
Reference in New Issue
Block a user