fix: harden security resource lifecycles

This commit is contained in:
Andy Dixon
2026-07-29 12:37:02 +01:00
parent f0a1a0b8f2
commit b5c7528160
17 changed files with 460 additions and 76 deletions
+72
View File
@@ -13,6 +13,19 @@ import (
"github.com/andydixon/nexus/internal/storage"
)
type closeTrackingWriter struct {
closed int
}
func (w *closeTrackingWriter) Write(p []byte) (int, error) {
return len(p), nil
}
func (w *closeTrackingWriter) Close() error {
w.closed++
return nil
}
func TestSSHKeyPairPathsAcceptsSafeName(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
@@ -128,6 +141,65 @@ func TestSFTPUploadChunkRejectsOversizedChunkBeforeUploadLookup(t *testing.T) {
}
}
func TestCancelSFTPUploadsClosesOnlyMatchingSession(t *testing.T) {
first := &closeTrackingWriter{}
second := &closeTrackingWriter{}
svc := &Service{
uploads: map[string]*sftpUpload{
"first": {writer: first, sessionID: "session-1", remotePath: "/first"},
"second": {writer: second, sessionID: "session-2", remotePath: "/second"},
},
}
svc.cancelSFTPUploads("session-1")
if first.closed != 1 {
t.Fatalf("matching writer closed %d times, want 1", first.closed)
}
if second.closed != 0 {
t.Fatalf("unrelated writer closed %d times, want 0", second.closed)
}
if len(svc.uploads) != 1 || svc.uploads["second"] == nil {
t.Fatalf("remaining uploads = %#v, want only session-2", svc.uploads)
}
}
func TestSFTPUploadCapacityIsBounded(t *testing.T) {
svc := &Service{uploads: make(map[string]*sftpUpload)}
for i := 0; i < maxConcurrentSFTPUploads; i++ {
svc.uploads[string(rune('a'+i))] = &sftpUpload{writer: &closeTrackingWriter{}}
}
if err := svc.checkSFTPUploadCapacity(); err == nil {
t.Fatal("expected active upload limit to be enforced")
}
}
func TestServiceShutdownReleasesUploadsAndSecretWaiters(t *testing.T) {
writer := &closeTrackingWriter{}
waiter := make(chan secretResponse, 1)
svc := &Service{
uploads: map[string]*sftpUpload{"upload": {writer: writer}},
secretChans: map[string]chan secretResponse{"prompt": waiter},
}
svc.Shutdown()
if writer.closed != 1 {
t.Fatalf("writer closed %d times, want 1", writer.closed)
}
if len(svc.uploads) != 0 {
t.Fatalf("active uploads = %d, want 0", len(svc.uploads))
}
select {
case response := <-waiter:
if !response.cancelled {
t.Fatal("shutdown response was not cancelled")
}
default:
t.Fatal("shutdown did not release secret prompt waiter")
}
}
func TestSafeSFTPUploadNamePreservesHTMLCharacters(t *testing.T) {
got, err := safeSFTPUploadName(`../report <final>.txt`)
if err != nil {