diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-07-04 11:12:55 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-07-04 15:05:30 +0200 |
| commit | c7d7f10bdff703e4a3c0414e8a33d4e45c91eb35 (patch) | |
| tree | 0dff0ee1f98dbfa3ad8776112053a450d176592b /vendor/github.com/ryancurrah | |
| parent | 9573094ce235bd9afe88f5da27a47dd6bcc1e13b (diff) | |
go.mod: vendor golangci-lint
Diffstat (limited to 'vendor/github.com/ryancurrah')
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/.dockerignore | 1 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/.gitignore | 21 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/.gomodguard.yaml | 18 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/.goreleaser.yml | 31 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/Dockerfile | 17 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/Dockerfile.goreleaser | 10 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/LICENSE | 21 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/Makefile | 37 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/README.md | 114 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/VERSION | 1 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/go.mod | 11 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/go.sum | 24 | ||||
| -rw-r--r-- | vendor/github.com/ryancurrah/gomodguard/gomodguard.go | 403 |
13 files changed, 709 insertions, 0 deletions
diff --git a/vendor/github.com/ryancurrah/gomodguard/.dockerignore b/vendor/github.com/ryancurrah/gomodguard/.dockerignore new file mode 100644 index 000000000..77738287f --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/.dockerignore @@ -0,0 +1 @@ +dist/
\ No newline at end of file diff --git a/vendor/github.com/ryancurrah/gomodguard/.gitignore b/vendor/github.com/ryancurrah/gomodguard/.gitignore new file mode 100644 index 000000000..5131b46d6 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/.gitignore @@ -0,0 +1,21 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +/gomodguard + +*.xml + +dist/ diff --git a/vendor/github.com/ryancurrah/gomodguard/.gomodguard.yaml b/vendor/github.com/ryancurrah/gomodguard/.gomodguard.yaml new file mode 100644 index 000000000..c0f061f59 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/.gomodguard.yaml @@ -0,0 +1,18 @@ +allowed: + modules: # List of allowed modules + - gopkg.in/yaml.v2 + - github.com/go-xmlfmt/xmlfmt + - github.com/phayes/checkstyle + domains: # List of allowed module domains + - golang.org + +blocked: + modules: # List of blocked modules + - github.com/uudashr/go-module: # Blocked module + recommendations: # Recommended modules that should be used instead (Optional) + - golang.org/x/mod + reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) + - github.com/mitchellh/go-homedir: + recommendations: + - github.com/ryancurrah/gomodguard + reason: "testing if the linted module is not blocked when it is recommended" diff --git a/vendor/github.com/ryancurrah/gomodguard/.goreleaser.yml b/vendor/github.com/ryancurrah/gomodguard/.goreleaser.yml new file mode 100644 index 000000000..20d834992 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/.goreleaser.yml @@ -0,0 +1,31 @@ +builds: +- main: ./cmd/gomodguard/main.go + env: + - CGO_ENABLED=0 +archives: +- replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 +checksum: + name_template: 'checksums.txt' +dockers: +- goos: linux + goarch: amd64 + binaries: + - gomodguard + image_templates: + - "ryancurrah/gomodguard:latest" + - "ryancurrah/gomodguard:{{.Tag}}" + skip_push: false + dockerfile: Dockerfile.goreleaser + build_flag_templates: + - "--pull" + - "--build-arg=gomodguard_VERSION={{.Version}}" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.name={{.ProjectName}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.source={{.GitURL}}" diff --git a/vendor/github.com/ryancurrah/gomodguard/Dockerfile b/vendor/github.com/ryancurrah/gomodguard/Dockerfile new file mode 100644 index 000000000..719a0ebdb --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/Dockerfile @@ -0,0 +1,17 @@ +ARG GO_VERSION=1.14.2 +ARG ALPINE_VERSION=3.11 +ARG gomodguard_VERSION= + +# ---- Build container +FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder +WORKDIR /gomodguard +COPY . . +RUN apk add --no-cache git +RUN go build -o gomodguard cmd/gomodguard/main.go + +# ---- App container +FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} +WORKDIR / +RUN apk --no-cache add ca-certificates +COPY --from=builder gomodguard/gomodguard / +ENTRYPOINT ./gomodguard diff --git a/vendor/github.com/ryancurrah/gomodguard/Dockerfile.goreleaser b/vendor/github.com/ryancurrah/gomodguard/Dockerfile.goreleaser new file mode 100644 index 000000000..57a042a67 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/Dockerfile.goreleaser @@ -0,0 +1,10 @@ +ARG GO_VERSION=1.14.2 +ARG ALPINE_VERSION=3.11 +ARG gomodguard_VERSION= + +# ---- App container +FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} +WORKDIR / +RUN apk --no-cache add ca-certificates +COPY gomodguard /gomodguard +ENTRYPOINT ./gomodguard diff --git a/vendor/github.com/ryancurrah/gomodguard/LICENSE b/vendor/github.com/ryancurrah/gomodguard/LICENSE new file mode 100644 index 000000000..acd8a81e1 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Ryan Currah + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ryancurrah/gomodguard/Makefile b/vendor/github.com/ryancurrah/gomodguard/Makefile new file mode 100644 index 000000000..d765f52d5 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/Makefile @@ -0,0 +1,37 @@ +current_dir = $(shell pwd) +version = $(shell printf '%s' $$(cat VERSION)) + +.PHONEY: lint +lint: + golangci-lint run -v --enable-all --disable funlen,gochecknoglobals,lll ./... + +.PHONEY: build +build: + go build -o gomodguard cmd/gomodguard/main.go + +.PHONEY: dockerbuild +dockerbuild: + docker build --build-arg GOMODGUARD_VERSION=${version} --tag ryancurrah/gomodguard:${version} . + +.PHONEY: run +run: build + ./gomodguard + +.PHONEY: dockerrun +dockerrun: dockerbuild + docker run -v "${current_dir}/.gomodguard.yaml:/.gomodguard.yaml" ryancurrah/gomodguard:latest + +.PHONEY: release +release: + git tag ${version} + git push --tags + goreleaser --skip-validate --rm-dist + +.PHONEY: clean +clean: + rm -rf dist/ + rm -f gomodguard + +.PHONEY: install-tools-mac +install-tools-mac: + brew install goreleaser/tap/goreleaser diff --git a/vendor/github.com/ryancurrah/gomodguard/README.md b/vendor/github.com/ryancurrah/gomodguard/README.md new file mode 100644 index 000000000..89a2398be --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/README.md @@ -0,0 +1,114 @@ +# gomodguard + +<img src="https://storage.googleapis.com/gopherizeme.appspot.com/gophers/9afcc208898c763be95f046eb2f6080146607209.png" width="30%"> + +Allow and block list linter for direct Go module dependencies. This is useful for organizations where they want to standardize on the modules used and be able to recommend alternative modules. + +## Description + +Allowed and blocked modules are defined in a `.gomodguard.yaml` or `~/.gomodguard.yaml` file. + +Modules can be allowed by module or domain name. When allowed modules are specified any modules not in the allowed configuration are blocked. + +If no allowed modules or domains are specified then all modules are allowed except for blocked ones. + +The linter looks for blocked modules in `go.mod` and searches for imported packages where the imported packages module is blocked. Indirect modules are not considered. + +Alternative modules can be optionally recommended in the blocked modules list. + +If the linted module imports a blocked module but the linted module is in the recommended modules list the blocked module is ignored. Usually, this means the linted module wraps that blocked module for use by other modules, therefore the import of the blocked module should not be blocked. + +Results are printed to `stdout`. + +Logging statements are printed to `stderr`. + +Results can be exported to different report formats. Which can be imported into CI tools. See the help section for more information. + +## Configuration + +```yaml +allowed: + modules: # List of allowed modules + - gopkg.in/yaml.v2 + - github.com/go-xmlfmt/xmlfmt + - github.com/phayes/checkstyle + - github.com/mitchellh/go-homedir + domains: # List of allowed module domains + - golang.org + +blocked: + modules: # List of blocked modules + - github.com/uudashr/go-module: # Blocked module + recommendations: # Recommended modules that should be used instead (Optional) + - golang.org/x/mod + reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) +``` + +## Usage + +``` +╰─ ./gomodguard -h +Usage: gomodguard <file> [files...] +Also supports package syntax but will use it in relative path, i.e. ./pkg/... +Flags: + -f string + Report results to the specified file. A report type must also be specified + -file string + + -h Show this help text + -help + + -n Don't lint test files + -no-test + + -r string + Report results to one of the following formats: checkstyle. A report file destination must also be specified + -report string +``` + +## Example + +``` +╰─ ./gomodguard -r checkstyle -f gomodguard-checkstyle.xml ./... + +info: allowed modules, [gopkg.in/yaml.v2 github.com/go-xmlfmt/xmlfmt github.com/phayes/checkstyle github.com/mitchellh/go-homedir] +info: allowed module domains, [golang.org] +info: blocked modules, [github.com/uudashr/go-module] +info: found `2` blocked modules in the go.mod file, [github.com/gofrs/uuid github.com/uudashr/go-module] +blocked_example.go:6: import of package `github.com/gofrs/uuid` is blocked because the module is not in the allowed modules list. +blocked_example.go:7: import of package `github.com/uudashr/go-module` is blocked because the module is in the blocked modules list. `golang.org/x/mod` is a recommended module. `mod` is the official go.mod parser library. +``` + +Resulting checkstyle file + +``` +╰─ cat gomodguard-checkstyle.xml + +<?xml version="1.0" encoding="UTF-8"?> +<checkstyle version="1.0.0"> + <file name="blocked_example.go"> + <error line="6" column="1" severity="error" message="import of package `github.com/gofrs/uuid` is blocked because the module is not in the allowed modules list." source="gomodguard"> + </error> + <error line="7" column="1" severity="error" message="import of package `github.com/uudashr/go-module` is blocked because the module is in the blocked modules list. `golang.org/x/mod` is a recommended module. `mod` is the official go.mod parser library." source="gomodguard"> + </error> + </file> +</checkstyle> +``` + +## Install + +``` +go get -u github.com/ryancurrah/gomodguard/cmd/gomodguard +``` + +## Develop + +``` +git clone https://github.com/ryancurrah/gomodguard.git && cd gomodguard + +go build -o gomodguard cmd/gomodguard/main.go +``` + +## License + +**MIT** diff --git a/vendor/github.com/ryancurrah/gomodguard/VERSION b/vendor/github.com/ryancurrah/gomodguard/VERSION new file mode 100644 index 000000000..3e7bcf08c --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/VERSION @@ -0,0 +1 @@ +v1.0.4 diff --git a/vendor/github.com/ryancurrah/gomodguard/go.mod b/vendor/github.com/ryancurrah/gomodguard/go.mod new file mode 100644 index 000000000..0f0e92e4e --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/go.mod @@ -0,0 +1,11 @@ +module github.com/ryancurrah/gomodguard + +go 1.14 + +require ( + github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b + github.com/mitchellh/go-homedir v1.1.0 + github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d + golang.org/x/mod v0.2.0 + gopkg.in/yaml.v2 v2.2.8 +) diff --git a/vendor/github.com/ryancurrah/gomodguard/go.sum b/vendor/github.com/ryancurrah/gomodguard/go.sum new file mode 100644 index 000000000..0f4bf3231 --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/go.sum @@ -0,0 +1,24 @@ +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/ryancurrah/gomodguard/gomodguard.go b/vendor/github.com/ryancurrah/gomodguard/gomodguard.go new file mode 100644 index 000000000..cd4f7d66e --- /dev/null +++ b/vendor/github.com/ryancurrah/gomodguard/gomodguard.go @@ -0,0 +1,403 @@ +package gomodguard + +import ( + "bytes" + "encoding/json" + "fmt" + "go/parser" + "go/token" + "io/ioutil" + "log" + "os" + "os/exec" + "strings" + + "golang.org/x/mod/modfile" +) + +var ( + blockedReasonNotInAllowedList = "import of package `%s` is blocked because the module is not in the allowed modules list." + blockedReasonInBlockedList = "import of package `%s` is blocked because the module is in the blocked modules list." + goModFilename = "go.mod" +) + +// Recommendations are alternative modules to use and a reason why. +type Recommendations struct { + Recommendations []string `yaml:"recommendations"` + Reason string `yaml:"reason"` +} + +// IsRecommended returns true if the package provided is in the Recommendations list +func (r *Recommendations) IsRecommended(pkg string) bool { + for n := range r.Recommendations { + if strings.TrimSpace(pkg) == strings.TrimSpace(r.Recommendations[n]) { + return true + } + } + + return false +} + +// String returns the recommended modules and reason message. +func (r *Recommendations) String() string { + msg := "" + + if r == nil { + return msg + } + + for i := range r.Recommendations { + switch { + case len(r.Recommendations) == 1: + msg += fmt.Sprintf("`%s` is a recommended module.", r.Recommendations[i]) + case (i+1) != len(r.Recommendations) && (i+1) == (len(r.Recommendations)-1): + msg += fmt.Sprintf("`%s` ", r.Recommendations[i]) + case (i + 1) != len(r.Recommendations): + msg += fmt.Sprintf("`%s`, ", r.Recommendations[i]) + default: + msg += fmt.Sprintf("and `%s` are recommended modules.", r.Recommendations[i]) + } + } + + if r.Reason != "" { + msg += fmt.Sprintf(" %s", r.Reason) + } + + return msg +} + +// HasRecommendations returns true if the blocked package has +// recommended modules. +func (r *Recommendations) HasRecommendations() bool { + return len(r.Recommendations) > 0 +} + +// BlockedModule is a blocked module name and +// optionally a list of recommended modules +// and a reason message. +type BlockedModule map[string]Recommendations + +// BlockedModules a list of blocked modules. +type BlockedModules []BlockedModule + +// Get returns the modules that are blocked. +func (b BlockedModules) Get() []string { + modules := make([]string, len(b)) + + for i := range b { + for module := range b[i] { + modules[i] = module + break + } + } + + return modules +} + +// RecommendedModules will return a list of recommended modules for the +// package provided. If there is no recommendation nil will be returned. +func (b BlockedModules) RecommendedModules(pkg string) *Recommendations { + for i := range b { + for blockedModule, recommendations := range b[i] { + if strings.HasPrefix(strings.ToLower(pkg), strings.ToLower(blockedModule)) && recommendations.HasRecommendations() { + return &recommendations + } + + break + } + } + + return nil +} + +// IsBlockedPackage returns true if the package name is in +// the blocked modules list. +func (b BlockedModules) IsBlockedPackage(pkg string) bool { + blockedModules := b.Get() + for i := range blockedModules { + if strings.HasPrefix(strings.ToLower(pkg), strings.ToLower(blockedModules[i])) { + return true + } + } + + return false +} + +// IsBlockedModule returns true if the given module name is in the +// blocked modules list. +func (b BlockedModules) IsBlockedModule(module string) bool { + blockedModules := b.Get() + for i := range blockedModules { + if strings.EqualFold(module, strings.TrimSpace(blockedModules[i])) { + return true + } + } + + return false +} + +// Allowed is a list of modules and module +// domains that are allowed to be used. +type Allowed struct { + Modules []string `yaml:"modules"` + Domains []string `yaml:"domains"` +} + +// IsAllowedModule returns true if the given module +// name is in the allowed modules list. +func (a *Allowed) IsAllowedModule(module string) bool { + allowedModules := a.Modules + for i := range allowedModules { + if strings.EqualFold(module, strings.TrimSpace(allowedModules[i])) { + return true + } + } + + return false +} + +// IsAllowedModuleDomain returns true if the given modules domain is +// in the allowed module domains list. +func (a *Allowed) IsAllowedModuleDomain(module string) bool { + allowedDomains := a.Domains + for i := range allowedDomains { + if strings.HasPrefix(strings.ToLower(module), strings.TrimSpace(strings.ToLower(allowedDomains[i]))) { + return true + } + } + + return false +} + +// Blocked is a list of modules that are +// blocked and not to be used. +type Blocked struct { + Modules BlockedModules `yaml:"modules"` +} + +// Configuration of gomodguard allow and block lists. +type Configuration struct { + Allowed Allowed `yaml:"allowed"` + Blocked Blocked `yaml:"blocked"` +} + +// Result represents the result of one error. +type Result struct { + FileName string + LineNumber int + Position token.Position + Reason string +} + +// String returns the filename, line +// number and reason of a Result. +func (r *Result) String() string { + return fmt.Sprintf("%s:%d: %s", r.FileName, r.LineNumber, r.Reason) +} + +// Processor processes Go files. +type Processor struct { + config Configuration + logger *log.Logger + modfile *modfile.File + blockedModulesFromModFile []string + result []Result +} + +// NewProcessor will create a Processor to lint blocked packages. +func NewProcessor(config Configuration, logger *log.Logger) (*Processor, error) { + goModFileBytes, err := loadGoModFile() + if err != nil { + errMsg := fmt.Sprintf("unable to read %s file: %s", goModFilename, err) + + return nil, fmt.Errorf(errMsg) + } + + mfile, err := modfile.Parse(goModFilename, goModFileBytes, nil) + if err != nil { + errMsg := fmt.Sprintf("unable to parse %s file: %s", goModFilename, err) + + return nil, fmt.Errorf(errMsg) + } + + logger.Printf("info: allowed modules, %+v", config.Allowed.Modules) + logger.Printf("info: allowed module domains, %+v", config.Allowed.Domains) + logger.Printf("info: blocked modules, %+v", config.Blocked.Modules.Get()) + + p := &Processor{ + config: config, + logger: logger, + modfile: mfile, + result: []Result{}, + } + + p.setBlockedModulesFromModFile() + + return p, nil +} + +// ProcessFiles takes a string slice with file names (full paths) +// and lints them. +func (p *Processor) ProcessFiles(filenames []string) []Result { + pluralModuleMsg := "s" + if len(p.blockedModulesFromModFile) == 1 { + pluralModuleMsg = "" + } + + p.logger.Printf("info: found `%d` blocked module%s in the %s file, %+v", + len(p.blockedModulesFromModFile), pluralModuleMsg, goModFilename, p.blockedModulesFromModFile) + + for _, filename := range filenames { + data, err := ioutil.ReadFile(filename) + if err != nil { + p.result = append(p.result, Result{ + FileName: filename, + LineNumber: 0, + Reason: fmt.Sprintf("unable to read file, file cannot be linted (%s)", err.Error()), + }) + } + + p.process(filename, data) + } + + return p.result +} + +// process file imports and add lint error if blocked package is imported. +func (p *Processor) process(filename string, data []byte) { + fileSet := token.NewFileSet() + + file, err := parser.ParseFile(fileSet, filename, data, parser.ParseComments) + if err != nil { + p.result = append(p.result, Result{ + FileName: filename, + LineNumber: 0, + Reason: fmt.Sprintf("invalid syntax, file cannot be linted (%s)", err.Error()), + }) + + return + } + + imports := file.Imports + for i := range imports { + importedPkg := strings.TrimSpace(strings.Trim(imports[i].Path.Value, "\"")) + if p.isBlockedPackageFromModFile(importedPkg) { + reason := "" + + if p.config.Blocked.Modules.IsBlockedPackage(importedPkg) { + reason = fmt.Sprintf(blockedReasonInBlockedList, importedPkg) + } else { + reason = fmt.Sprintf(blockedReasonNotInAllowedList, importedPkg) + } + + recommendedModules := p.config.Blocked.Modules.RecommendedModules(importedPkg) + if recommendedModules != nil { + reason += fmt.Sprintf(" %s", recommendedModules.String()) + } + + p.addError(fileSet, imports[i].Pos(), reason) + } + } +} + +// addError adds an error for the file and line number for the current token.Pos +// with the given reason. +func (p *Processor) addError(fileset *token.FileSet, pos token.Pos, reason string) { + position := fileset.Position(pos) + + p.result = append(p.result, Result{ + FileName: position.Filename, + LineNumber: position.Line, + Position: position, + Reason: reason, + }) +} + +// setBlockedModules determines which modules are blocked by reading +// the go.mod file and comparing the require modules to the allowed modules. +func (p *Processor) setBlockedModulesFromModFile() { + blockedModules := make([]string, 0, len(p.modfile.Require)) + requiredModules := p.modfile.Require + lintedModule := p.modfile.Module.Mod.Path + + for i := range requiredModules { + if !requiredModules[i].Indirect { + requiredModule := strings.TrimSpace(requiredModules[i].Mod.Path) + + if p.config.Allowed.IsAllowedModuleDomain(requiredModule) { + continue + } + + if p.config.Allowed.IsAllowedModule(requiredModule) { + continue + } + + requiredModuleIsBlocked := p.config.Blocked.Modules.IsBlockedModule(requiredModule) + + if len(p.config.Allowed.Modules) == 0 && + len(p.config.Allowed.Domains) == 0 && + !requiredModuleIsBlocked { + continue + } + + // If the go.mod file being linted is a recommended module of a blocked module + // and it imports that blocked module, do not set as a blocked. This means + // that the linted module wraps that blocked module + if requiredModuleIsBlocked { + recommendedModules := p.config.Blocked.Modules.RecommendedModules(requiredModule) + + if recommendedModules.IsRecommended(lintedModule) { + continue + } + } + + blockedModules = append(blockedModules, requiredModule) + } + } + + if len(blockedModules) > 0 { + p.blockedModulesFromModFile = blockedModules + } +} + +// isBlockedPackageFromModFile returns true if the imported packages +// module is in the go.mod file and was blocked. +func (p *Processor) isBlockedPackageFromModFile(pkg string) bool { + blockedModulesFromModFile := p.blockedModulesFromModFile + for i := range blockedModulesFromModFile { + if strings.HasPrefix(strings.ToLower(pkg), strings.ToLower(blockedModulesFromModFile[i])) { + return true + } + } + + return false +} + +func loadGoModFile() ([]byte, error) { + cmd := exec.Command("go", "env", "-json") + stdout, _ := cmd.StdoutPipe() + _ = cmd.Start() + + if stdout == nil { + return ioutil.ReadFile(goModFilename) + } + + buf := new(bytes.Buffer) + _, _ = buf.ReadFrom(stdout) + + goEnv := make(map[string]string) + err := json.Unmarshal(buf.Bytes(), &goEnv) + if err != nil { + return ioutil.ReadFile(goModFilename) + } + + if _, ok := goEnv["GOMOD"]; !ok { + return ioutil.ReadFile(goModFilename) + } + + if _, err := os.Stat(goEnv["GOMOD"]); os.IsNotExist(err) { + return ioutil.ReadFile(goModFilename) + } + + return ioutil.ReadFile(goEnv["GOMOD"]) +} |
