🔒 Security Audit
Perform security audits on project dependencies to detect known vulnerabilities (CVEs) and abandoned packages.
Composer Skills wraps composer audit and related capabilities into a set of methods covering the complete chain from "get raw output" to "structured parsing" to "filter high-risk vulnerabilities by severity". All structured methods are based on composer audit --format=json and automatically handle the non-zero exit code returned when vulnerabilities are found.
When to Use
- 📦 Run an audit after
composer installin CI/CD pipeline; block the build if vulnerabilities are found. - 🛠️ Operations patrol: periodically scan
composer.lockto confirm no new CVEs have been disclosed for production dependencies. - 🧩 Dependency governance: find abandoned packages and plan replacements in advance.
- ⚡ Incident response: quickly determine if the current project is affected when a CVE breaks out, including affected package versions and severity.
🔍 Audit Data Flow
Structured Return Types
AuditResult
Returned by AuditWithJSON, corresponds to the top-level structure of composer audit --format=json.
type AuditResult struct {
Vulnerabilities []Vulnerability `json:"vulnerabilities"`
Found int `json:"found"`
Advisory string `json:"advisory,omitempty"`
WithoutDev bool `json:"without-dev,omitempty"`
}| Field | Type | Description |
|---|---|---|
Vulnerabilities | []Vulnerability | List of vulnerabilities found |
Found | int | Total number of vulnerabilities |
Advisory | string | Advisory identifier (may be empty) |
WithoutDev | bool | Whether dev dependencies were excluded |
Vulnerability
Individual vulnerability entry. When Abandoned=true, this entry represents an "abandoned package" rather than a traditional CVE.
type Vulnerability struct {
Package string `json:"package"`
Version string `json:"version"`
Title string `json:"title"`
Link string `json:"link"`
CVE []string `json:"cve,omitempty"`
Advisory string `json:"advisory"`
Abandoned bool `json:"abandoned,omitempty"`
Severity string `json:"severity,omitempty"`
Source string `json:"source,omitempty"`
Affectedver string `json:"affectedver,omitempty"`
}| Field | Type | Description |
|---|---|---|
Package | string | Affected package name |
Version | string | Currently installed version |
Title | string | Vulnerability title |
Link | string | Details link |
CVE | []string | List of associated CVE identifiers |
Advisory | string | Advisory identifier |
Abandoned | bool | Whether this is an abandoned package |
Severity | string | Severity: critical/high/medium/low |
Source | string | Data source |
Affectedver | string | Affected version range |
AuditInfoResult
Returned by GetAuditInfo / GetAuditInfoWithOptions, provides more granular advisory information.
type AuditAdvisoryInfo struct {
PackageName string `json:"package"`
Version string `json:"version"`
Title string `json:"title"`
Severity string `json:"severity"` // "critical", "high", "medium", "low"
CVE string `json:"cve,omitempty"`
Link string `json:"link,omitempty"`
ReportedAt string `json:"reportedAt,omitempty"`
}
type AuditInfoResult struct {
Advisories []AuditAdvisoryInfo `json:"advisories"`
Count int `json:"count,omitempty"`
}Difference Between Two Structured Results
AuditResult (from AuditWithJSON) directly maps Composer's raw JSON, including abandoned markers; AuditInfoResult (from GetAuditInfo) is an SDK-layer normalization with more consistent field names (e.g., PackageName), and automatically fills Count during parsing. Use the former when you need to determine "whether abandoned packages are included"; use the latter when you need to iterate through advisories for alert distribution.
Audit
🔒 Execute security audit, return raw text output.
Signature
func (c *Composer) Audit() (string, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Standard output from composer audit |
| Error | error | Returned on execution failure; also returned as error when Composer returns non-zero exit code due to found vulnerabilities |
Example
package main
import (
"fmt"
"log"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func main() {
comp, err := composer.New(composer.DefaultOptions())
if err != nil {
log.Fatalf("Initialization failed: %v", err)
}
output, err := comp.Audit()
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Println("Security audit result:", output)
}AuditWithJSON
🔒 Execute security audit and return structured JSON result.
Signature
func (c *Composer) AuditWithJSON() (*AuditResult, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Result | *AuditResult | Parsed audit result, including vulnerability list and count |
| Error | error | Returned on execution or JSON parsing failure |
Example
result, err := comp.AuditWithJSON()
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Printf("Found %d vulnerabilities\n", result.Found)
for _, vuln := range result.Vulnerabilities {
fmt.Printf("Vulnerability: %s %s\n", vuln.Package, vuln.Title)
fmt.Printf("Severity: %s\n", vuln.Severity)
fmt.Printf("Details: %s\n\n", vuln.Link)
}AuditWithoutDev
🔒 Audit only production dependencies, excluding dev dependencies (require-dev).
Signature
func (c *Composer) AuditWithoutDev() (string, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Output from composer audit --no-dev |
| Error | error | Returned on execution failure |
Example
output, err := comp.AuditWithoutDev()
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Println("Production dependency security audit result:", output)Equivalent Command
composer audit --no-dev. Production environments typically don't deploy dev dependencies, so auditing production dependencies reflects the actual risk surface.
AuditWithFormat
🔒 Output audit result in specified format.
Signature
func (c *Composer) AuditWithFormat(format string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
format | string | Output format, e.g., json, table, plain |
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Output from composer audit --format=FORMAT |
| Error | error | Returned on execution failure |
Example
// Output in table format
output, err := comp.AuditWithFormat("table")
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Println(output)
// Output in plain text format
output, err = comp.AuditWithFormat("plain")
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Println(output)HasVulnerabilities
🔒 Quickly determine if the project has any security vulnerabilities.
Signature
func (c *Composer) HasVulnerabilities() (bool, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Has vulnerabilities | bool | true means vulnerabilities exist |
| Error | error | Returned when unexpected error occurs during check |
Implementation Note
Internally calls AuditWithJSON and determines based on result.Found > 0. When Composer returns non-zero exit code due to found vulnerabilities, it checks if the error message contains Found and vulnerabilities keywords; if so, it's also considered "has vulnerabilities" without propagating the error.
Example
hasVulns, err := comp.HasVulnerabilities()
if err != nil {
log.Fatalf("Failed to check vulnerabilities: %v", err)
}
if hasVulns {
fmt.Println("Warning: Security vulnerabilities exist in the project!")
} else {
fmt.Println("No security vulnerabilities found in the project.")
}GetHighSeverityVulnerabilities
🔒 Filter out high-severity vulnerabilities (high or critical) for prioritized fixing.
Signature
func (c *Composer) GetHighSeverityVulnerabilities() ([]Vulnerability, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| High-severity vulnerabilities | []Vulnerability | List of vulnerabilities with Severity as high or critical; empty slice if none |
| Error | error | Returned on audit or parsing failure |
Example
highVulns, err := comp.GetHighSeverityVulnerabilities()
if err != nil {
log.Fatalf("Failed to get high-severity vulnerabilities: %v", err)
}
if len(highVulns) > 0 {
fmt.Printf("Found %d high-severity vulnerabilities:\n", len(highVulns))
for _, vuln := range highVulns {
fmt.Printf("Package: %s Version: %s\n", vuln.Package, vuln.Version)
fmt.Printf("Vulnerability: %s\n", vuln.Title)
fmt.Printf("Details: %s\n\n", vuln.Link)
}
} else {
fmt.Println("No high-severity vulnerabilities found.")
}AuditLock
🔒 Audit a specified composer.lock file, usable for projects that haven't installed dependencies yet.
Signature
func (c *Composer) AuditLock(lockFilePath string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
lockFilePath | string | Path to composer.lock file; pass empty string to audit the lock file in current directory |
Return Values
| Value | Type | Description |
|---|---|---|
| Output | string | Audit output |
| Error | error | Returned on execution failure |
Example
// Audit the lock file in current project
output, err := comp.AuditLock("")
if err != nil {
log.Fatalf("Audit lock file failed: %v", err)
}
fmt.Println(output)
// Audit another project's lock file
output, err = comp.AuditLock("/path/to/other/project/composer.lock")
if err != nil {
log.Fatalf("Audit lock file failed: %v", err)
}
fmt.Println(output)Path Parameter
When lockFilePath is non-empty, the path is passed directly to composer audit <path> as a positional argument. Ensure the path is correct and the file exists.
GetAbandonedPackages
🔒 Get list of packages marked as "abandoned".
Signature
func (c *Composer) GetAbandonedPackages() ([]Vulnerability, error)Parameters
None.
Return Values
| Value | Type | Description |
|---|---|---|
| Abandoned packages | []Vulnerability | List of entries with Abandoned=true; empty slice if none |
| Error | error | Returned on audit or parsing failure |
Example
abandoned, err := comp.GetAbandonedPackages()
if err != nil {
log.Fatalf("Failed to get abandoned packages: %v", err)
}
if len(abandoned) > 0 {
fmt.Printf("Found %d abandoned packages:\n", len(abandoned))
for _, pkg := range abandoned {
fmt.Printf("Package: %s Version: %s\n", pkg.Package, pkg.Version)
fmt.Printf("Details: %s\n\n", pkg.Link)
}
fmt.Println("Consider replacing these packages to avoid potential security risks.")
} else {
fmt.Println("No abandoned packages found.")
}Reusing Vulnerability Type
Abandoned packages are not traditional vulnerabilities, but the SDK reuses the Vulnerability struct, distinguishing them via the Abandoned field. Check this field first when iterating if you need to handle them separately.
Advanced
AuditWithOptions
Use when you need to combine multiple audit flags for maximum flexibility.
func (c *Composer) AuditWithOptions(options map[string]string) (string, error)| Parameter | Type | Description |
|---|---|---|
options | map[string]string | Options map; keys are option names, values are option values (pass empty string for flag options without values) |
options := map[string]string{
"no-dev": "",
"format": "json",
"locked": "",
}
output, err := comp.AuditWithOptions(options)
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
fmt.Println(output)GetAuditInfo / GetAuditInfoWithOptions
Returns normalized AuditInfoResult, suitable for scenarios where you need to distribute alerts per advisory (e.g., pushing to monitoring systems).
func (c *Composer) GetAuditInfo() (*AuditInfoResult, error)
func (c *Composer) GetAuditInfoWithOptions(options map[string]string) (*AuditInfoResult, error)result, err := comp.GetAuditInfo()
if err != nil {
log.Fatalf("Security audit failed: %v", err)
}
for _, adv := range result.Advisories {
fmt.Printf("Vulnerability: %s (%s) - %s\n", adv.PackageName, adv.Severity, adv.Title)
}RunAudit
dependencies.go also provides RunAudit(), equivalent to Audit(), which can be called in pairs in dependency management workflows.
🔍 Related Methods
- Validate - CheckForSecurityVulnerabilities: Returns
(output, hasVuln, err)tuple, suitable for scripts that "just want to know if there are vulnerabilities". - Diagnosis and Health Check - HealthCheck: Comprehensive health check that calls audit and writes vulnerability count to
VulnerabilityCount.