Repository Analysis

juanfont/headscale

An open source, self-hosted implementation of the Tailscale control server

2.2 Likely human-written View on GitHub
2.2
Adjusted Score
2.2
Raw Score
100%
Time Factor
2026-05-29
Last Push
39,429
Stars
Go
Language
157,776
Lines of Code
403
Files
314
Pattern Hits
2026-05-31
Scan Date

Score History

Severity Breakdown

CRITICAL 0HIGH 0MEDIUM 2LOW 312

Pattern Findings

314 matches across 5 categories. Click a row to expand file-level details.

Over-Commented Block180 hits · 174 pts
SeverityFileLineSnippet
LOWconfig-example.yaml1---
LOWconfig-example.yaml21# Address to listen to /metrics and /debug, you may want
LOWconfig-example.yaml41
LOWconfig-example.yaml61# WARNING: These prefixes MUST be subsets of the standard Tailscale ranges:
LOWconfig-example.yaml81 # IP. A best-effort approach is used and Headscale might leave holes in the
LOWconfig-example.yaml121 # If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using D
LOWconfig-example.yaml141 paths: []
LOWconfig-example.yaml161 #
LOWconfig-example.yaml181 #
LOWconfig-example.yaml221 # Enable WAL mode for SQLite. This is recommended for production environments.
LOWconfig-example.yaml241 # max_idle_conns: 10
LOWconfig-example.yaml261# Domain name to request a TLS certificate for:
LOWconfig-example.yaml301## DNS
LOWconfig-example.yaml341 - 2606:4700:4700::1111
LOWconfig-example.yaml361 # Extra DNS records
LOWconfig-example.yaml381# OpenID Connect
LOWconfig-example.yaml401# # Use the expiry from the token received from OpenID when the user logged
LOWconfig-example.yaml421# extra_params:
LOWconfig-example.yaml441# pkce:
LOWconfig-example.yaml461# Taildrop configuration
LOWconfig-example.yaml481# Only modify these if you have identified a specific performance issue.
LOWcmd/vendorhash/main.go1// vendorhash maintains the Nix SRI hash for the Go module vendor tree
LOWintegration/auth_oidc_test.go121 t.Fatalf("unexpected users: %s", diff)
LOWintegration/auth_oidc_test.go1081 listNodes, err := headscale.ListNodes()
LOWintegration/auth_oidc_test.go1101// - The test verifies that the node ID is preserved (since it's the same user on the same device)
LOWintegration/auth_oidc_test.go1321 }
LOWintegration/auth_oidc_test.go1461// policy applied until they restarted their client. This was a regression
LOWintegration/auth_oidc_test.go1741 }, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "headscale should have correct users and no
LOWintegration/auth_key_test.go561
LOWintegration/acl_test.go621 assert.EventuallyWithT(t, func(c *assert.CollectT) {
LOWintegration/acl_test.go641// "SrcIPs": ["*"]
LOWintegration/acl_test.go3141//
LOWintegration/acl_test.go3301 // Additional verification: check filter rules are not empty
LOWintegration/acl_test.go3461// This test verifies that:
LOWintegration/auth_web_flow_test.go201// initially authenticate using the web-based authentication flow (where users visit a URL
LOWintegration/tags_test.go2781 assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
LOWintegration/tags_test.go3081 t.Logf("Test 5.2 PASS: Registration correctly rejected with error: %v", err)
LOWintegration/route_test.go2161 panic("node not found")
LOWintegration/route_test.go3841 ip, err := subRouter2.IPv4()
LOWintegration/route_test.go4061// than a graceful tailscale down. The two differ in what the server sees:
LOWintegration/route_test.go4261 assert.Contains(c, peer.PrimaryRoutes.AsSlice(), pref)
LOWintegration/route_test.go4281// resumes when r1 returns.
LOWintegration/scenario.go61 // The list contains two special cases, "head" and "unstable" which
LOWintegration/scenario.go141 // Networks, if set, is the separate Docker networks that should be
LOWintegration/scenario.go1741 // endpoint.
LOWintegration/scenario.go1761 // return errStatusCodeNotOK
LOWintegration/tsic/tsic.go1021// Netmap returns the current Netmap ([netmap.NetworkMap]) of the Tailscale instance.
LOWhscontrol/grpcv1.go281 // dependency here.
LOWhscontrol/auth_test.go2301 "error-test-method",
LOWhscontrol/auth_test.go2941 t.Logf("✓ New node created for user1 with machine key from %s (ID=%d)", node.hostname, newNode.ID().Uint64())
LOWhscontrol/auth_test.go3161
LOWhscontrol/auth_test.go3441 assert.Equal(t, initialNodeID, allNodes.At(0).ID(), "node ID should not change on re-registration")
LOWhscontrol/auth_test.go3781
LOWhscontrol/auth.go61 }
LOWhscontrol/auth.go381 }
LOWhscontrol/oidc.go861 )
LOWhscontrol/app.go221 for _, d := range magicDNSDomains {
LOWhscontrol/noise.go181 // /whoami is a debug endpoint to validate that the client can communicate over the connection,
LOWhscontrol/auth_tags_test.go1261 assert.True(t, node2.Expiry().Get().After(firstExpiry),
LOWhscontrol/types/users.go61
120 more matches not shown…
Verbosity Indicators94 hits · 134 pts
SeverityFileLineSnippet
LOWintegration/auth_oidc_test.go1834 // Step 1: Verify initial route is advertised, approved, and SERVING
LOWintegration/auth_oidc_test.go1863 // Step 2: Logout
LOWintegration/auth_oidc_test.go1885 // Step 3: Re-authenticate via OIDC as the same user
LOWintegration/auth_oidc_test.go1903 // Step 4: THE CRITICAL TEST - Verify routes are STILL SERVING after re-authentication
LOWintegration/auth_key_test.go640 // Step 1: Verify initial route is advertised, approved, and SERVING
LOWintegration/auth_key_test.go669 // Step 2: Logout
LOWintegration/auth_key_test.go691 // Step 3: Re-authenticate with the SAME user (using auth key)
LOWintegration/auth_key_test.go714 // Step 4: THE CRITICAL TEST - Verify routes are STILL SERVING after re-authentication
LOWintegration/acl_test.go2576 // Step 1: Verify initial access state
LOWintegration/acl_test.go2609 // Step 2: Apply tag change
LOWintegration/acl_test.go2627 // Step 3: Verify final NetMap visibility first (fast signal that
LOWintegration/acl_test.go2655 // Step 4: Verify final access state (this is the key test for #2389).
LOWintegration/acl_test.go2812 // Step 1: Verify initial state - HTTP on port 80 should work with tag:webserver
LOWintegration/acl_test.go2818 // Step 2: Change tag from webserver to sshonly
LOWintegration/acl_test.go2839 // Step 3: Verify peer is still visible in NetMap (partial access, not full removal)
LOWintegration/acl_test.go2858 // Step 4: Verify HTTP on port 80 now fails (tag:sshonly only allows port 22).
LOWintegration/acl_test.go3054 // Step 1: Verify initial connectivity - all users can reach each other
LOWintegration/acl_test.go3066 // Step 2: Get user3's node and user, then delete them
LOWintegration/acl_test.go3091 // Step 3: Verify that user1 and user2 can still communicate (before triggering policy refresh)
LOWintegration/acl_test.go3102 // Step 4: Create a NEW user - this triggers [State.updatePolicyManagerUsers] which
LOWintegration/acl_test.go3114 // Step 5: THIS IS THE CRITICAL TEST - verify connectivity STILL works after
LOWintegration/acl_test.go3231 // Step 1: Verify initial connectivity - user1 and user3 can ping each other
LOWintegration/acl_test.go3245 // Step 2: Delete user2's node and user (like reporter deleting "deleteable")
LOWintegration/acl_test.go3263 // Step 3: Verify connectivity still works after user2 deletion
LOWintegration/acl_test.go3278 // Step 4: Create a NEW user - this triggers [State.updatePolicyManagerUsers]
LOWintegration/acl_test.go3285 // Step 5: THE CRITICAL TEST - verify connectivity STILL works
LOWintegration/acl_test.go3395 // Step 1: Verify initial connectivity with VALID policy
LOWintegration/acl_test.go3409 // Step 2: DYNAMICALLY update policy to add unknown user
LOWintegration/acl_test.go3439 // Step 3: THE CRITICAL TEST - verify connectivity STILL works
LOWintegration/acl_test.go3543 // Step 1: Verify initial connectivity WITH unknown user in policy
LOWintegration/acl_test.go3558 // Step 2: Update policy to REMOVE the unknown user
LOWintegration/acl_test.go3587 // Step 3: Verify connectivity after removing unknown user
LOWintegration/tags_test.go526 // Step 2: Admin assigns different tags via headscale CLI
LOWintegration/tags_test.go548 // Step 3: Force reauthentication
LOWintegration/tags_test.go650 // Step 2: Admin assigns multiple tags via headscale CLI
LOWintegration/tags_test.go671 // Step 3: Attempt to reduce tags via CLI
LOWintegration/tags_test.go1012 // Step 2: Admin assigns tags
LOWintegration/tags_test.go1033 // Step 3: Run tailscale up with --reset
LOWintegration/tags_test.go1131 // Step 2: Admin assigns tags
LOWintegration/tags_test.go1152 // Step 3: Run tailscale up with empty --advertise-tags
LOWintegration/tags_test.go1250 // Step 2: Admin assigns multiple tags
LOWintegration/tags_test.go1271 // Step 3: Attempt to reduce tags via CLI
LOWintegration/tags_test.go1549 // Step 1: Create and register with one tag
LOWintegration/tags_test.go1579 // Step 2: Try to add second tag via CLI
LOWintegration/tags_test.go1640 // Step 1: Create and register with two tags
LOWintegration/tags_test.go1670 // Step 2: Try to remove second tag via CLI
LOWintegration/tags_test.go1731 // Step 1: Register with one tag
LOWintegration/tags_test.go1765 // Step 2: Admin assigns different tag
LOWintegration/tags_test.go1785 // Step 3: Try to change tags via CLI
LOWintegration/tags_test.go1848 // Step 1: Register with one tag
LOWintegration/tags_test.go1881 // Step 2: Admin assigns both tags
LOWintegration/tags_test.go1901 // Step 3: Try to reduce tags via CLI
LOWintegration/tags_test.go2575 // Step 2: Admin changes tag to tag:second (FIRST CALL - this is "tag:bar" in issue terms)
LOWintegration/tags_test.go2630 // Step 3: Call SetNodeTags AGAIN with the SAME tag (SECOND CALL)
LOWintegration/tags_test.go2649 // Step 4: Do another tag change to verify the pattern repeats
LOWintegration/tags_test.go2685 // Step 5: Call SetNodeTags AGAIN with the SAME tag
LOWintegration/tags_test.go2835 // Step 1: Create and register a node with tags
LOWintegration/tags_test.go2876 // Step 2: Reauth with empty tags to remove all tags
LOWintegration/tags_test.go2921 // Step 3: Verify tags are removed and ownership is returned to user
LOWintegration/tags_test.go3126 // Step 1: Create a tags-only preauthkey WITHOUT a user.
34 more matches not shown…
Fake / Example Data36 hits · 36 pts
SeverityFileLineSnippet
LOWhscontrol/types/testcapture/testcapture_test.go424 "full_policy": {"tagOwners": {"tag:ops": ["user@example.com"]}},
LOWhscontrol/types/testcapture/testcapture_test.go442 want := `{"tagOwners":{"tag:ops":["user@example.com"]}}`
LOWhscontrol/templates/auth_success.go25 // e.g. "user@example.com".
LOWhscontrol/policy/v2/policy_test.go828 {Model: gorm.Model{ID: 1}, Name: "admin", Email: "admin@example.com"},
LOWhscontrol/policy/v2/policy_test.go867 "group:admin": ["admin@example.com"]
LOWhscontrol/policy/v2/policy_test.go995 {Model: gorm.Model{ID: 2}, Name: "admin", Email: "admin@example.com"},
LOWhscontrol/policy/v2/policy_test.go1077 "group:admin": ["admin@example.com"],
LOWhscontrol/policy/v2/policy_test.go1164 {Model: gorm.Model{ID: 1}, Name: "admin", Email: "admin@example.com"},
LOWhscontrol/policy/v2/policy_test.go1194 "group:admin": ["admin@example.com"]
LOWhscontrol/policy/v2/policy_test.go1232 {Model: gorm.Model{ID: 1}, Name: "admin", Email: "admin@example.com"},
LOWhscontrol/policy/v2/policy_test.go1271 "group:admin": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go42 Group("group:example"): []Username{Username("user@example.com")},
LOWhscontrol/policy/v2/types_test.go48 Tag("tag:test"): Owners{up("user@example.com")},
LOWhscontrol/policy/v2/types_test.go55 new(Username("user@example.com")),
LOWhscontrol/policy/v2/types_test.go74 assert.Contains(t, jsonString, "user@example.com")
LOWhscontrol/policy/v2/types_test.go661 "group:admins": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go682 Group("group:admins"): []Username{Username("admin@example.com")},
LOWhscontrol/policy/v2/types_test.go709 "tag:web": ["admin@example.com"],
LOWhscontrol/policy/v2/types_test.go710 "tag:server": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go733 "group:admins": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go752 Group("group:admins"): []Username{Username("admin@example.com")},
LOWhscontrol/policy/v2/types_test.go1031 "group:test": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1032 "INVALID_GROUP_FIELD": ["user@example.com"]
LOWhscontrol/policy/v2/types_test.go1043 "group:test": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1055 "group:test": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1079 "tag:test": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1110 "src": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1111 "dst": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1143 "10.0.0.0/8": ["user@example.com"]
LOWhscontrol/policy/v2/types_test.go1145 "exitNode": ["user@example.com"],
LOWhscontrol/policy/v2/types_test.go1198 "user@example.com"
LOWhscontrol/policy/v2/types_test.go1201 "user@example.com"
LOWhscontrol/policy/v2/types_test.go2175 "tag:client": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go2197 "tag:client": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go2217 "tag:client": ["admin@example.com"]
LOWhscontrol/policy/v2/types_test.go2237 "tag:client": ["admin@example.com"]
AI Slop Vocabulary2 hits · 6 pts
SeverityFileLineSnippet
MEDIUMintegration/route_test.go683 // Get the expected router IP - use a more robust approach to handle temporary disconnections
MEDIUMintegration/dockertestutil/config.go70 // This could be improved with more robust detection if needed
Redundant / Tautological Comments2 hits · 3 pts
SeverityFileLineSnippet
LOWintegration/run.sh59# Check if both arguments are provided
LOW.github/workflows/needs-more-info-timer.yml81 # Check if 3 days have passed