You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用jq按模式提取子串并重构CycloneDX格式依赖数据?

适配Debian与Alpine的CycloneDX组件purl重构及字段更新jq命令

需要处理Syft工具生成的Debian(bullseye-slim)和Alpine Docker镜像的CycloneDX格式JSON数据,实现以下转换逻辑:

  • 从组件purl的upstream参数提取源名称(srcName)和源版本(srcVersion):
    • 若upstream值包含@,拆分@前后内容分别作为srcName、srcVersion(需解码URL编码的%40为@)
    • 若upstream值不含@,则srcName为upstream值,srcVersion沿用组件原version字段
  • 提取到有效srcName时:
    • Debian组件更新name为srcName、version为srcVersion;Alpine组件保留原name和version
    • 重构purl:保留pkg:开头的包管理器前缀(如pkg:deb/debian/、pkg:apk/alpine/),替换为srcName@srcVersion?arch=source
  • 未提取到upstream参数的组件,保持原数据不变

原始输入JSON

{
    "bomFormat": "CycloneDX",
    "components": [{
            "name": "bsdutils",
            "version": "1:2.36.1-8+deb11u1",
            "purl": "pkg:deb/debian/bsdutils@1:2.36.1-8+deb11u1?arch=amd64&upstream=util-linux%402.36.1-8+deb11u1&distro=debian-11",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "util-linux"
                }, {
                    "name": "syft:metadata:sourceVersion",
                    "value": "2.36.1-8+deb11u1"
                }
            ]
        }, {
            "name": "curl",
            "version": "7.74.0-1.3+deb11u7",
            "purl": "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11"
        }, {
            "name": "libaudit-common",
            "version": "1:3.0-2",
            "purl": "pkg:deb/debian/libaudit-common@1:3.0-2?arch=all&upstream=audit&distro=debian-11",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "audit"
                }
            ]
        }, {
            "name": "busybox-binsh",
            "version": "1.35.0-r29",
            "purl": "pkg:apk/alpine/busybox-binsh@1.35.0-r29?arch=x86_64&upstream=busybox&distro=alpine-3.17.2",
            "properties": [{
                    "name": "syft:metadata:originPackage",
                    "value": "busybox"
                }
            ]
        }
    ]
}

目标输出JSON

{
    "bomFormat": "CycloneDX",
    "components": [{
            "name": "util-linux",
            "version": "2.36.1-8+deb11u1",
            "purl": "pkg:deb/debian/util-linux@2.36.1-8+deb11u1?arch=source",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "util-linux"
                }, {
                    "name": "syft:metadata:sourceVersion",
                    "value": "2.36.1-8+deb11u1"
                }
            ]
        }, {
            "name": "curl",
            "version": "7.74.0-1.3+deb11u7",
            "purl": "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11"
        }, {
            "name": "audit",
            "version": "1:3.0-2",
            "purl": "pkg:deb/debian/audit@1:3.0-2?arch=source",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "audit"
                }
            ]
        }, {
            "name": "busybox-binsh",
            "version": "1.35.0-r29",
            "purl": "pkg:apk/alpine/busybox@1.35.0-r29?arch=source",
            "properties": [{
                    "name": "syft:metadata:originPackage",
                    "value": "busybox"
                }
            ]
        }
    ]
}

通用jq命令

.components[] |= (
    # 提取并解码purl中的upstream参数
    (.purl | capture("\\?.*upstream=(?<upstream>[^&]+)") | .upstream | @uri) as $upstream
    # 拆分upstream为源名称和版本
    | ($upstream | split("@") as $parts | {
        srcName: $parts[0],
        srcVersion: if $parts | length > 1 then $parts[1] else .version end
    }) as $srcInfo
    # 提取purl的包管理器前缀(如pkg:deb/debian/)
    | (.purl | capture("(?<prefix>pkg:[^/]+/[^/]+/)")) as $prefix
    # 生成新的purl
    | let newPurl = "\($prefix.prefix)\($srcInfo.srcName)@\($srcInfo.srcVersion)?arch=source"
    # 按组件类型更新字段
    | if .purl | startswith("pkg:deb/") then
        .name = $srcInfo.srcName
        | .version = $srcInfo.srcVersion
        | .purl = newPurl
    elif .purl | startswith("pkg:apk/") then
        .purl = newPurl
    else
        .
    end
    // . # 无upstream参数时返回原组件
)

命令逻辑说明

  1. 解析upstream参数:通过正则捕获purl中upstream=后的内容,用@uri解码URL编码字符
  2. 拆分源信息:将upstream按@拆分,自动处理带版本和不带版本的两种情况
  3. 提取前缀:保留purl的包管理器标识部分,确保重构后的purl格式合规
  4. 差异化更新:针对Debian和Alpine组件设置不同的字段更新规则,无upstream参数的组件保持原样

内容的提问来源于stack exchange,提问作者EricBDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 01:12:56