• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mindersec / minder / 14315603253

07 Apr 2025 05:28PM UTC coverage: 56.758% (-0.01%) from 56.772%
14315603253

push

github

web-flow
build(deps): bump golangci/golangci-lint-action from 6.5.2 to 7.0.0 (#5548)

* build(deps): bump golangci/golangci-lint-action from 6.5.2 to 7.0.0

Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 6.5.2 to 7.0.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/55c2c1448...148140484)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Migrate to golangci-lint version 2

* Fix newly-detected golangci-lint issues

* Fix remaining lint issues from new golangci-lint

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evan Anderson <evan@stacklok.com>

53 of 164 new or added lines in 78 files covered. (32.32%)

2 existing lines in 1 file now uncovered.

18301 of 32244 relevant lines covered (56.76%)

36.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.25
/internal/datasources/structured/handler.go
1
// SPDX-FileCopyrightText: Copyright 2024 The Minder Authors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package structured
5

6
import (
7
        "context"
8
        "errors"
9
        "fmt"
10
        "io"
11
        "os"
12
        "path/filepath"
13
        "slices"
14
        "strings"
15

16
        "github.com/go-git/go-billy/v5"
17
        "github.com/rs/zerolog/log"
18
        "google.golang.org/protobuf/types/known/structpb"
19

20
        minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
21
        v1datasources "github.com/mindersec/minder/pkg/datasources/v1"
22
        "github.com/mindersec/minder/pkg/engine/v1/interfaces"
23
)
24

25
const (
26
        jsonType decoderType = "json"
27
        yamlType decoderType = "yaml"
28
        tomlType decoderType = "toml"
29
)
30

31
type decoder interface {
32
        Parse(io.Reader) (any, error)
33
        Extensions() []string
34
}
35

36
type decoderType string
37

38
// Catalog of decoders enabled by default
39
var decoders = map[decoderType]decoder{
40
        jsonType: &jsonDecoder{},
41
        yamlType: &yamlDecoder{},
42
        tomlType: &tomlDecoder{},
43
}
44

45
var _ v1datasources.DataSourceFuncDef = (*structHandler)(nil)
46

47
// ErrorNoFileMatchInPath triggers if the path specification can't match a
48
// file in the filesystem received by the data source.
49
var ErrorNoFileMatchInPath = errors.New("no file matched through path specification")
50

51
type structHandler struct {
52
        Path *minderv1.StructDataSource_Def_Path
53
}
54

55
func newHandlerFromDef(def *minderv1.StructDataSource_Def) (*structHandler, error) {
7✔
56
        if def == nil {
9✔
57
                return nil, errors.New("data source handler definition is nil")
2✔
58
        }
2✔
59

60
        return &structHandler{
5✔
61
                Path: def.GetPath(),
5✔
62
        }, nil
5✔
63
}
64

65
// openFirstAlternative tries to open the main path and return an open file. If
66
// not found, it will try the defined alternatives returning the first one.
67
// If paths are directories, they will be ignored. Returns an error if no path
68
// corresponds to a file that can be opened.
69
func openFirstAlternative(fs billy.Filesystem, mainPath string, alternatives []string) (billy.File, error) {
10✔
70
        if mainPath == "" && len(alternatives) == 0 {
12✔
71
                return nil, errors.New("no file specified in data source definition")
2✔
72
        }
2✔
73
        if mainPath != "" {
15✔
74
                alternatives = append([]string{mainPath}, alternatives...)
7✔
75
        }
7✔
76

77
        for _, p := range alternatives {
21✔
78
                s, err := fs.Stat(p)
13✔
79
                if err != nil {
18✔
80
                        if errors.Is(err, os.ErrNotExist) {
10✔
81
                                continue
5✔
82
                        }
83
                        return nil, fmt.Errorf("error checking path: %w", err)
×
84
                }
85

86
                if s.IsDir() {
9✔
87
                        continue
1✔
88
                }
89

90
                f, err := fs.Open(p)
7✔
91
                if err != nil {
7✔
92
                        return nil, fmt.Errorf("opening file: %w", err)
×
93
                }
×
94

95
                return f, nil
7✔
96
        }
97
        return nil, ErrorNoFileMatchInPath
1✔
98
}
99

100
// parseFileAlternatives takes a path and alternative locations and parses
101
// the first available
102
func parseFileAlternatives(fs billy.Filesystem, mainPath string, alternatives []string) (any, error) {
3✔
103
        f, err := openFirstAlternative(fs, mainPath, alternatives)
3✔
104
        if err != nil {
4✔
105
                // If no file was found, we don't return an error but nil
1✔
106
                // we want rules to not error but to get a blank struct
1✔
107
                if errors.Is(err, ErrorNoFileMatchInPath) {
1✔
108
                        log.Info().Err(err).Msg("error validating datasource function arguments")
×
109
                        return nil, nil
×
110
                }
×
111
                return nil, err
1✔
112
        }
113
        return parseFile(f)
2✔
114
}
115

116
// parseFile parses an open file using the configured parsers
117
func parseFile(f billy.File) (any, error) {
2✔
118
        // Get the file extension, perhaps we can shortcut before trying
2✔
119
        // to brute force through all decoders
2✔
120
        ext := filepath.Ext(f.Name())
2✔
121
        tried := map[decoderType]struct{}{}
2✔
122
        for t, d := range decoders {
8✔
123
                exts := d.Extensions()
6✔
124
                if slices.Contains(exts, strings.ToLower(ext)) {
6✔
125
                        if _, err := f.Seek(0, 0); err != nil {
×
126
                                return nil, fmt.Errorf("unable to rewind file")
×
127
                        }
×
128
                        res, err := d.Parse(f)
×
129
                        if err == nil {
×
130
                                return res, nil
×
131
                        }
×
132
                        tried[t] = struct{}{}
×
133
                }
134
        }
135

136
        // no dice, try the rest of the decoders
137
        for t, d := range decoders {
5✔
138
                if _, ok := tried[t]; ok {
3✔
139
                        continue
×
140
                }
141
                if _, err := f.Seek(0, 0); err != nil {
3✔
142
                        return nil, fmt.Errorf("unable to rewind file")
×
143
                }
×
144
                res, err := d.Parse(f)
3✔
145
                if err == nil {
5✔
146
                        return res, nil
2✔
147
                }
2✔
148
        }
149
        return nil, errors.New("unable to parse structured data with any of the available decoders")
×
150
}
151

152
// Call parses the structured data from the billy filesystem in the context
153
func (sh *structHandler) Call(_ context.Context, ingest *interfaces.Result, _ any) (any, error) {
3✔
154
        if ingest == nil || ingest.Fs == nil {
5✔
155
                return nil, fmt.Errorf("filesystem not found in execution context")
2✔
156
        }
2✔
157

158
        return parseFileAlternatives(ingest.Fs, sh.Path.GetFileName(), sh.Path.GetAlternatives())
1✔
159
}
160

161
func (*structHandler) GetArgsSchema() *structpb.Struct {
×
162
        return nil
×
163
}
×
164

165
// ValidateArgs is just a stub as the structured data source does not have arguments
NEW
166
func (*structHandler) ValidateArgs(any) error {
×
167
        return nil
×
168
}
×
169

170
// ValidateUpdate
NEW
171
func (*structHandler) ValidateUpdate(*structpb.Struct) error {
×
172
        return nil
×
173
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc