




















@@ -506,13 +506,24 @@ function policyDeniedResult(input: {
506506};
507507}
508508509-async function runWritePreflight(input: {
509+type PreflightResult =
510+| {
511+ok: true;
512+payload: Record<string, unknown> | null;
513+canonicalPath: string;
514+}
515+| {
516+ok: false;
517+result: OpenClawPluginNodeInvokePolicyResult;
518+};
519+520+async function invokePreflight(input: {
510521ctx: OpenClawPluginNodeInvokePolicyContext;
511522op: FileTransferAuditOp;
512523params: Record<string, unknown>;
513524requestedPath: string;
514525startedAt: number;
515-}): Promise<OpenClawPluginNodeInvokePolicyResult | null> {
526+}): Promise<PreflightResult> {
516527const nodeDisplayName = input.ctx.node?.displayName;
517528const preflight = await input.ctx.invokeNode({
518529params: {
@@ -533,10 +544,13 @@ async function runWritePreflight(input: {
533544});
534545return {
535546ok: false,
536-code: preflight.code,
537-message: `${input.op} failed: ${preflight.message}`,
538-details: preflight.details,
539-unavailable: true,
547+result: {
548+ok: false,
549+code: preflight.code,
550+message: `${input.op} failed: ${preflight.message}`,
551+details: preflight.details,
552+unavailable: true,
553+},
540554};
541555}
542556@@ -553,108 +567,39 @@ async function runWritePreflight(input: {
553567errorMessage: typeof payload.message === "string" ? payload.message : undefined,
554568durationMs: Date.now() - input.startedAt,
555569});
556-return preflight;
570+return { ok: false, result: preflight };
557571}
558572559573const canonicalPath =
560574payload && typeof payload.path === "string" && payload.path
561575 ? payload.path
562576 : input.requestedPath;
563-if (canonicalPath === input.requestedPath) {
564-return null;
565-}
566-567-const policy = evaluateFilePolicy({
568-nodeId: input.ctx.nodeId,
569- nodeDisplayName,
570-kind: "write",
571-path: canonicalPath,
572-pluginConfig: input.ctx.pluginConfig,
573-});
574-if (policy.ok) {
575-return null;
576-}
577-578-await appendFileTransferAudit({
579-op: input.op,
580-nodeId: input.ctx.nodeId,
581- nodeDisplayName,
582-requestedPath: input.requestedPath,
583- canonicalPath,
584-decision: "denied:symlink_escape",
585-errorCode: policy.code,
586-reason: policy.reason,
587-durationMs: Date.now() - input.startedAt,
588-});
589-return {
590-ok: false,
591-code: "SYMLINK_TARGET_DENIED",
592-message: `${input.op} SYMLINK_TARGET_DENIED: requested path resolved to ${canonicalPath} which is not allowed by policy`,
593-};
577+return { ok: true, payload, canonicalPath };
594578}
595579596-async function runFileFetchPreflight(input: {
580+async function runPathPreflight(input: {
597581ctx: OpenClawPluginNodeInvokePolicyContext;
598582op: FileTransferAuditOp;
583+kind: FilePolicyKind;
599584params: Record<string, unknown>;
600585requestedPath: string;
601586startedAt: number;
602587}): Promise<OpenClawPluginNodeInvokePolicyResult | null> {
603-const nodeDisplayName = input.ctx.node?.displayName;
604-const preflight = await input.ctx.invokeNode({
605-params: {
606- ...input.params,
607-preflightOnly: true,
608-},
609-});
588+const preflight = await invokePreflight(input);
610589if (!preflight.ok) {
611-await appendFileTransferAudit({
612-op: input.op,
613-nodeId: input.ctx.nodeId,
614- nodeDisplayName,
615-requestedPath: input.requestedPath,
616-decision: "error",
617-errorCode: preflight.code,
618-errorMessage: preflight.message,
619-durationMs: Date.now() - input.startedAt,
620-});
621-return {
622-ok: false,
623-code: preflight.code,
624-message: `${input.op} failed: ${preflight.message}`,
625-details: preflight.details,
626-unavailable: true,
627-};
590+return preflight.result;
628591}
629592630-const payload = readResultPayload(preflight);
631-if (payload?.ok === false) {
632-await appendFileTransferAudit({
633-op: input.op,
634-nodeId: input.ctx.nodeId,
635- nodeDisplayName,
636-requestedPath: input.requestedPath,
637-canonicalPath: typeof payload.canonicalPath === "string" ? payload.canonicalPath : undefined,
638-decision: "error",
639-errorCode: typeof payload.code === "string" ? payload.code : undefined,
640-errorMessage: typeof payload.message === "string" ? payload.message : undefined,
641-durationMs: Date.now() - input.startedAt,
642-});
643-return preflight;
644-}
645-646-const canonicalPath =
647-payload && typeof payload.path === "string" && payload.path
648- ? payload.path
649- : input.requestedPath;
593+const nodeDisplayName = input.ctx.node?.displayName;
594+const { canonicalPath } = preflight;
650595if (canonicalPath === input.requestedPath) {
651596return null;
652597}
653598654599const policy = evaluateFilePolicy({
655600nodeId: input.ctx.nodeId,
656601 nodeDisplayName,
657-kind: "read",
602+kind: input.kind,
658603path: canonicalPath,
659604pluginConfig: input.ctx.pluginConfig,
660605});
@@ -687,59 +632,17 @@ async function runDirFetchPreflight(input: {
687632requestedPath: string;
688633startedAt: number;
689634}): Promise<OpenClawPluginNodeInvokePolicyResult | null> {
690-const nodeDisplayName = input.ctx.node?.displayName;
691-const preflight = await input.ctx.invokeNode({
692-params: {
693- ...input.params,
694-preflightOnly: true,
695-},
696-});
635+const preflight = await invokePreflight(input);
697636if (!preflight.ok) {
698-await appendFileTransferAudit({
699-op: input.op,
700-nodeId: input.ctx.nodeId,
701- nodeDisplayName,
702-requestedPath: input.requestedPath,
703-decision: "error",
704-errorCode: preflight.code,
705-errorMessage: preflight.message,
706-durationMs: Date.now() - input.startedAt,
707-});
708-return {
709-ok: false,
710-code: preflight.code,
711-message: `${input.op} failed: ${preflight.message}`,
712-details: preflight.details,
713-unavailable: true,
714-};
715-}
716-717-const payload = readResultPayload(preflight);
718-if (payload?.ok === false) {
719-await appendFileTransferAudit({
720-op: input.op,
721-nodeId: input.ctx.nodeId,
722- nodeDisplayName,
723-requestedPath: input.requestedPath,
724-canonicalPath: typeof payload.canonicalPath === "string" ? payload.canonicalPath : undefined,
725-decision: "error",
726-errorCode: typeof payload.code === "string" ? payload.code : undefined,
727-errorMessage: typeof payload.message === "string" ? payload.message : undefined,
728-durationMs: Date.now() - input.startedAt,
729-});
730-return preflight;
637+return preflight.result;
731638}
732639733-const canonicalPath =
734-payload && typeof payload.path === "string" && payload.path
735- ? payload.path
736- : input.requestedPath;
737640return await validateDirFetchEntries({
738641ctx: input.ctx,
739642op: input.op,
740643requestedPath: input.requestedPath,
741- canonicalPath,
742-entries: payload?.entries,
644+canonicalPath: preflight.canonicalPath,
645+entries: preflight.payload?.entries,
743646startedAt: input.startedAt,
744647phase: "preflight",
745648});
@@ -780,9 +683,10 @@ async function handleFileTransferInvoke(
780683maxBytes: gate.maxBytes,
781684});
782685if (command === "file.fetch") {
783-const preflightDeny = await runFileFetchPreflight({
686+const preflightDeny = await runPathPreflight({
784687 ctx,
785688 op,
689+kind: "read",
786690params: forwardedParams,
787691 requestedPath,
788692 startedAt,
@@ -791,9 +695,10 @@ async function handleFileTransferInvoke(
791695return preflightDeny;
792696}
793697} else if (command === "file.write") {
794-const preflightDeny = await runWritePreflight({
698+const preflightDeny = await runPathPreflight({
795699 ctx,
796700 op,
701+kind: "write",
797702params: forwardedParams,
798703 requestedPath,
799704 startedAt,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。