Skip to content

Commit b066ac4

Browse files
committed
SBOM: various fixes.
- be a bit stricter with SBOM handling with the test default formula flow in CI by making it raise errors if SBOM's aren't generated and validated as expected - fix handling of HEAD installations of formulae so SBOM generation is both correct and doesn't raise errors - make `Formula#bottle_hash` more accepting of edge cases e.g. HEAD-only formulae without a stable spec Fixes #17333
1 parent ea05828 commit b066ac4

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed

.github/workflows/tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ jobs:
405405
runs-on: macos-14
406406
env:
407407
HOMEBREW_TEST_BOT_ANALYTICS: 1
408+
HOMEBREW_ENFORCE_SBOM: 1
408409
steps:
409410
- name: Set up Homebrew
410411
id: set-up-homebrew

Library/Homebrew/formula.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -2579,9 +2579,13 @@ def to_hash_with_variations(hash_method: :to_hash)
25792579

25802580
# Returns the bottle information for a formula.
25812581
def bottle_hash(compact_for_api: false)
2582-
bottle_spec = T.must(stable).bottle_specification
2583-
25842582
hash = {}
2583+
stable_spec = stable
2584+
return hash unless stable_spec
2585+
return hash unless bottle_defined?
2586+
2587+
bottle_spec = stable_spec.bottle_specification
2588+
25852589
hash["rebuild"] = bottle_spec.rebuild if !compact_for_api || !bottle_spec.rebuild.zero?
25862590
hash["root_url"] = bottle_spec.root_url unless compact_for_api
25872591
hash["files"] = {}

Library/Homebrew/sbom.rb

+27-14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ class SBOM
1717
# Instantiates a {SBOM} for a new installation of a formula.
1818
sig { params(formula: Formula, tab: Tab).returns(T.attached_class) }
1919
def self.create(formula, tab)
20+
active_spec = if formula.stable?
21+
T.must(formula.stable)
22+
else
23+
T.must(formula.head)
24+
end
25+
active_spec_sym = formula.active_spec_sym
26+
2027
attributes = {
2128
name: formula.name,
2229
homebrew_version: HOMEBREW_VERSION,
@@ -32,13 +39,13 @@ def self.create(formula, tab)
3239
path: formula.specified_path.to_s,
3340
tap: formula.tap&.name,
3441
tap_git_head: nil, # Filled in later if possible
35-
spec: formula.active_spec_sym.to_s,
36-
patches: formula.stable&.patches,
42+
spec: active_spec_sym.to_s,
43+
patches: active_spec.patches,
3744
bottle: formula.bottle_hash,
38-
stable: {
39-
version: formula.stable&.version,
40-
url: formula.stable&.url,
41-
checksum: formula.stable&.checksum,
45+
active_spec_sym => {
46+
version: active_spec.version,
47+
url: active_spec.url,
48+
checksum: active_spec.checksum,
4249
},
4350
},
4451
}
@@ -230,7 +237,8 @@ def generate_relations_json(runtime_dependency_declaration, compiler_declaration
230237
}
231238
def generate_packages_json(runtime_dependency_declaration, compiler_declaration, bottling:)
232239
bottle = []
233-
if !bottling && (bottle_info = get_bottle_info(source[:bottle]))
240+
if !bottling && (bottle_info = get_bottle_info(source[:bottle])) &&
241+
(stable_version = source.dig(:stable, :version))
234242
bottle << {
235243
SPDXID: "SPDXRef-Bottle-#{name}",
236244
name: name.to_s,
@@ -267,18 +275,18 @@ def generate_packages_json(runtime_dependency_declaration, compiler_declaration,
267275
{
268276
SPDXID: "SPDXRef-Archive-#{name}-src",
269277
name: name.to_s,
270-
versionInfo: stable_version.to_s,
278+
versionInfo: spec_version.to_s,
271279
filesAnalyzed: false,
272280
licenseDeclared: assert_value(nil),
273281
builtDate: source_modified_time.to_s,
274282
licenseConcluded: assert_value(license),
275-
downloadLocation: source[:stable][:url],
283+
downloadLocation: source[spec_symbol][:url],
276284
copyrightText: assert_value(nil),
277285
externalRefs: [],
278286
checksums: [
279287
{
280288
algorithm: "SHA256",
281-
checksumValue: source[:stable][:checksum].to_s,
289+
checksumValue: source[spec_symbol][:checksum].to_s,
282290
},
283291
],
284292
},
@@ -362,13 +370,13 @@ def to_spdx_sbom(bottling:)
362370
{
363371
SPDXID: "SPDXRef-DOCUMENT",
364372
spdxVersion: "SPDX-2.3",
365-
name: "SBOM-SPDX-#{name}-#{stable_version}",
373+
name: "SBOM-SPDX-#{name}-#{spec_version}",
366374
creationInfo: {
367375
created: (Time.at(time).utc if time.present? && !bottling),
368376
creators: ["Tool: https://github.com/homebrew/brew@#{homebrew_version}"],
369377
},
370378
dataLicense: "CC0-1.0",
371-
documentNamespace: "https://formulae.brew.sh/spdx/#{name}-#{stable_version}.json",
379+
documentNamespace: "https://formulae.brew.sh/spdx/#{name}-#{spec_version}.json",
372380
documentDescribes: packages.map { |dependency| dependency[:SPDXID] },
373381
files: [],
374382
packages:,
@@ -397,9 +405,14 @@ def tap
397405
Tap.fetch(tap_name) if tap_name
398406
end
399407

408+
sig { returns(Symbol) }
409+
def spec_symbol
410+
source.fetch(:spec).to_sym
411+
end
412+
400413
sig { returns(T.nilable(Version)) }
401-
def stable_version
402-
source[:stable][:version]
414+
def spec_version
415+
source.fetch(spec_symbol)[:version]
403416
end
404417

405418
sig { returns(Time) }

0 commit comments

Comments
 (0)