Skip to content

Gilthoniel/ctxprop

Repository files navigation

codecov Go Reference

ctxprop

ctxprop is a Golang static linter that will report unproper propogation of contexts.

Installation

Linter can be installed as a standalone binary.

go install github.com/Gilthoniel/ctxprop/cmd/ctxprop@latest

Or built locally:

make build
make install

Usage

It can be invoked as a single linter but it is recommended to run it through golangci-lint.

ctxprop [-flag] [package]

What it checks

ctxprop reports calls that pass a context.Context that is not derived from the parent context already in scope. The parent is found by walking the enclosing function (and its parents, for closures) and looking for either:

  • a parameter implementing context.Context, or
  • a parameter exposing a Context() context.Context method (a context provider, e.g. *http.Request).

A context "inherits" from the parent if it is the parent itself, a value derived from it (wrappers like context.WithCancel, struct embedding, type assertions, slice/map lookups storing it, …), or a value returned by the provider's Context() method.

Examples

func handle(ctx context.Context) error {
    return work(context.Background()) // want: must inherit the context from the parent — use ctx instead
}

func handle(ctx context.Context) error {
    sub, cancel := context.WithCancel(ctx)
    defer cancel()
    return work(sub) // ok
}

func serve() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        foo(r.Context())              // ok
        foo(context.Background())     // want: use r.Context() instead
    })
}

func addHandler(ctx context.Context) {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        foo(r.Context()) // ok
        foo(ctx)         // want: use r.Context() instead
    })
}

func run(ctx context.Context) {
    go func() {
        _ = work(ctx)                 // ok
        _ = work(context.Background()) // want: use ctx instead
    }()
}

type MyContext struct {
    context.Context
    IsAuthenticated bool
}

func handle(ctx context.Context) {
    mc := MyContext{Context: ctx}
    _ = work(mc)         // ok
    _ = work(mc.Context) // ok
}

About

Go linter that ensures context propagation

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors