@@ -14,6 +14,27 @@ test("skillName derives from a git url or path, or takes an override", () => {
1414 assert . equal ( skillName ( "whatever" , "Custom Name" ) , "custom-name" ) ;
1515} ) ;
1616
17+ test ( "skillName never yields `.` or `..`, which would escape the skills dir" , ( ) => {
18+ const here = path . basename ( process . cwd ( ) ) ;
19+ const parent = path . basename ( path . dirname ( process . cwd ( ) ) ) ;
20+ assert . equal ( skillName ( "." ) , here ) ;
21+ assert . equal ( skillName ( "./" ) , here ) ;
22+ assert . equal ( skillName ( "a/b/." ) , "b" ) ;
23+ assert . equal ( skillName ( ".." ) , parent ) ;
24+ assert . equal ( skillName ( "../" ) , parent ) ;
25+ assert . equal ( skillName ( "whatever" , "." ) , "skill" ) ;
26+ assert . equal ( skillName ( "whatever" , ".." ) , "skill" ) ;
27+ } ) ;
28+
29+ test ( "the claude clone destination stays inside the skills dir" , ( ) => {
30+ const dir = claudeSkillsDir ( ) ;
31+ for ( const source of [ "." , "./" , ".." , "../" , "a/b/." ] ) {
32+ const { args } = skillInstallAction ( "claude" , { source, name : skillName ( source ) } ) ;
33+ const dest = args . at ( - 1 ) ;
34+ assert . equal ( path . dirname ( dest ) , dir , `${ source } escaped to ${ dest } ` ) ;
35+ }
36+ } ) ;
37+
1738test ( "skillInstallAction: gemini installs natively, claude clones into its skills dir" , ( ) => {
1839 const gemini = skillInstallAction ( "gemini" , { source : "https://x/y" , name : "y" } ) ;
1940 assert . deepEqual ( gemini , { cmd : "gemini" , args : [ "skills" , "install" , "https://x/y" , "--scope" , "user" ] } ) ;
0 commit comments