Enforce Go style rules across codebase

Apply five style rules: convert iota string enums to typed
string constants, replace errors.As with errors.AsType,
merge three-group imports into two groups, fix multiline
parameter/argument formatting, and replace fmt.Sprintf URL
construction with net/url.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-05-20 11:46:39 +04:00
parent 34c25c2727
commit f5703d390b
105 changed files with 1180 additions and 940 deletions

View File

@@ -68,9 +68,11 @@ func CheckCORSTool() agent.Tool {
"Send a CORS preflight (OPTIONS) request to a URL with a given Origin and analyze the Access-Control-* response headers, flagging wildcard origins and origin reflection.",
func(ctx context.Context, p corsParams) (agent.ToolResult, error) {
if err := netcheck.ValidatePublicURL(p.URL); err != nil {
return agent.ResultJSON(corsResult{
ErrorDetail: fmt.Sprintf("URL not allowed: %s", err),
}), nil
return agent.ResultJSON(
corsResult{
ErrorDetail: fmt.Sprintf("URL not allowed: %s", err),
},
), nil
}
client := &http.Client{
@@ -87,9 +89,11 @@ func CheckCORSTool() agent.Tool {
nil,
)
if err != nil {
return agent.ResultJSON(corsResult{
ErrorDetail: fmt.Sprintf("cannot build request: %s", err),
}), nil
return agent.ResultJSON(
corsResult{
ErrorDetail: fmt.Sprintf("cannot build request: %s", err),
},
), nil
}
req.Header.Set("Origin", p.Origin)
@@ -97,9 +101,11 @@ func CheckCORSTool() agent.Tool {
resp, err := client.Do(req)
if err != nil {
return agent.ResultJSON(corsResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", p.URL, err),
}), nil
return agent.ResultJSON(
corsResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", p.URL, err),
},
), nil
}
defer func() { _ = resp.Body.Close() }()

View File

@@ -81,16 +81,20 @@ func AnalyzeCSPTool() agent.Tool {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.URL, nil)
if err != nil {
return agent.ResultJSON(cspResult{
ErrorDetail: fmt.Sprintf("cannot create request for %s: %s", p.URL, err),
}), nil
return agent.ResultJSON(
cspResult{
ErrorDetail: fmt.Sprintf("cannot create request for %s: %s", p.URL, err),
},
), nil
}
resp, err := client.Do(req)
if err != nil {
return agent.ResultJSON(cspResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", p.URL, err),
}), nil
return agent.ResultJSON(
cspResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", p.URL, err),
},
), nil
}
defer func() { _ = resp.Body.Close() }()

View File

