Faillint: Report unwanted import path and declaration usages

Overview

faillint

Faillint is a simple Go linter that fails when a specific set of import paths or exported path's functions, constant, vars or types are used. It's meant to be used in CI/CD environments to catch rules you want to enforce in your projects.

As an example, you could enforce the usage of github.com/pkg/errors instead of the errors package. To prevent the usage of the errors package, you can configure faillint to fail whenever someone imports the errors package in this case. To make sure fmt.Errorf is not used for creating errors as well, you can configure to fail on such single function of fmt as well.

faillint

Install

go install github.com/fatih/[email protected]

Example

Assume we have the following file:

package a

import (
        "errors"
)

func foo() error {
        return errors.New("bar!")
}

Let's run faillint to check if errors import is used and report it:

$ faillint -paths "errors=github.com/pkg/errors" a.go
a.go:4:2: package "errors" shouldn't be imported, suggested: "github.com/pkg/errors"

Usage

faillint works on a file, directory or a Go package:

$ faillint -paths "errors,fmt.{Errorf}" foo.go # pass a file
$ faillint -paths "errors,fmt.{Errorf}" ./...  # recursively analyze all files
$ faillint -paths "errors,fmt.{Errorf}" github.com/fatih/gomodifytags # or pass a package

By default, faillint will not check any import paths. You need to explicitly define it with the -paths flag, which is comma-separated list. Some examples are:

# Fail if the errors package is used.
-paths "errors"

# Fail if the old context package is imported.
-paths "golang.org/x/net/context"

# Fail both on stdlib log and errors package to enforce other internal libraries.
-paths "log,errors"

# Fail if any of Print, Printf of Println function were used from fmt library.
-paths "fmt.{Print,Printf,Println}"

