Skip to content
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
snapshot:
runs-on: ubuntu-latest
environment: snapshot
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v5
with:
Expand Down
68 changes: 68 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"slices"
"strings"
Expand Down Expand Up @@ -315,3 +316,70 @@ func decodeManifest(r io.Reader, driverName string, requireShared bool) (Manifes

return result, nil
}

// Common, non-platform-specific code for uninstalling a driver. Called by
// platform-specific UninstallDriver function.
func UninstallDriverShared(cfg Config, info DriverInfo) error {
for sharedPath := range info.Driver.Shared.Paths() {
// Don't remove anything that isn't contained withing the found driver's
// config directory (i.e., avoid malicious driver manifests)
if !strings.HasPrefix(sharedPath, cfg.Location) {
continue
}

// Skip any shared paths with more than one contiguous `.` in them to avoid
// path traversal in the middle of a path
matched, err := regexp.MatchString("\\.{2,}", sharedPath)
if matched || err != nil { // Also ignore errors which shouldn't happen with
// such a simple regex
continue
}

// dbc installs drivers in a folder, other tools may not so we handle each
// differently.
if info.Source == "dbc" {
if err := os.RemoveAll(filepath.Dir(sharedPath)); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
} else {
if err := os.Remove(sharedPath); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
}

}

// Manifest only drivers can come with extra files such as a LICENSE and we
// create a folder next to the driver manifest to store them, same as we'd
// store the actual driver shared library. Above, we find the path of this
// folder by looking at the Driver.shared path. For manifest-only drivers,
// Driver.shared is not a valid path (it's just a name), so this trick doesn't
// work. We do want to clean this folder up so here we guess what it is and
// try to remove it e.g., "somedriver_macos_arm64_v1.2.3."
extra_folder := fmt.Sprintf("%s_%s_v%s", info.ID, platformTuple, info.Version)
// Return immediately if folder has repeated . chars (for safety)
matched, err := regexp.MatchString("\\.{2,}", extra_folder)
if matched || err != nil {
return nil
}
extra_path := filepath.Join(cfg.Location, extra_folder)
finfo, err := os.Stat(extra_path)
if err == nil && finfo.IsDir() {
_ = os.RemoveAll(extra_path)
// ignore errors
}

return nil
}
32 changes: 4 additions & 28 deletions config/dirs_unixlike.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
package config

import (
"errors"
"fmt"
"io/fs"
"maps"
"os"
"path/filepath"
Expand Down Expand Up @@ -90,36 +88,14 @@ func CreateManifest(cfg Config, driver DriverInfo) (err error) {
}

func UninstallDriver(cfg Config, info DriverInfo) error {
if info.Source == "dbc" {
for sharedPath := range info.Driver.Shared.Paths() {
if err := os.RemoveAll(filepath.Dir(sharedPath)); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
}
} else {
for sharedPath := range info.Driver.Shared.Paths() {
if err := os.Remove(sharedPath); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
}
}

manifest := filepath.Join(cfg.Location, info.ID+".toml")
if err := os.Remove(manifest); err != nil {
return fmt.Errorf("error removing manifest %s: %w", manifest, err)
}

if err := UninstallDriverShared(cfg, info); err != nil {
return fmt.Errorf("failed to delete driver shared object: %w", err)
}

return nil
}
27 changes: 2 additions & 25 deletions config/dirs_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package config
import (
"errors"
"fmt"
"io/fs"
"log"
"maps"
"os"
Expand Down Expand Up @@ -285,30 +284,8 @@ func UninstallDriver(cfg Config, info DriverInfo) error {
return fmt.Errorf("failed to delete driver registry key: %w", err)
}

if info.Source == "dbc" {
for sharedPath := range info.Driver.Shared.Paths() {
if err := os.RemoveAll(filepath.Dir(sharedPath)); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
}
} else {
for sharedPath := range info.Driver.Shared.Paths() {
if err := os.Remove(sharedPath); err != nil {
// Ignore only when not found. This supports manifest-only drivers.
// TODO: Come up with a better mechanism to handle manifest-only drivers
// and remove this continue when we do
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("error removing driver %s: %w", info.ID, err)
}
}
if err = UninstallDriverShared(cfg, info); err != nil {
return fmt.Errorf("failed to delete driver shared object: %w", err)
}

return nil
Expand Down
Loading