@@ -73,10 +73,12 @@ func CheckDMARCTool() agent.Tool {
},
)
if err != nil {
return agent.ResultJSON(dmarcResult{
Found: false,
ErrorDetail: fmt.Sprintf("cannot lookup DMARC record: %s", err),
}), nil
return agent.ResultJSON(
dmarcResult{
Found: false,
ErrorDetail: fmt.Sprintf("cannot lookup DMARC record: %s", err),
},
), nil
}
for _, answer := range answers {

View File

@@ -61,10 +61,12 @@ func CheckDNSSECTool() agent.Tool {
withDNSSEC(),
)
if err != nil {
return agent.ResultJSON(dnssecResult{
Enabled: false,
ErrorDetail: fmt.Sprintf("cannot query DNSKEY records: %s", err),
}), nil
return agent.ResultJSON(
dnssecResult{
Enabled: false,
ErrorDetail: fmt.Sprintf("cannot query DNSKEY records: %s", err),
},
), nil
}
var (

View File

@@ -18,6 +18,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
"time"
@@ -79,9 +80,11 @@ func CheckSecurityHeadersTool() agent.Tool {
"Check security-related HTTP headers for a URL (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-*-Policy). Also checks if HTTP redirects to HTTPS.",
func(ctx context.Context, p headersParams) (agent.ToolResult, error) {
if err := netcheck.ValidatePublicURL(p.URL); err != nil {
return agent.ResultJSON(headersResult{
ErrorDetail: fmt.Sprintf("URL not allowed: %s", err),
}), nil
return agent.ResultJSON(
headersResult{
ErrorDetail: fmt.Sprintf("URL not allowed: %s", err),
},
), nil
}
client := &http.Client{
@@ -94,11 +97,19 @@ func CheckSecurityHeadersTool() agent.Tool {
// First check the HTTP version to detect HTTP→HTTPS redirect.
redirectsToHTTPS := false
httpURL := p.URL
if after, ok := strings.CutPrefix(httpURL, "https://"); ok {
httpURL = "http://" + after
parsedURL, err := url.Parse(p.URL)
if err != nil {
return agent.ResultJSON(
headersResult{
ErrorDetail: fmt.Sprintf("cannot parse URL: %s", err),
},
), nil
}
httpParsed := *parsedURL
httpParsed.Scheme = "http"
httpURL := httpParsed.String()
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, httpURL, nil)
if err == nil {
httpResp, err := client.Do(httpReq)
@@ -114,25 +125,28 @@ func CheckSecurityHeadersTool() agent.Tool {
}
// Now check the HTTPS version for the actual security headers.
httpsURL := p.URL
if after, ok := strings.CutPrefix(httpsURL, "http://"); ok {
httpsURL = "https://" + after
}
httpsParsed := *parsedURL
httpsParsed.Scheme = "https"
httpsURL := httpsParsed.String()
followClient := &http.Client{Timeout: 10 * time.Second}
httpsReq, err := http.NewRequestWithContext(ctx, http.MethodGet, httpsURL, nil)
if err != nil {
return agent.ResultJSON(headersResult{
ErrorDetail: fmt.Sprintf("cannot create request for %s: %s", httpsURL, err),
}), nil
return agent.ResultJSON(
headersResult{
ErrorDetail: fmt.Sprintf("cannot create request for %s: %s", httpsURL, err),
},
), nil
}
resp, err := followClient.Do(httpsReq)
if err != nil {
return agent.ResultJSON(headersResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", httpsURL, err),
}), nil
return agent.ResultJSON(
headersResult{
ErrorDetail: fmt.Sprintf("cannot fetch %s: %s", httpsURL, err),
},
), nil
}
defer func() { _ = resp.Body.Close() }()

View File

@@ -61,34 +61,48 @@ func CheckBreachesTool() agent.Tool {
func(ctx context.Context, p hibpParams) (agent.ToolResult, error) {
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequestWithContext(
ctx,
http.MethodGet,
"https://haveibeenpwned.com/api/v3/breaches?domain="+url.QueryEscape(p.Domain),
nil,
)
hibpURL, err := url.Parse("https://haveibeenpwned.com/api/v3/breaches")
if err != nil {
return agent.ResultJSON(hibpResult{
ErrorDetail: fmt.Sprintf("cannot create request: %s", err),
}), nil
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("cannot parse HIBP URL: %s", err),
},
), nil
}
q := hibpURL.Query()
q.Set("domain", p.Domain)
hibpURL.RawQuery = q.Encode()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, hibpURL.String(), nil)
if err != nil {
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("cannot create request: %s", err),
},
), nil
}
req.Header.Set("User-Agent", "Probo-Vendor-Assessment")
resp, err := client.Do(req)
if err != nil {
return agent.ResultJSON(hibpResult{
ErrorDetail: fmt.Sprintf("cannot fetch breaches: %s", err),
}), nil
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("cannot fetch breaches: %s", err),
},
), nil
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil {
return agent.ResultJSON(hibpResult{
ErrorDetail: fmt.Sprintf("cannot read response: %s", err),
}), nil
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("cannot read response: %s", err),
},
), nil
}
if resp.StatusCode == http.StatusNotFound {
@@ -96,23 +110,29 @@ func CheckBreachesTool() agent.Tool {
}
if resp.StatusCode != http.StatusOK {
return agent.ResultJSON(hibpResult{
ErrorDetail: fmt.Sprintf("HIBP API returned status %d", resp.StatusCode),
}), nil
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("HIBP API returned status %d", resp.StatusCode),
},
), nil
}
var breaches []breach
if err := json.Unmarshal(body, &breaches); err != nil {
return agent.ResultJSON(hibpResult{
ErrorDetail: fmt.Sprintf("cannot parse response: %s", err),
}), nil
return agent.ResultJSON(
hibpResult{
ErrorDetail: fmt.Sprintf("cannot parse response: %s", err),
},
), nil
}
return agent.ResultJSON(hibpResult{
Found: len(breaches) > 0,
Count: len(breaches),
Breaches: breaches,
}), nil
return agent.ResultJSON(
hibpResult{
Found: len(breaches) > 0,
Count: len(breaches),
Breaches: breaches,
},
), nil
},
)
}

View File