# Fail if the package is imported including sub paths starting with
  "golang.org/x/net/". In example: `golang.org/x/net/context`, 
  `golang.org/x/net/nettest`, .nettest`, ...
-paths "golang.org/x/net/..."

If you have a preferred import path to suggest, append the suggestion after a = character:

# Fail if the errors package is used and suggest to use github.com/pkg/errors.
-paths "errors=github.com/pkg/errors"

# Fail for the old context import path and suggest to use the stdlib context.
-paths "golang.org/x/net/context=context"

# Fail both on stdlib log and errors package to enforce other libraries.
-paths "log=go.uber.org/zap,errors=github.com/pkg/errors"

# Fail on fmt.Errorf and suggest the Errorf function from github.compkg/errors instead.
-paths "fmt.{Errorf}=github.com/pkg/errors.{Errorf}"

Ignoring problems

If you want to ignore a problem reported by faillint you can add a lint directive based on staticcheck's design.

Line-based lint directives

Line-based lint directives can be applied to imports or functions you want to tolerate. The format is,

//lint:ignore faillint reason

For example,

package a

import (
        //lint:ignore faillint Whatever your reason is.
        "errors"
        "fmt" //lint:ignore faillint Whatever your reason is.
)

func foo() error {
        //lint:ignore faillint Whatever your reason is.
        return errors.New("bar!")
}

File-based lint directives

File-based lint directives can be applied to ignore faillint problems in a whole file. The format is,

//lint:file-ignore faillint reason

This may be placed anywhere in the file but conventionally it should be placed at, or near, the top of the file.

For example,

//lint:file-ignore faillint This file should be ignored by faillint.

package a

import (
        "errors"
)

func foo() error {
        return errors.New("bar!")
}

The need for this tool?

Most of these checks should be probably detected during the review cycle. But it's totally normal to accidentally import them (we're all humans in the end).

Second, tools like goimports favors certain packages. As an example going forward if you decided to use github.com/pkg/errors in you project, and write errors.New() in a new file, goimports will automatically import the errors package (and not github.com/pkg/errors). The code will perfectly compile. faillint would be able to detect and report it to you.

Credits

This tool is built on top of the excellent go/analysis package that makes it easy to write custom analyzers in Go. If you're interested in writing a tool, check out my Using go/analysis to write a custom linter blog post.

Part of the code is modified and based on astutil.UsesImport

Issues
  • Added support for unwanted function; added more tests.

    Added support for unwanted function; added more tests.

    Fixes: https://github.com/fatih/faillint/issues/7

    Changes

    • No more globals :heart:
    • Separate tests for parsing (as it gets a bit more complex now) and tests.
    • Add some test edge cases for imports as well (e.g named imports).
    • Fixes some edge cases like whitespaces etc.
    • Support for unwanted functions with {Func1,Func2} notion.
    opened by bwplotka 10
  • Add failing for certain methods in a given package (i.e: fmt.Errorf)

    Add failing for certain methods in a given package (i.e: fmt.Errorf)

    Currently faillint only fails on package level (based on the import path). We should also make it possible to fail for a sub-set of exported functions, types or variables (i.e: ast.TypeSpec and ast.ValueSpec should be enough).

    Why is this useful? Let's look at this example:

    If a user opted to use github.com/pkg/errors not only want they prevent the usage of errors package, they probably also want to avoid using fmt.Errorf and start using errors.Errorf method from the github.com/pkg/errors package. There are many reasons for that. For example the github.com/pkg/errors package includes stack information in each error value. Hence they want to make sure all errors are created with the github.com/pkg/errors package.

    We could still use the paths flags and could define the sub-set with a dot identifier. For example the following command could fail for all usages of errors and the usage of fmt.Errorf:

    faillint --paths "errors,fmt.Errorf"
    

    If anyone wants to work on this, please comment on the PR before starting on it. I'll work on that at some point otherwise.

    enhancement 
    opened by fatih 10
  • Comment imports to tolerate exceptions

    Comment imports to tolerate exceptions

    Imagine wanting to avoid a package but, in practice, needing to be able to tolerate exceptions to it (while using faillint in a CI pipeline). Much like many linting tools I wonder if the import could be annotated like,

    import (
        "github.com/gogo/protobuf/proto" // faillint: gogo is tolerated here because XYZ.
    )
    

    So if we had -path "github.com/gogo/protobuf/proto=github.com/golang/protobuf/proto" but faillint saw a // faillint: annotation it would suppress its objection (and if no objections exit zero).

    opened by nnutter 10
  • package imported without types errors when using with Go 1.18

    package imported without types errors when using with Go 1.18

    When using this tool with Go 1.18, I'm seeing errors like

    faillint: internal error: package "time" without types was imported from "github.com/github/my-project-repo/constants"
    

    This might be fixed by bumping golang.org/x/tools to a newer version

    opened by joshmgross 4
  • [Feature Request] Support excluding packages

    [Feature Request] Support excluding packages

    It would be nice to have a flag to exclude a package from a scan.

    Example

    faillint -paths google.golang.org/grpc/status ./pkg/... -exclude ./pkg/server/...
    

    instead of having to do

    faillint -paths google.golang.org/grpc/status ./pkg/log/... ./pkg/metrics/... ./pkg/internal/... # and so on and so forth
    
    opened by dimitarvdimitrov 4
  • Upgrade `golang.org/x/tools` to latest version to get a bug fix

    Upgrade `golang.org/x/tools` to latest version to get a bug fix

    Signed-off-by: Alvin Lin [email protected]

    After upgrading to Go 1.19, I started to get this error: Unexpected package creation during export data loading.

    Googling around I found this. So I thought I'd upgrade golang.org/x/tools to latest version to see if it fixes my issue, and it did.

    opened by alvinlin123 3
  • Bump `golang.org/x/tools` version to latest

    Bump `golang.org/x/tools` version to latest

    This PR fixes constant overflow errors which occur when faillint loads any go1.17 module that has statements assigning math.MaxFloat64 to any float64 variables (see #24 and here), by bumping golang.org/x/tools to latest release (v0.1.8).

    opened by saswatamcode 3
  • Error

    Error "could not import C" when using CGO

    if I run this target without build it fails with the error in the title. https://github.com/arribada/i360/blob/master/Makefile#L108

    Here is a github action. https://github.com/arribada/i360/runs/1800460336?check_suite_focus=true

    When I add build as a prerequisite for this target it works fine.

    opened by krasi-georgiev 3
  • Analyse go files with buildtags

    Analyse go files with buildtags

    We have some tests with a buildtag // +build requires_docker at the beginning of the file and I've just realised these files are skipped by faillint and I can't find a way to specify build tags (I also checked a bit the source code). Is there any way to get it working on source files with build tags?

    opened by pracucci 3
  • Add support to path prefixes

    Add support to path prefixes

    We have some use cases where we would like to blacklist an import path prefix so that all import packages belonging to that prefix are blacklisted as well. Would be of any interest to add such feature to the project?

    opened by pracucci 3
  • Skip generated files.

    Skip generated files.

    Hey :wave:

    Any ideas on how to deal with generated files? How can we easily ignore those without many faillint invocations?

    /home/bwplotka/Repos/thanos/pkg/store/storepb/types.pb.go:18:13: declaration "Errorf" from package "fmt" shouldn't be used, suggested: "github.com/pkg/errors.{Errorf}"

    I tried find . -type f -name "*.go" | grep -v vendor/ | grep -vE '*.pb.go' | xargs $(FAILLINT) -paths $(FAILLINT_PATHS) but got:

    -: named files must all be in one directory; have ./test/e2e/ and ./test/e2e/e2ethanos/
    faillint: error during loading
    
    opened by bwplotka 3
  • Add ability to lint only test/benchmark/fuzz functions

    Add ability to lint only test/benchmark/fuzz functions

    Thank you for this tool! I have a use case where I want to ban time.Sleep from test functions to avoid flaky tests. Instead of time.Sleep with a hard-coded timeout, I want to push others to use functions that would retry some operations continuously until some deadline. For that, faillint should be able to operate only on Test*, Benchmark*, and Fuzz* functions. What do you think? Would you be open to adding such an option?

    opened by GiedriusS 1
  • Possibility to detect function from a struct

    Possibility to detect function from a struct

    I'd like a way to block github.com/jmoiron/sqlx, struct DB, function Select, Exec, Must*

    • Must* functions are dangerous in a service context (assuming you don't have recover middleware)
    • Select, Exec, and a few others don't take a context, we need to use *Context( for cancellation aware versions.

    The issue is that these aren't top level functions or vars, but are nested inside an *sqlx.DB.

    Wanted expression:

    github.com/jmoiron/sqlx.DB.{Select,Exec,Must*}
    
    opened by titpetric 0
  • Dot imports

    Dot imports

    I'd like to forbid dot imports on some projects, could faillint catch package aliases or explicitly . with -paths?

    e.g.

    import (
       . "github.com/pkg/errors"
    )
    
    opened by titpetric 0
Releases(v1.11.0)
Owner
Fatih Arslan
Software Engineer. Gopher and Coffee geek. Creator of vim-go. Tool maker.
Fatih Arslan
Search and output the value of JSON by it's path.

golang-cli Get the value of a JSON element via it's path name. Usage ======= jutil ======= Usage: jutil [-p <path>] [-v] Options: -p string

Alexander Dawson 0 Dec 19, 2021
A command-line tool to pretty print your system's PATH environment variable.

Description A command-line tool to pretty print your system's PATH environment variable. The output paths are colorized if they have special associati

Marwan Hawari 3 Aug 7, 2022
Serverless SOAR (Security Orchestration, Automation and Response) framework for automatic inspection and evaluation of security alert

DeepAlert DeepAlert is a serverless framework for automatic response of security alert. Overview DeepAlert receives a security alert that is event of

null 37 Aug 5, 2022
Use AWS SQS as a clipboard to copy and paste across different systems and platforms

sqs_clipboard Use AWS SQS as a clipboard to copy and paste across different systems and platforms. Clipboard contents are encrypted in transit and at

John Taylor 20 May 9, 2022
A API scanner written in GOLANG to scan files recursively and look for API keys and IDs.

GO FIND APIS _____ ____ ______ _____ _ _ _____ _____ _____ _____ / ____|/ __ \ | ____|_ _| \ | | __ \ /\ | __ \_

Sreekanth Sasi 3 Oct 25, 2021
A simple Go utility to display track information from, and send commands to, spotifyd from Tiling Window Managers like Sway and i3

Untitled Spotifyd Controller A simple Go utility to display track information from, and send commands to, spotifyd from Tiling Window Managers like Sw

Matt 2 Mar 8, 2022
planet is a blockchain built using Cosmos SDK and Tendermint and created with Starport.

planet planet is a blockchain built using Cosmos SDK and Tendermint and created with Starport. Get started starport chain serve serve command install

Andrei Ivasko 0 Oct 31, 2021
AWS credential_process utility to assume AWS IAM Roles with Yubikey Touch and Authenticator App TOPT MFA to provide temporary session credentials; With encrypted caching and support for automatic credential refresh.

AWS credential_process utility to assume AWS IAM Roles with Yubikey Touch and Authenticator App TOPT MFA to provide temporary session credentials; With encrypted caching and support for automatic credential refresh.

Ari Palo 15 May 2, 2022
Todo-list - In this project using golang and mySql to create todo-list to Add and remove

TODO-Fullstack-App-Go-Gin-Postgres-React This fullstack application creates a TODO List Web Page using the Go/Gin/Postgres/React Stack. Starting the a

Krishna Nagpure 2 Apr 7, 2022
Rest API to get KVB departures - Written in Go with hexagonal architecture and tracing via OpenTelemetry and Jaeger

KVB API Rest API to get upcoming departures per KVB train station Implemented in Go with hexagonal architecture and tracing via OpenTelemetry and Jaeg

Jan Ritter 3 May 7, 2022
Pokemon Unite scoreboard HUD and extra tools running over captured game feeds using the OpenCV video processing API and Client/Server architecture.

unite Pokemon Unite scoreboard HUD and extra tools running over captured game feeds using the OpenCV video processing API. Client (OBS Live) Server Ar

pidgy 5 Jun 14, 2022
MealPlanr is an application dedicated to the trivial and boring task of meal planning 📅 and generating a shopping list 🛒 .

MealPlanr is an application dedicated to the trivial and boring task of meal planning ?? and generating a shopping list ?? .

Anders Wiggers 1 Mar 1, 2022
The wazuh-integratord is a daemon that allows Wazuh to connect to external APIs and alerting tools such as Slack, VirusTotal and PagerDuty.

The wazuh-integratord is a daemon that allows Wazuh to connect to external APIs and alerting tools such as Slack, VirusTotal and PagerDuty.

Admicro 2 Apr 22, 2022
Awspowertoggle - Web UI and API for quickly starting and stopping AWS environments

aws-power-toggle web UI and API for quickly starting and stopping AWS environmen

null 1 Feb 23, 2022
Fast and light-weight API proxy firewall for request and response validation by OpenAPI specs.

Open Source API Firewall API Firewall is a high-performance proxy with API request and response validation based on OpenAPI/Swagger schema. It is desi

Wallarm 381 Aug 11, 2022
Go library to access geocoding and reverse geocoding APIs

GeoService in Go Code Coverage A geocoding service developed in Go's way, idiomatic and elegant, not just in golang. This product is designed to open

Jerry Zhao 438 Aug 11, 2022
Go library for accessing trending repositories and developers at Github.

go-trending A package to retrieve trending repositories and developers from Github written in golang. This package were inspired by rochefort/git-tren

Andy Grunwald 121 Aug 2, 2022
Go Twitter REST and Streaming API v1.1

go-twitter go-twitter is a Go client library for the Twitter API. Check the usage section or try the examples to see how to access the Twitter API. Fe

Dalton Hubble 1.5k Aug 6, 2022