11import fs from "node:fs/promises" ;
22import os from "node:os" ;
33import path from "node:path" ;
4- import { afterEach , describe , expect , it } from "vitest" ;
4+ import { afterEach , describe , expect , it , vi } from "vitest" ;
5+ import { resetLogger , setLoggerOverride } from "../logging/logger.js" ;
6+ import { loggingState } from "../logging/state.js" ;
57import { withPathResolutionEnv } from "../test-utils/env.js" ;
68import { writeSkill } from "./skills.e2e-test-helpers.js" ;
79import { loadWorkspaceSkillEntries } from "./skills.js" ;
@@ -21,6 +23,9 @@ function withWorkspaceHome<T>(workspaceDir: string, cb: () => T): T {
2123}
2224
2325afterEach ( async ( ) => {
26+ setLoggerOverride ( null ) ;
27+ loggingState . rawConsole = null ;
28+ resetLogger ( ) ;
2429 await Promise . all (
2530 tempDirs . splice ( 0 , tempDirs . length ) . map ( ( dir ) => fs . rm ( dir , { recursive : true , force : true } ) ) ,
2631 ) ;
@@ -282,14 +287,32 @@ describe("loadWorkspaceSkillEntries", () => {
282287 description : "Outside" ,
283288 } ) ;
284289 await fs . mkdir ( path . join ( workspaceDir , "skills" ) , { recursive : true } ) ;
285- await fs . symlink ( escapedSkillDir , path . join ( workspaceDir , "skills" , "escaped-skill" ) , "dir" ) ;
290+ const requestedPath = path . join ( workspaceDir , "skills" , "escaped-skill" ) ;
291+ await fs . symlink ( escapedSkillDir , requestedPath , "dir" ) ;
292+ setLoggerOverride ( { level : "silent" , consoleLevel : "warn" } ) ;
293+ const warn = vi . fn ( ) ;
294+ loggingState . rawConsole = {
295+ log : vi . fn ( ) ,
296+ info : vi . fn ( ) ,
297+ warn,
298+ error : vi . fn ( ) ,
299+ } ;
286300
287301 const entries = loadWorkspaceSkillEntries ( workspaceDir , {
288302 managedSkillsDir : path . join ( workspaceDir , ".managed" ) ,
289303 bundledSkillsDir : path . join ( workspaceDir , ".bundled" ) ,
290304 } ) ;
291305
292306 expect ( entries . map ( ( entry ) => entry . skill . name ) ) . not . toContain ( "outside-skill" ) ;
307+ const [ line ] = warn . mock . calls [ 0 ] ?? [ ] ;
308+ const warningLine = String ( line ) ;
309+ expect ( warningLine ) . toContain (
310+ "Skipping skill path that resolves outside its configured root:" ,
311+ ) ;
312+ expect ( warningLine ) . toContain ( "source=openclaw-workspace" ) ;
313+ expect ( warningLine ) . toContain ( `root=${ path . join ( workspaceDir , "skills" ) } ` ) ;
314+ expect ( warningLine ) . toContain ( `requested=${ requestedPath } ` ) ;
315+ expect ( warningLine ) . toContain ( "resolved=" ) ;
293316 } ,
294317 ) ;
295318
0 commit comments