title: Content of go.sum and modules really used by a go application
body: <p>I'm trying to compare the behavior of <code>go mod tidy</code> (and the resulting content of go.sum) to the output of <code>go list -m all</code>.
  Reading the docs, I understand go.sum contains the whole list of dependent modules declared in go.mod and in dependencies' go.mod files, <code>go list -m all</code> shows the modules really loaded during the execution.
  As an example, an application including logrus and prometheus like this:</p>
  <p>go.mod</p>
  <pre><code>module mytest
  
  go 1.14
  
  require (
          github.com/prometheus/common v0.4.0
          github.com/sirupsen/logrus v1.8.1
  )
  </code></pre>
  <p>main.go</p>
  <pre><code>package main
  
  import &quot;github.com/sirupsen/logrus&quot;
  import &quot;github.com/prometheus/common/version&quot;
  
  func main() {
    logrus.Info(&quot;Hello World&quot;)
    logrus.Infof(&quot;Prometheus info: %v&quot;, version.Info())
  }
  </code></pre>
  <p>After <code>go mod tidy</code>, go.sum shows both logrus v1.8.1, requested by the go.mod, and 1.2.0, dependency of prometheus v0.4.0; <code>go list -m all</code> shows only v1.8.1.</p>
  <p>go.sum</p>
  <pre><code>[...]
  github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
  github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
  github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
  [...]
  </code></pre>
  <p>output of go list</p>
  <pre><code>[...]
  github.com/sirupsen/logrus v1.8.1
  [...]
  </code></pre>
  <p><strong>Is it correct to say the modules really used by the application are listed by <code>go list -m all</code>?</strong></p>
  <p>The underlying problem is that a static code analysis detects insecure module versions listed in go.sum, but actually these versions don't show up in <code>go list -m all</code>, hence they shouldn't be really used by the application, but only downloaded during build phase to select the proper minimal version.</p>
  <p>Some reference:</p>
  <p><a href="https://go.dev/ref/mod#go-mod-tidy" rel="nofollow noreferrer">https://go.dev/ref/mod#go-mod-tidy</a></p>
  <blockquote>
  <p>go mod tidy acts as if all build tags are enabled, so it will consider
  platform-specific source files and files that require custom build
  tags, even if those source files wouldn’t normally be built.</p>
  </blockquote>
  <p><a href="https://go.dev/ref/mod#go-sum-files" rel="nofollow noreferrer">https://go.dev/ref/mod#go-sum-files</a></p>
  <blockquote>
  <p>The go.sum file may contain hashes for multiple versions of a module.
  The go command may need to load go.mod files from multiple versions of
  a dependency in order to perform minimal version selection. go.sum may
  also contain hashes for module versions that aren’t needed anymore
  (for example, after an upgrade).</p>
  </blockquote>
  <p><a href="https://github.com/golang/go/wiki/Modules#is-gosum-a-lock-file-why-does-gosum-include-information-for-module-versions-i-am-no-longer-using" rel="nofollow noreferrer">https://github.com/golang/go/wiki/Modules#is-gosum-a-lock-file-why-does-gosum-include-information-for-module-versions-i-am-no-longer-using</a></p>
  <blockquote>
  <p>[...]In addition, your module's go.sum records checksums for all
  direct and indirect dependencies used in a build (and hence your
  go.sum will frequently have more modules listed than your go.mod).</p>
  </blockquote>
  <p><a href="https://github.com/golang/go/wiki/Modules#version-selection" rel="nofollow noreferrer">https://github.com/golang/go/wiki/Modules#version-selection</a></p>
  <blockquote>
  <p>The minimal version selection algorithm is used to select the versions
  of all modules used in a build. For each module in a build, the
  version selected by minimal version selection is always the
  semantically highest of the versions explicitly listed by a require
  directive in the main module or one of its dependencies.</p>
  <p>As an example, if your module depends on module <code>A</code> which has a
  <code>require D v1.0.0</code>, and your module also depends on module <code>B</code> which
  has a <code>require D v1.1.1</code>, then minimal version selection would choose
  v1.1.1 of D to include in the build (given it is the highest listed
  require version). [...] To see a list of the selected module versions
  (including indirect dependencies), use <code>go list -m all</code>.</p>
  </blockquote>