Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/JAVA/Openclaw/src/infra/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 6 kB image not shown  

Quelle  boundary-path.test.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { withTempDir } from "../test-helpers/temp-dir.js";
import { resolveBoundaryPath, resolveBoundaryPathSync } from "./boundary-path.js";
import { isPathInside } from "./path-guards.js";

function createSeededRandom(seed: number): () => number {
  let state = seed >>> 0;
  return () => {
    state = (state * 1664525 + 1013904223) >>> 0;
    return state / 0x100000000;
  };
}

describe("resolveBoundaryPath", () => {
  it("resolves symlink parents with non-existent leafs inside root", async () => {
    if (process.platform === "win32") {
      return;
    }

    await withTempDir({ prefix: "openclaw-boundary-path-" }, async (base) => {
      const root = path.join(base, "workspace");
      const targetDir = path.join(root, "target-dir");
      const linkPath = path.join(root, "alias");
      await fs.mkdir(targetDir, { recursive: true });
      await fs.symlink(targetDir, linkPath);

      const unresolved = path.join(linkPath, "missing.txt");
      const result = await resolveBoundaryPath({
        absolutePath: unresolved,
        rootPath: root,
        boundaryLabel: "sandbox root",
      });

      const targetReal = await fs.realpath(targetDir);
      expect(result.exists).toBe(false);
      expect(result.kind).toBe("missing");
      expect(result.canonicalPath).toBe(path.join(targetReal, "missing.txt"));
      expect(isPathInside(result.rootCanonicalPath, result.canonicalPath)).toBe(true);
    });
  });

  it("blocks dangling symlink leaf escapes outside root", async () => {
    if (process.platform === "win32") {
      return;
    }

    await withTempDir({ prefix: "openclaw-boundary-path-" }, async (base) => {
      const root = path.join(base, "workspace");
      const outside = path.join(base, "outside");
      const linkPath = path.join(root, "alias-out");
      await fs.mkdir(root, { recursive: true });
      await fs.mkdir(outside, { recursive: true });
      await fs.symlink(outside, linkPath);
      const dangling = path.join(linkPath, "missing.txt");

      await expect(
        resolveBoundaryPath({
          absolutePath: dangling,
          rootPath: root,
          boundaryLabel: "sandbox root",
        }),
      ).rejects.toThrow(/Symlink escapes sandbox root/i);
      expect(() =>
        resolveBoundaryPathSync({
          absolutePath: dangling,
          rootPath: root,
          boundaryLabel: "sandbox root",
        }),
      ).toThrow(/Symlink escapes sandbox root/i);
    });
  });

  it("allows final symlink only when unlink policy opts in", async () => {
    if (process.platform === "win32") {
      return;
    }

    await withTempDir({ prefix: "openclaw-boundary-path-" }, async (base) => {
      const root = path.join(base, "workspace");
      const outside = path.join(base, "outside");
      const outsideFile = path.join(outside, "target.txt");
      const linkPath = path.join(root, "link.txt");
      await fs.mkdir(root, { recursive: true });
      await fs.mkdir(outside, { recursive: true });
      await fs.writeFile(outsideFile, "x", "utf8");
      await fs.symlink(outsideFile, linkPath);

      await expect(
        resolveBoundaryPath({
          absolutePath: linkPath,
          rootPath: root,
          boundaryLabel: "sandbox root",
        }),
      ).rejects.toThrow(/Symlink escapes sandbox root/i);

      const allowed = await resolveBoundaryPath({
        absolutePath: linkPath,
        rootPath: root,
        boundaryLabel: "sandbox root",
        policy: { allowFinalSymlinkForUnlink: true },
      });
      const rootReal = await fs.realpath(root);
      expect(allowed.exists).toBe(true);
      expect(allowed.kind).toBe("symlink");
      expect(allowed.canonicalPath).toBe(path.join(rootReal, "link.txt"));
    });
  });

  it("allows canonical aliases that still resolve inside root", async () => {
    if (process.platform === "win32") {
      return;
    }

    await withTempDir({ prefix: "openclaw-boundary-path-" }, async (base) => {
      const root = path.join(base, "workspace");
      const aliasRoot = path.join(base, "workspace-alias");
      const fileName = "plugin.js";
      await fs.mkdir(root, { recursive: true });
      await fs.writeFile(path.join(root, fileName), "export default {}", "utf8");
      await fs.symlink(root, aliasRoot);

      const resolved = await resolveBoundaryPath({
        absolutePath: path.join(aliasRoot, fileName),
        rootPath: await fs.realpath(root),
        boundaryLabel: "plugin root",
      });
      expect(resolved.exists).toBe(true);
      expect(isPathInside(resolved.rootCanonicalPath, resolved.canonicalPath)).toBe(true);

      const resolvedSync = resolveBoundaryPathSync({
        absolutePath: path.join(aliasRoot, fileName),
        rootPath: await fs.realpath(root),
        boundaryLabel: "plugin root",
      });
      expect(resolvedSync.exists).toBe(true);
      expect(isPathInside(resolvedSync.rootCanonicalPath, resolvedSync.canonicalPath)).toBe(true);
    });
  });

  it("maintains containment invariant across randomized alias cases", async () => {
    if (process.platform === "win32") {
      return;
    }

    await withTempDir({ prefix: "openclaw-boundary-path-fuzz-" }, async (base) => {
      const root = path.join(base, "workspace");
      const outside = path.join(base, "outside");
      const safeTarget = path.join(root, "safe-target");
      const safeRealBase = path.join(root, "safe-real");
      const safeLinkBase = path.join(root, "safe-link");
      const escapeLink = path.join(root, "escape-link");
      await fs.mkdir(root, { recursive: true });
      await fs.mkdir(outside, { recursive: true });
      await fs.mkdir(safeTarget, { recursive: true });
      await fs.mkdir(safeRealBase, { recursive: true });
      await fs.symlink(safeTarget, safeLinkBase);
      await fs.symlink(outside, escapeLink);

      const rand = createSeededRandom(0x5eed1234);
      const fuzzCases = 32;
      for (let idx = 0; idx < fuzzCases; idx += 1) {
        const token = Math.floor(rand() * 1_000_000)
          .toString(16)
          .padStart(5, "0");
        const useLink = rand() > 0.5;
        const safeBase = useLink ? safeLinkBase : safeRealBase;
        const safeCandidate = path.join(safeBase, `new-${token}.txt`);
        const safeResolved = await resolveBoundaryPath({
          absolutePath: safeCandidate,
          rootPath: root,
          boundaryLabel: "sandbox root",
        });
        expect(isPathInside(safeResolved.rootCanonicalPath, safeResolved.canonicalPath)).toBe(true);

        const unsafeCandidate = path.join(escapeLink, `new-${token}.txt`);
        await expect(
          resolveBoundaryPath({
            absolutePath: unsafeCandidate,
            rootPath: root,
            boundaryLabel: "sandbox root",
          }),
        ).rejects.toThrow(/Symlink escapes sandbox root/i);
      }
    });
  });
});

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.