Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"nemoclaw/openclaw.plugin.json",
"nemoclaw/package.json",
"nemoclaw-blueprint/",
"schemas/network-policy.schema.json",
"schemas/sandbox-policy.schema.json",
"scripts/",
"docs/resources/local-credential-form.html",
Expand Down
27 changes: 22 additions & 5 deletions src/lib/policy/sandbox-policy-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Ajv from "ajv/dist/2020.js";
import { parseOpenShellPolicy } from "./merge";

const PACKAGE_ROOT = path.resolve(__dirname, "..", "..", "..");
const NETWORK_POLICY_SCHEMA_PATH = path.join(PACKAGE_ROOT, "schemas", "network-policy.schema.json");
const SANDBOX_POLICY_SCHEMA_PATH = path.join(PACKAGE_ROOT, "schemas", "sandbox-policy.schema.json");
const MAX_SCHEMA_ERRORS = 3;
const MAX_SCHEMA_ERROR_MESSAGE_CHARS = 120;
Expand All @@ -20,21 +21,37 @@ let cachedSandboxPolicyValidator: ValidateFunction<unknown> | null = null;
function loadSandboxPolicyValidator(): ValidateFunction<unknown> {
if (cachedSandboxPolicyValidator) return cachedSandboxPolicyValidator;

let schema: AnySchemaObject;
let networkPolicySchema: AnySchemaObject;
let sandboxPolicySchema: AnySchemaObject;
try {
const parsed: unknown = JSON.parse(fs.readFileSync(SANDBOX_POLICY_SCHEMA_PATH, "utf-8"));
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
const parsedNetworkPolicySchema: unknown = JSON.parse(
fs.readFileSync(NETWORK_POLICY_SCHEMA_PATH, "utf-8"),
);
const parsedSandboxPolicySchema: unknown = JSON.parse(
fs.readFileSync(SANDBOX_POLICY_SCHEMA_PATH, "utf-8"),
);
if (
!parsedNetworkPolicySchema ||
typeof parsedNetworkPolicySchema !== "object" ||
Array.isArray(parsedNetworkPolicySchema) ||
!parsedSandboxPolicySchema ||
typeof parsedSandboxPolicySchema !== "object" ||
Array.isArray(parsedSandboxPolicySchema)
) {
throw new Error("schema root is not an object");
}
schema = parsed as AnySchemaObject;
networkPolicySchema = parsedNetworkPolicySchema as AnySchemaObject;
sandboxPolicySchema = parsedSandboxPolicySchema as AnySchemaObject;
} catch {
throw new Error(
"Sandbox policy validation schema is unavailable from this NemoClaw installation.",
);
}

try {
const compiled = new Ajv({ allErrors: true, strict: false, $data: true }).compile(schema);
const ajv = new Ajv({ allErrors: true, strict: false, $data: true });
ajv.addSchema(networkPolicySchema);
const compiled = ajv.compile(sandboxPolicySchema);
cachedSandboxPolicyValidator = compiled;
return compiled;
} catch {
Expand Down
3 changes: 3 additions & 0 deletions test/package-contract/openshell-policy-boundary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ describe("OpenShell policy boundary package contract", () => {
expect(fs.existsSync(path.join(installedRoot, "schemas", "sandbox-policy.schema.json"))).toBe(
true,
);
expect(fs.existsSync(path.join(installedRoot, "schemas", "network-policy.schema.json"))).toBe(
true,
);
expect(
fs.existsSync(
path.join(installedRoot, "dist", "lib", "policy", "sandbox-policy-validation.js"),
Expand Down
Loading