Module: StillActive::CyclonedxHelper

Extended by:
CyclonedxHelper
Included in:
CyclonedxHelper
Defined in:
lib/helpers/cyclonedx_helper.rb

Overview

Renders a still_active workflow result as a CycloneDX SBOM. Emits 1.6 by default (the version mainstream consumers — Dependency-Track via cyclonedx-core-java, Trivy/Syft via cyclonedx-go — actually ingest as of 2026); 1.7 is opt-in. Our emitted subset is identical across both versions, so only the specVersion string changes.

Maintenance signals that have no native CycloneDX field (scorecard, libyear, archived, last commit) are emitted as ‘still_active:`-namespaced component properties — lossy by spec design, ignorable by consumers that don’t care.

Constant Summary collapse

SUPPORTED_SPEC_VERSIONS =
["1.6", "1.7"].freeze

Instance Method Summary collapse

Instance Method Details

#render(result:, ruby_info:, tool_version:, spec_version: "1.6", now: Time.now.utc) ⇒ Object

result: gem_name => gem_data (as StillActive::Workflow.call returns) ruby_info: Ruby freshness hash or nil now: injectable clock so output is deterministic in tests



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/helpers/cyclonedx_helper.rb', line 26

def render(result:, ruby_info:, tool_version:, spec_version: "1.6", now: Time.now.utc)
  components = build_components(result, ruby_info)
  vulnerabilities = build_vulnerabilities(result)

  document = {
    "bomFormat" => "CycloneDX",
    "specVersion" => spec_version,
    "serialNumber" => deterministic_serial(components),
    "version" => 1,
    "metadata" => {
      "timestamp" => now.iso8601,
      "tools" => [{ "vendor" => "SeanLF", "name" => "still_active", "version" => tool_version }],
    },
    "components" => components,
  }
  document["vulnerabilities"] = vulnerabilities unless vulnerabilities.empty?
  JSON.pretty_generate(document)
end