🔒 安全审计
对项目依赖执行安全审计,检测已知漏洞(CVE)与已放弃维护(abandoned)的包。
Composer Skills 把 composer audit 及其周边能力封装为一组方法,覆盖从「拿一份原始输出」到「结构化解析」再到「按严重性筛选高危漏洞」的完整链路。所有结构化方法都基于 composer audit --format=json,并自动处理审计发现漏洞时返回的非零退出码。
何时使用
- 📦 CI/CD 流水线里在
composer install之后跑一次审计,发现漏洞即阻断构建。 - 🛠️ 运维巡检:定期扫描
composer.lock,确认生产依赖没有被披露新的 CVE。 - 🧩 依赖治理:找出已放弃维护(abandoned)的包,提前规划替换。
- ⚡ 应急响应:某 CVE 爆发后,快速判断当前项目是否受影响、受影响包的版本与严重性。
🔍 审计数据流
结构化返回类型
AuditResult
AuditWithJSON 返回,对应 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"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Vulnerabilities | []Vulnerability | 发现的漏洞列表 |
Found | int | 漏洞总数 |
Advisory | string | 公告标识(可空) |
WithoutDev | bool | 是否排除了开发依赖 |
Vulnerability
单个漏洞条目,Abandoned=true 时表示该条目是「已放弃维护的包」而非传统 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"`
}| 字段 | 类型 | 说明 |
|---|---|---|
Package | string | 受影响的包名 |
Version | string | 当前安装版本 |
Title | string | 漏洞标题 |
Link | string | 详情链接 |
CVE | []string | 关联的 CVE 编号列表 |
Advisory | string | 公告标识 |
Abandoned | bool | 是否为已放弃维护的包 |
Severity | string | 严重性:critical/high/medium/low |
Source | string | 数据来源 |
Affectedver | string | 受影响版本范围 |
AuditInfoResult
GetAuditInfo / GetAuditInfoWithOptions 返回,提供更细粒度的公告信息。
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"`
}两种结构化结果的区别
AuditResult(来自 AuditWithJSON)直接映射 Composer 的原始 JSON,含 abandoned 标记;AuditInfoResult(来自 GetAuditInfo)是 SDK 层做的归一化封装,字段名更规整(如 PackageName),并在解析时自动填充 Count。需要判断「是否含已放弃包」用前者,需要遍历公告做告警分发用后者。
Audit
🔒 执行安全审计,返回原始文本输出。
签名
func (c *Composer) Audit() (string, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer audit 的标准输出 |
| 错误 | error | 执行失败时返回;发现漏洞时 Composer 返回非零退出码也会以 error 形式返回 |
示例
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("初始化失败: %v", err)
}
output, err := comp.Audit()
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Println("安全审计结果:", output)
}AuditWithJSON
🔒 执行安全审计并返回结构化 JSON 结果。
签名
func (c *Composer) AuditWithJSON() (*AuditResult, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 结果 | *AuditResult | 解析后的审计结果,含漏洞列表与计数 |
| 错误 | error | 执行或 JSON 解析失败时返回 |
示例
result, err := comp.AuditWithJSON()
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Printf("发现 %d 个漏洞\n", result.Found)
for _, vuln := range result.Vulnerabilities {
fmt.Printf("漏洞: %s %s\n", vuln.Package, vuln.Title)
fmt.Printf("严重性: %s\n", vuln.Severity)
fmt.Printf("详情: %s\n\n", vuln.Link)
}AuditWithoutDev
🔒 仅审计生产依赖,排除开发依赖(require-dev)。
签名
func (c *Composer) AuditWithoutDev() (string, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer audit --no-dev 的输出 |
| 错误 | error | 执行失败时返回 |
示例
output, err := comp.AuditWithoutDev()
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Println("生产环境依赖安全审计结果:", output)等价命令
composer audit --no-dev。生产环境通常不部署开发依赖,审计生产依赖即可反映真实风险面。
AuditWithFormat
🔒 以指定格式输出审计结果。
签名
func (c *Composer) AuditWithFormat(format string) (string, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
format | string | 输出格式,例如 json、table、plain |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | composer audit --format=FORMAT 的输出 |
| 错误 | error | 执行失败时返回 |
示例
// 以表格形式输出
output, err := comp.AuditWithFormat("table")
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Println(output)
// 以纯文本形式输出
output, err = comp.AuditWithFormat("plain")
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Println(output)HasVulnerabilities
🔒 快速判断项目是否存在任何安全漏洞。
签名
func (c *Composer) HasVulnerabilities() (bool, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 是否有漏洞 | bool | true 表示存在漏洞 |
| 错误 | error | 检查过程发生非预期错误时返回 |
实现说明
内部调用 AuditWithJSON,并依据 result.Found > 0 判断。当 Composer 因发现漏洞返回非零退出码时,会检查错误信息是否包含 Found 与 vulnerabilities 关键字,若是则同样认定为「有漏洞」而不向上抛错。
示例
hasVulns, err := comp.HasVulnerabilities()
if err != nil {
log.Fatalf("检查漏洞失败: %v", err)
}
if hasVulns {
fmt.Println("警告: 项目中存在安全漏洞!")
} else {
fmt.Println("项目中未发现安全漏洞。")
}GetHighSeverityVulnerabilities
🔒 筛选出严重性为 high 或 critical 的高危漏洞,便于优先修复。
签名
func (c *Composer) GetHighSeverityVulnerabilities() ([]Vulnerability, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 高危漏洞 | []Vulnerability | Severity 为 high 或 critical 的漏洞列表,无则为空切片 |
| 错误 | error | 审计或解析失败时返回 |
示例
highVulns, err := comp.GetHighSeverityVulnerabilities()
if err != nil {
log.Fatalf("获取高危漏洞失败: %v", err)
}
if len(highVulns) > 0 {
fmt.Printf("发现 %d 个高危漏洞:\n", len(highVulns))
for _, vuln := range highVulns {
fmt.Printf("包: %s 版本: %s\n", vuln.Package, vuln.Version)
fmt.Printf("漏洞: %s\n", vuln.Title)
fmt.Printf("详情: %s\n\n", vuln.Link)
}
} else {
fmt.Println("未发现高危漏洞。")
}AuditLock
🔒 审计指定的 composer.lock 文件,可用于尚未安装依赖的项目。
签名
func (c *Composer) AuditLock(lockFilePath string) (string, error)参数
| 参数 | 类型 | 说明 |
|---|---|---|
lockFilePath | string | composer.lock 文件路径;传空字符串则审计当前目录的 lock 文件 |
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 输出 | string | 审计输出 |
| 错误 | error | 执行失败时返回 |
示例
// 审计当前项目的 lock 文件
output, err := comp.AuditLock("")
if err != nil {
log.Fatalf("审计 lock 文件失败: %v", err)
}
fmt.Println(output)
// 审计其他项目的 lock 文件
output, err = comp.AuditLock("/path/to/other/project/composer.lock")
if err != nil {
log.Fatalf("审计 lock 文件失败: %v", err)
}
fmt.Println(output)路径参数
当 lockFilePath 非空时,路径会作为位置参数直接传给 composer audit <path>,请确保路径正确且文件存在。
GetAbandonedPackages
🔒 获取已被标记为「已放弃维护」(abandoned)的包列表。
签名
func (c *Composer) GetAbandonedPackages() ([]Vulnerability, error)参数
无。
返回值
| 值 | 类型 | 说明 |
|---|---|---|
| 已放弃包 | []Vulnerability | Abandoned=true 的条目列表,无则为空切片 |
| 错误 | error | 审计或解析失败时返回 |
示例
abandoned, err := comp.GetAbandonedPackages()
if err != nil {
log.Fatalf("获取已放弃的包失败: %v", err)
}
if len(abandoned) > 0 {
fmt.Printf("发现 %d 个已放弃维护的包:\n", len(abandoned))
for _, pkg := range abandoned {
fmt.Printf("包: %s 版本: %s\n", pkg.Package, pkg.Version)
fmt.Printf("详情: %s\n\n", pkg.Link)
}
fmt.Println("建议替换这些包以避免潜在的安全风险。")
} else {
fmt.Println("未发现已放弃维护的包。")
}复用 Vulnerability 类型
已放弃的包并非传统漏洞,但 SDK 复用 Vulnerability 结构承载,通过 Abandoned 字段区分。遍历时如需分别处理,先判断该字段。
进阶
AuditWithOptions
需要组合多个审计标志时使用,提供最大灵活性。
func (c *Composer) AuditWithOptions(options map[string]string) (string, error)| 参数 | 类型 | 说明 |
|---|---|---|
options | map[string]string | 选项映射,键为选项名,值为选项值(无值标志传空字符串) |
options := map[string]string{
"no-dev": "",
"format": "json",
"locked": "",
}
output, err := comp.AuditWithOptions(options)
if err != nil {
log.Fatalf("执行安全审计失败: %v", err)
}
fmt.Println(output)GetAuditInfo / GetAuditInfoWithOptions
返回归一化的 AuditInfoResult,适合需要逐条公告做分发的场景(如向监控系统推送告警)。
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("安全审计失败: %v", err)
}
for _, adv := range result.Advisories {
fmt.Printf("漏洞: %s (%s) - %s\n", adv.PackageName, adv.Severity, adv.Title)
}RunAudit
dependencies.go 中还提供了 RunAudit(),等价于 Audit(),可在依赖管理流程中成对调用。
🔍 相关方法
- 验证 - CheckForSecurityVulnerabilities:返回
(output, hasVuln, err)三元组,适合「只想知道有没有漏洞」的脚本。 - 诊断与健康检查 - HealthCheck:综合健康检查,会调用审计并把漏洞数量写入
VulnerabilityCount。