@@ -77,10 +77,12 @@ func CheckSPFTool() agent.Tool {
},
)
if err != nil {
return agent.ResultJSON(spfResult{
Found: false,
ErrorDetail: fmt.Sprintf("cannot lookup SPF record: %s", err),
}), nil
return agent.ResultJSON(
spfResult{
Found: false,
ErrorDetail: fmt.Sprintf("cannot lookup SPF record: %s", err),
},
), nil
}
var spfRecords []string
@@ -100,21 +102,25 @@ func CheckSPFTool() agent.Tool {
}
if len(spfRecords) > 1 {
return agent.ResultJSON(spfResult{
Found: true,
ErrorDetail: fmt.Sprintf("multiple SPF records found (%d); this is an invalid configuration per RFC 7208", len(spfRecords)),
}), nil
return agent.ResultJSON(
spfResult{
Found: true,
ErrorDetail: fmt.Sprintf("multiple SPF records found (%d); this is an invalid configuration per RFC 7208", len(spfRecords)),
},
), nil
}
if len(spfRecords) == 1 {
record := spfRecords[0]
return agent.ResultJSON(spfResult{
Found: true,
RawRecord: record,
Policy: parseSPFPolicy(record),
Mechanisms: record,
}), nil
return agent.ResultJSON(
spfResult{
Found: true,
RawRecord: record,
Policy: parseSPFPolicy(record),
Mechanisms: record,
},
), nil
}
return agent.ResultJSON(spfResult{Found: false}), nil

View File

@@ -66,10 +66,12 @@ func CheckSSLCertificateTool() agent.Tool {
"Check the SSL/TLS certificate for a domain, returning issuer, expiry, protocol version, and validity.",
func(ctx context.Context, p sslParams) (agent.ToolResult, error) {
if err := netcheck.ValidatePublicDomain(p.Domain); err != nil {
return agent.ResultJSON(sslResult{
Valid: false,
ErrorDetail: fmt.Sprintf("domain not allowed: %s", err),
}), nil
return agent.ResultJSON(
sslResult{
Valid: false,
ErrorDetail: fmt.Sprintf("domain not allowed: %s", err),
},
), nil
}
// This is a certificate inspection tool: we intentionally
@@ -96,20 +98,24 @@ func CheckSSLCertificateTool() agent.Tool {
}
if err != nil {
return agent.ResultJSON(sslResult{
Valid: false,
ErrorDetail: err.Error(),
}), nil
return agent.ResultJSON(
sslResult{
Valid: false,
ErrorDetail: err.Error(),
},
), nil
}
defer func() { _ = conn.Close() }()
state := conn.ConnectionState()
if len(state.PeerCertificates) == 0 {
return agent.ResultJSON(sslResult{
Valid: false,
ErrorDetail: "no peer certificates",
}), nil
return agent.ResultJSON(
sslResult{
Valid: false,
ErrorDetail: "no peer certificates",
},
), nil
}
cert := state.PeerCertificates[0]

View File

@@ -50,17 +50,21 @@ func CheckWhoisTool() agent.Tool {
"Perform a WHOIS lookup on a domain to retrieve registration details including registrar, creation date, expiry date, registrant organization, and name servers.",
func(ctx context.Context, p whoisParams) (agent.ToolResult, error) {
if err := netcheck.ValidatePublicDomain(p.Domain); err != nil {
return agent.ResultJSON(whoisResult{
ErrorDetail: fmt.Sprintf("domain not allowed: %s", err),
}), nil
return agent.ResultJSON(
whoisResult{
ErrorDetail: fmt.Sprintf("domain not allowed: %s", err),
},
), nil
}
// Step 1: query IANA to find the referral WHOIS server.
referral, err := queryWhois(ctx, "whois.iana.org:43", p.Domain)
if err != nil {
return agent.ResultJSON(whoisResult{
ErrorDetail: fmt.Sprintf("cannot query IANA WHOIS: %s", err),
}), nil
return agent.ResultJSON(
whoisResult{
ErrorDetail: fmt.Sprintf("cannot query IANA WHOIS: %s", err),
},
), nil
}
whoisServer := parseWhoisField(referral, "refer")
@@ -87,17 +91,21 @@ func CheckWhoisTool() agent.Tool {
}
if err := netcheck.ValidatePublicDomain(whoisHost); err != nil {
return agent.ResultJSON(whoisResult{
ErrorDetail: fmt.Sprintf("WHOIS referral server not allowed: %s", err),
}), nil
return agent.ResultJSON(
whoisResult{
ErrorDetail: fmt.Sprintf("WHOIS referral server not allowed: %s", err),
},
), nil
}
// Step 2: query the registrar's WHOIS server.
raw, err := queryWhois(ctx, whoisServer, p.Domain)
if err != nil {
return agent.ResultJSON(whoisResult{
ErrorDetail: fmt.Sprintf("cannot query WHOIS server %s: %s", whoisServer, err),
}), nil
return agent.ResultJSON(
whoisResult{
ErrorDetail: fmt.Sprintf("cannot query WHOIS server %s: %s", whoisServer, err),
},
), nil
}
result := parseWhoisResponse(raw)