Skip to content

Strange capacity misreporting by capslock and capslock-git-diff #295

@deltamualpha

Description

@deltamualpha

I'm still trying to narrow this down to a reproducer, but figured I'd file an issue just to get started.

I've been running capslock-git-diff on internal pipelines at work, and by and large it doesn't report changes -- which is to be expected, most libraries don't change capabilities that often. However, today, I upgraded one internal service to start using 1.26, and ran go fix as part of that. Among other changes, it updated two usages of a range over strings.Split to instead range over strings.SplitSeq; a straightforward enough change.

However, capslock-git-diff reports:

❯ capslock-git-diff -v master .
2026/02/25 23:19:27 analyzing at revision "master"
2026/02/25 23:19:27 running git with args ["rev-parse" "--git-dir"]
2026/02/25 23:19:27 git directory: ".git"
2026/02/25 23:19:27 running git with args ["rev-parse" "--show-prefix"]
2026/02/25 23:19:27 current path in repository: ""
2026/02/25 23:19:27 running git with args ["clone" "--shared" "--no-checkout" "--" ".git" "/var/folders/vl/k9dw37lx0x5bbtzj98plsqbh0000gp/T/2381433021"]
Cloning into '/var/folders/vl/k9dw37lx0x5bbtzj98plsqbh0000gp/T/2381433021'...
done.
2026/02/25 23:19:27 switched to directory "/var/folders/vl/k9dw37lx0x5bbtzj98plsqbh0000gp/T/2381433021"
2026/02/25 23:19:27 running git with args ["checkout" "master" "--"]
Switched to a new branch 'master'
2026/02/25 23:19:27 switched to directory "/var/folders/vl/k9dw37lx0x5bbtzj98plsqbh0000gp/T/2381433021"
2026/02/25 23:19:27 running capslock with args ["-packages=./..." "-output=json" "-granularity=intermediate" "-capabilities=-UNANALYZED"]
2026/02/25 23:19:29 capslock returned "{\n\t\"capabilityInfo\":  [\n\t\t{\n\t\t\t\"packageName\":  \"bufio\",\n\t\t\t\"capabilityName\":  \"FILES\",\n\t\t\t\"capabilit..."
2026/02/25 23:19:29 parsed CapabilityInfoList with 1032 entries
2026/02/25 23:19:29 returned to working directory "/Users/pwd"
2026/02/25 23:19:29 analyzing at revision "."
2026/02/25 23:19:29 running capslock with args ["-packages=./..." "-output=json" "-granularity=intermediate" "-capabilities=-UNANALYZED"]
2026/02/25 23:19:32 capslock returned "{\n\t\"capabilityInfo\":  [\n\t\t{\n\t\t\t\"packageName\":  \"bufio\",\n\t\t\t\"capabilityName\":  \"FILES\",\n\t\t\t\"capabilit..."
2026/02/25 23:19:32 parsed CapabilityInfoList with 1033 entries
Comparing capabilities in "./..." between revisions "master" and "."


Added 1 new use of existing capability:
          NETWORK:    Access to the network

New packages in call paths to capability NETWORK:

Package internal.service.snip/model has capability NETWORK:
               internal.service.snip/model.ParseLicenses
               strings.splitSeq$1
iter.go:41:14  net/http.containsDotDot$1

I've gone and looked at line 41 of iter.go; it certainly does not appear to have any reference to http.containsDotDot in it (which is unexported anyway).

More curiously, if I run capslock directly against the fix'd code:

❯ capslock -packages internal.service.snip/model
Capslock is an experimental tool for static analysis of Go packages.
Share feedback and file bugs at https://github.com/google/capslock.
For additional debugging signals, use verbose mode with -output=verbose
To get machine-readable full analysis output, use -output=json

Analyzed packages:
  internal.library.package v0.0.0-snip
Capslock found no capabilities in this package.

Capslock doesn't think that the package in question has any capabilities at all.

When I run capslock -granularity=intermediate -packages=./... -output=json on both commits and compare the output, the only change is indeed the new appearance of

{
	"packageName":  "model",
	"capabilityName":  "NETWORK",
	"capability":  "CAPABILITY_NETWORK",
	"path":  [
		{
			"name":  "internal.service.snip/model.ParseLicenses",
			"package":  "internal.service.snip/model"
		},
		{
			"name":  "strings.splitSeq$1",
			"package":  "strings"
		},
		{
			"name":  "net/http.containsDotDot$1",
			"site":  {
				"filename":  "iter.go",
				"line":  "41",
				"column":  "14"
			},
			"package":  "net/http"
		}
	],
	"packageDir":  "internal.service.snip/model"
}

So somehow, capslock is convinced that the strings package imports and uses a private function from net/http.

I've tried a narrow reproducer of a git repo that just has

func main() {
	// doesn't actually matter what we do
	for _, s := range strings.Split("a,b,c", ",") {
		fmt.Println(s)
	}
}

and

func main() {
	// doesn't actually matter what we do
	for s := range strings.SplitSeq("a,b,c", ",") {
		fmt.Println(s)
	}
}

as the two commits, but that doesn't seem to trigger it.

Do you have any further guidance on how I can debug this strange behavior?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions