Skip to content

Add AnalysisError type and wrap all analyzer error paths#4779

Open
johnelliott wants to merge 3 commits intomainfrom
enhance/analysis-errors
Open

Add AnalysisError type and wrap all analyzer error paths#4779
johnelliott wants to merge 3 commits intomainfrom
enhance/analysis-errors

Conversation

@johnelliott
Copy link

@johnelliott johnelliott commented Feb 27, 2026

What this does

Adds a shared error type so analyzer failures carry structured metadata (analyzer type, operation, service). Currently only GCP errors have this; the other 44 analyzers return bare errors.New that get stored as "unknown" in the database.

How to review

Read one file, skip the other 44. There are only 2 things to look at:

1. The new error type (entire abstraction)

pkg/analyzer/analyzers/errors.go -- 51 lines, new file:

type AnalysisErrorInfo interface {
    error
    AnalyzerType() string
    Operation() string  // "validate_credentials", "analyze_permissions"
    Service() string    // "API", "Database", "OAuth", "config"
    Resource() string
}

type AnalysisError struct {
    analyzerType, operation, service, resource string
    err error
}

func NewAnalysisError(analyzerType, operation, service, resource string, err error) *AnalysisError

2. The pattern every analyzer follows

Every analyzer diff looks like this (Airbrake shown):

// Before:
return nil, err

// After:
return nil, analyzers.NewAnalysisError("Airbrake", "analyze_permissions", "API", "", err)

The original error is wrapped, not replaced (Unwrap() preserves the chain). Two operations are used: "validate_credentials" for bad input, "analyze_permissions" for API/DB failures.

All 44 analyzer files are this same 1-3 line change. You can spot-check a few and skip the rest.

Part of a cross-repo change

Order Repo PR What
1 trufflehog this PR Define error type, wrap 44 analyzers
2 integrations #118 Wrap 10 integrations analyzers
3 thog #5724 Scanner consumes the metadata via errors.As()

Test plan

  • go test ./pkg/analyzer/analyzers/... (includes errors_test.go)
  • go build ./pkg/analyzer/analyzers/...

Introduce a shared error type that provides structured metadata
(analyzer type, operation, service, resource) for analysis failures.
This allows the scanner to extract context from errors without
depending on concrete types.
Batch A: Airbrake, Anthropic, Asana, DigitalOcean, DockerHub,
ElevenLabs, Fastly, Groq, HuggingFace, Mailchimp, Mailgun, Mux,
Netlify, Ngrok, Notion, OpenAI, Opsgenie, Posthog, Postman,
Sendgrid, Sourcegraph.

Wraps credential validation errors with operation
"validate_credentials" and AnalyzePermissions errors with
operation "analyze_permissions".
Batch B (OAuth/multi-credential): airtableoauth, airtablepat, datadog,
dropbox, figma, launchdarkly, plaid
Batch C (Complex): bitbucket, databricks, github, gitlab, jira, monday,
planetscale, shopify, slack, square, stripe, twilio
Batch D (Database): mysql, postgres (service: Database)
Batch E (PrivateKey): privatekey (service: crypto)
@johnelliott johnelliott requested a review from a team February 27, 2026 20:54
@johnelliott johnelliott requested a review from a team as a code owner February 27, 2026 20:54
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

return nil, err
return nil, analyzers.NewAnalysisError(
"Airbrake", "analyze_permissions", "API", "", err,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded analyzer type strings duplicate existing constants

Low Severity

Every NewAnalysisError call across all 43 analyzers passes a hardcoded string like "Airbrake", "GitHub", etc. for the analyzer type. These exact strings already exist in analyzerTypeStrings and are accessible via a.Type().String() from within each Analyze method. This duplication means a future analyzer addition or rename requires updating both the analyzerTypeStrings map and each NewAnalysisError call, with no compile-time check to catch a mismatch.

Additional Locations (1)

Fix in Cursor Fix in Web

if err != nil {
return nil, err
return nil, analyzers.NewAnalysisError(
"Airbrake", "analyze_permissions", "API", "", err,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a.Type().String() instead of the hardcoded Airbrake to eliminate the risk of inconsistencies and improve maintainability.

token, ok := credInfo["token"]
if !ok {
return nil, errors.New("token not found in credInfo")
return nil, analyzers.NewAnalysisError("AirtablePat", "validate_credentials", "config", "", errors.New("token not found in credInfo"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we define constants (or typed values) for validate_credentials, analyze_permissions, etc., instead of using raw strings? They’re used in several places, and this would help prevent easy typos (speaking for myself here 😄) and make things safer long-term.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants