-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhover.go
More file actions
117 lines (96 loc) · 2.96 KB
/
Copy pathhover.go
File metadata and controls
117 lines (96 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main
import (
"fmt"
"strings"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func textDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
uri := params.TextDocument.URI
position := params.Position
// Get document snapshot
doc, ok := globalServer.documents.Get(uri)
if !ok {
return nil, nil
}
// Find diagnostic at cursor position
var finding *Finding
for i, diag := range doc.Diagnostics {
if positionInRange(position, diag.Range) {
if i < len(doc.Findings) {
finding = &doc.Findings[i]
break
}
}
}
if finding == nil {
return nil, nil
}
// Format hover content
content := formatHoverContent(*finding)
return &protocol.Hover{
Contents: protocol.MarkupContent{
Kind: protocol.MarkupKindMarkdown,
Value: content,
},
}, nil
}
// positionInRange checks if a position is within a range
func positionInRange(pos protocol.Position, rng protocol.Range) bool {
// Check if position is after range start
if pos.Line < rng.Start.Line {
return false
}
if pos.Line == rng.Start.Line && pos.Character < rng.Start.Character {
return false
}
// Check if position is before range end
if pos.Line > rng.End.Line {
return false
}
if pos.Line == rng.End.Line && pos.Character > rng.End.Character {
return false
}
return true
}
// formatHoverContent creates markdown documentation for a finding
func formatHoverContent(f Finding) string {
var sb strings.Builder
// Title
fmt.Fprintf(&sb, "# 🔐 Secret Detected: %s\n\n", f.RuleID)
// Description
fmt.Fprintf(&sb, "**Description**: %s\n\n", f.Description)
// Details section
sb.WriteString("## Details\n\n")
fmt.Fprintf(&sb, "- **Rule ID**: `%s`\n", f.RuleID)
fmt.Fprintf(&sb, "- **Location**: Line %d, Column %d-%d\n", f.StartLine, f.StartColumn, f.EndColumn)
if f.Entropy > 0 {
fmt.Fprintf(&sb, "- **Entropy**: %.2f (randomness score)\n", f.Entropy)
}
fmt.Fprintf(&sb, "- **Fingerprint**: `%s`\n", f.Fingerprint)
sb.WriteString("\n")
// Matched content (truncated if too long)
if len(f.Match) > 0 {
match := f.Match
if len(match) > 100 {
match = match[:100] + "..."
}
sb.WriteString("**Matched Content**:\n")
fmt.Fprintf(&sb, "```\n%s\n```\n\n", match)
}
// Recommendations
sb.WriteString("## 🛡️ Recommendations\n\n")
sb.WriteString("1. **Remove the secret** from the code\n")
sb.WriteString("2. **Use environment variables** or secret management tools\n")
sb.WriteString("3. **Rotate the credential** if already committed\n")
sb.WriteString("4. **Add to `.gitleaksignore`** if this is a false positive\n\n")
// How to suppress
sb.WriteString("## 🔕 How to Ignore\n\n")
sb.WriteString("If this is a false positive, add a comment on the line above:\n")
sb.WriteString("```go\n")
sb.WriteString("// gitleaks:allow\n")
sb.WriteString("```\n\n")
sb.WriteString("Or add the fingerprint to `.gitleaksignore`:\n")
fmt.Fprintf(&sb, "```\n%s\n```\n", f.Fingerprint)
return sb.String()
}