From 847b0466bed757b54b1dc81223b644868cdf5f3d Mon Sep 17 00:00:00 2001 From: yuraaaaa Date: Sat, 16 May 2026 23:39:54 +0300 Subject: [PATCH 1/2] fix: close lock file handles to prevent leaks --- internal/adapters/lock_file/lock_file.go | 2 ++ internal/adapters/lock_file/write.go | 11 +++++++++-- internal/adapters/plugin/remote.go | 17 ++++++++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/internal/adapters/lock_file/lock_file.go b/internal/adapters/lock_file/lock_file.go index 0723aca6..44243fa1 100644 --- a/internal/adapters/lock_file/lock_file.go +++ b/internal/adapters/lock_file/lock_file.go @@ -26,6 +26,8 @@ func New(dirWalker core.DirWalker) *LockFile { fp, err := dirWalker.Open(lockFileName) if err == nil { + defer func() { _ = fp.Close() }() + fscanner := bufio.NewScanner(fp) for fscanner.Scan() { diff --git a/internal/adapters/lock_file/write.go b/internal/adapters/lock_file/write.go index ed57e635..1dfc8d17 100644 --- a/internal/adapters/lock_file/write.go +++ b/internal/adapters/lock_file/write.go @@ -9,11 +9,16 @@ import ( func (l *LockFile) Write( moduleName string, revisionVersion string, installedPackageHash models.ModuleHash, -) error { +) (err error) { fp, err := l.dirWalker.Create(lockFileName) if err != nil { return fmt.Errorf("l.dirWalker.Create: %w", err) } + defer func() { + if closeErr := fp.Close(); closeErr != nil && err == nil { + err = fmt.Errorf("fp.Close: %w", closeErr) + } + }() fileInfo := fileInfo{ version: revisionVersion, @@ -30,7 +35,9 @@ func (l *LockFile) Write( for _, k := range keys { r := fmt.Sprintf("%s %s %s\n", k, l.cache[k].version, l.cache[k].hash) - _, _ = fp.Write([]byte(r)) + if _, err := fp.Write([]byte(r)); err != nil { + return fmt.Errorf("fp.Write: %w", err) + } } return nil diff --git a/internal/adapters/plugin/remote.go b/internal/adapters/plugin/remote.go index 8422b552..6e9d370a 100644 --- a/internal/adapters/plugin/remote.go +++ b/internal/adapters/plugin/remote.go @@ -70,7 +70,14 @@ func (e *RemotePluginExecutor) Execute(ctx context.Context, plugin Info, request if err != nil { return nil, fmt.Errorf("failed to connect to gRPC server %s: %w", host, err) } - defer conn.Close() + defer func() { + if err := conn.Close(); err != nil { + e.logger.Warn(ctx, "failed to close gRPC connection", + slog.String("plugin", plugin.Source), + slog.Any("error", err), + ) + } + }() // Создаем gRPC клиент client := plugingeneratorv1.NewServiceAPIClient(conn) @@ -93,14 +100,6 @@ func (e *RemotePluginExecutor) Execute(ctx context.Context, plugin Info, request return nil, fmt.Errorf("gRPC call failed for plugin %s: %w", plugin.Source, err) } - err = conn.Close() - if err != nil { - e.logger.Warn(ctx, "failed to close gRPC connection", - slog.String("plugin", plugin.Source), - slog.Any("error", err), - ) - } - return resp.CodeGeneratorResponse, nil } From 36580e39abf5c5fe199ecac383d87b02ebe17a70 Mon Sep 17 00:00:00 2001 From: yuraaaaa Date: Sun, 17 May 2026 17:45:46 +0300 Subject: [PATCH 2/2] fix: surface lockfile scanner errors and fix Windows-specific tests --- .gitattributes | 1 + internal/adapters/lock_file/lock_file.go | 9 +++++++-- internal/adapters/storage/get_install_dir_test.go | 4 ++-- internal/adapters/storage/install_test.go | 8 +++++++- internal/api/temporaly_helper.go | 6 +++++- 5 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..2b648252 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +testdata/**/*.proto text eol=lf diff --git a/internal/adapters/lock_file/lock_file.go b/internal/adapters/lock_file/lock_file.go index 44243fa1..ca15d674 100644 --- a/internal/adapters/lock_file/lock_file.go +++ b/internal/adapters/lock_file/lock_file.go @@ -2,6 +2,7 @@ package lockfile import ( "bufio" + "fmt" "strings" "github.com/easyp-tech/easyp/internal/core" @@ -21,7 +22,7 @@ type LockFile struct { cache map[string]fileInfo } -func New(dirWalker core.DirWalker) *LockFile { +func New(dirWalker core.DirWalker) (*LockFile, error) { cache := make(map[string]fileInfo) fp, err := dirWalker.Open(lockFileName) @@ -42,11 +43,15 @@ func New(dirWalker core.DirWalker) *LockFile { } cache[parts[0]] = fileInfo } + + if err := fscanner.Err(); err != nil { + return nil, fmt.Errorf("scan %s: %w", lockFileName, err) + } } lockFile := &LockFile{ dirWalker: dirWalker, cache: cache, } - return lockFile + return lockFile, nil } diff --git a/internal/adapters/storage/get_install_dir_test.go b/internal/adapters/storage/get_install_dir_test.go index b09746e9..a41ab7ba 100644 --- a/internal/adapters/storage/get_install_dir_test.go +++ b/internal/adapters/storage/get_install_dir_test.go @@ -1,14 +1,14 @@ package storage import ( - "path" + "path/filepath" ) func (s *storageSuite) Test_GetInstallDir() { moduleName := getFakeModule().Name version := getFakeRevision().Version - expectedResult := path.Join(s.rootDir, installedDir, moduleName, version) + expectedResult := filepath.Join(s.rootDir, installedDir, moduleName, version) res := s.storage.GetInstallDir(moduleName, version) s.Equal(expectedResult, res) diff --git a/internal/adapters/storage/install_test.go b/internal/adapters/storage/install_test.go index 37e1652a..1bd514ec 100644 --- a/internal/adapters/storage/install_test.go +++ b/internal/adapters/storage/install_test.go @@ -3,6 +3,7 @@ package storage import ( "os" "path/filepath" + "runtime" "strings" "testing" @@ -183,9 +184,14 @@ func TestBuildInstallTree_AbsoluteSymlinkRejected(t *testing.T) { Directories: []string{"proto"}, }) + absTarget := "/etc/passwd" + if runtime.GOOS == "windows" { + absTarget = `C:\Windows\System32\drivers\etc\hosts` + } + require.NoError(t, os.MkdirAll(filepath.Join(srcDir, "proto"), 0755)) require.NoError(t, os.WriteFile(filepath.Join(srcDir, "proto", "file.proto"), []byte("data"), 0644)) - require.NoError(t, os.Symlink("/etc/passwd", filepath.Join(srcDir, "proto", "bad.proto"))) + require.NoError(t, os.Symlink(absTarget, filepath.Join(srcDir, "proto", "bad.proto"))) err := buildInstallTree(srcDir, dstDir, renamer) require.Error(t, err) diff --git a/internal/api/temporaly_helper.go b/internal/api/temporaly_helper.go index b61f059a..338757a6 100644 --- a/internal/api/temporaly_helper.go +++ b/internal/api/temporaly_helper.go @@ -79,7 +79,11 @@ func buildCore(_ context.Context, log logger.Logger, cfg config.Config, dirWalke return nil, fmt.Errorf("cfg.BuildLinterRules: %w", err) } - lockFile := lockfile.New(dirWalker) + lockFile, err := lockfile.New(dirWalker) + if err != nil { + return nil, fmt.Errorf("lockfile.New: %w", err) + } + easypPath, err := getEasypPath(log) if err != nil { return nil, fmt.Errorf("getEasypPath: %w", err)