* Add AnalysisError type and AnalysisErrorInfo interface 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. * Wrap errors in simple API analyzers with AnalysisError 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". * Wrap errors in remaining analyzers with AnalysisError (Batches B-E) 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) * Use Type().String() and constants for NewAnalysisError calls Address PR feedback: replace hardcoded analyzer type strings with a.Type().String() and replace raw operation/service strings with package-level constants (OperationValidateCredentials, OperationAnalyzePermissions, ServiceAPI, ServiceConfig, etc.). * Omit empty resource parenthetical from AnalysisError messages Conditionally include "(resource: ...)" only when non-empty, avoiding cluttered messages like "... (resource: ): ..." that appear for the majority of analyzers that don't set a resource. * Wrap no-data error path in GitHub analyzer with AnalysisError
70 lines
2.1 KiB
Go
70 lines
2.1 KiB
Go
package analyzers
|
|
|
|
import "fmt"
|
|
|
|
// Operation constants for AnalysisError.
|
|
const (
|
|
OperationValidateCredentials = "validate_credentials"
|
|
OperationAnalyzePermissions = "analyze_permissions"
|
|
)
|
|
|
|
// Service constants for AnalysisError.
|
|
const (
|
|
ServiceAPI = "API"
|
|
ServiceConfig = "config"
|
|
ServiceDatabase = "Database"
|
|
ServiceOAuth = "OAuth"
|
|
ServiceCrypto = "crypto"
|
|
)
|
|
|
|
// AnalysisErrorInfo is implemented by errors that provide structured context
|
|
// about analysis failures. This allows downstream consumers (e.g., the scanner)
|
|
// to extract metadata for structured error storage without depending on
|
|
// concrete error types.
|
|
type AnalysisErrorInfo interface {
|
|
error
|
|
AnalyzerType() string
|
|
Operation() string // "validate_credentials", "authenticate", "analyze_permissions", "connect", "ping"
|
|
Service() string // "config", "API", "OAuth", "Database"
|
|
Resource() string // account ID, endpoint URL, or other identifier
|
|
}
|
|
|
|
// AnalysisError represents a structured error from an analyzer.
|
|
type AnalysisError struct {
|
|
analyzerType string
|
|
operation string
|
|
service string
|
|
resource string
|
|
err error
|
|
}
|
|
|
|
// NewAnalysisError creates a new AnalysisError.
|
|
func NewAnalysisError(analyzerType, operation, service, resource string, err error) *AnalysisError {
|
|
return &AnalysisError{
|
|
analyzerType: analyzerType,
|
|
operation: operation,
|
|
service: service,
|
|
resource: resource,
|
|
err: err,
|
|
}
|
|
}
|
|
|
|
func (e *AnalysisError) Error() string {
|
|
var resource string
|
|
if e.resource != "" {
|
|
resource = fmt.Sprintf(" (resource: %s)", e.resource)
|
|
}
|
|
if e.err != nil {
|
|
return fmt.Sprintf("%s analysis failed: %s on %s%s: %v",
|
|
e.analyzerType, e.operation, e.service, resource, e.err)
|
|
}
|
|
return fmt.Sprintf("%s analysis failed: %s on %s%s",
|
|
e.analyzerType, e.operation, e.service, resource)
|
|
}
|
|
|
|
func (e *AnalysisError) Unwrap() error { return e.err }
|
|
func (e *AnalysisError) AnalyzerType() string { return e.analyzerType }
|
|
func (e *AnalysisError) Operation() string { return e.operation }
|
|
func (e *AnalysisError) Service() string { return e.service }
|
|
func (e *AnalysisError) Resource() string { return e.resource }
|