@@ -165,3 +165,86 @@ func TestLinuxAbsentSSHKeyRefusesCommandBeforeCreation(t *testing.T) {
165165 })
166166 }
167167}
168+
169+ func TestSSHDiscoverySymlinkDirectoryBounds (t * testing.T ) {
170+ t .Run ("symlink directory limit exceeded" , func (t * testing.T ) {
171+ sshDir := filepath .Join (t .TempDir (), ".ssh" )
172+ mustWriteFile (t , filepath .Join (sshDir , "known_hosts" ), "example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." )
173+ external := t .TempDir ()
174+ curr := external
175+ for i := 0 ; i <= sshSymlinkMaxDirs ; i ++ {
176+ curr = filepath .Join (curr , fmt .Sprintf ("dir-%03d" , i ))
177+ if err := os .Mkdir (curr , 0700 ); err != nil {
178+ t .Fatal (err )
179+ }
180+ }
181+ if err := os .Symlink (external , filepath .Join (sshDir , "link" )); err != nil {
182+ t .Fatal (err )
183+ }
184+ scanner := & sshDiscovery {}
185+ _ = scanner .walkPrivateKeyFiles (sshDir )
186+ if len (scanner .errors ) == 0 {
187+ t .Fatal ("expected discovery error for symlink directory limit exceeded, got none" )
188+ }
189+ var matched bool
190+ for _ , e := range scanner .errors {
191+ if strings .Contains (e , "symlink directory limit exceeded" ) {
192+ matched = true
193+ break
194+ }
195+ }
196+ if ! matched {
197+ t .Fatalf ("expected symlink directory limit exceeded, got %v" , scanner .errors )
198+ }
199+ })
200+
201+ t .Run ("symlink entry limit exceeded" , func (t * testing.T ) {
202+ sshDir := filepath .Join (t .TempDir (), ".ssh" )
203+ if err := os .MkdirAll (sshDir , 0700 ); err != nil {
204+ t .Fatal (err )
205+ }
206+ external := t .TempDir ()
207+ for i := 0 ; i <= sshSymlinkMaxEntries ; i ++ {
208+ mustWriteFile (t , filepath .Join (external , fmt .Sprintf ("file-%04d" , i )), "data" )
209+ }
210+ if err := os .Symlink (external , filepath .Join (sshDir , "link" )); err != nil {
211+ t .Fatal (err )
212+ }
213+ scanner := & sshDiscovery {}
214+ _ = scanner .walkPrivateKeyFiles (sshDir )
215+ if len (scanner .errors ) == 0 {
216+ t .Fatal ("expected discovery error for symlink entry limit exceeded, got none" )
217+ }
218+ var matched bool
219+ for _ , e := range scanner .errors {
220+ if strings .Contains (e , "symlink entry limit exceeded" ) {
221+ matched = true
222+ break
223+ }
224+ }
225+ if ! matched {
226+ t .Fatalf ("expected symlink entry limit exceeded, got %v" , scanner .errors )
227+ }
228+ })
229+
230+ t .Run ("symlink within budget succeeds" , func (t * testing.T ) {
231+ sshDir := filepath .Join (t .TempDir (), ".ssh" )
232+ if err := os .MkdirAll (sshDir , 0700 ); err != nil {
233+ t .Fatal (err )
234+ }
235+ external := t .TempDir ()
236+ keyFile := filepath .Join (external , "custom_key" )
237+ mustWriteFile (t , keyFile , sshPrivateKeyFixture ())
238+ if err := os .Symlink (external , filepath .Join (sshDir , "link" )); err != nil {
239+ t .Fatal (err )
240+ }
241+ scanner := & sshDiscovery {}
242+ keys := scanner .walkPrivateKeyFiles (sshDir )
243+ if len (scanner .errors ) != 0 {
244+ t .Fatalf ("unexpected discovery errors: %v" , scanner .errors )
245+ }
246+ if len (keys ) == 0 {
247+ t .Fatal ("expected discovered key in symlinked directory, got none" )
248+ }
249+ })
250+ }
0 commit comments