blob: 6f91ea36fed97366220213d5c8d471eb7cd13982 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Parse purl arguments for a specific purl entry.
# arguments_var_name is the variable name that contains the args.
# prefix is the prefix passed to cmake_parse_arguments.
macro(_qt_internal_sbom_parse_purl_entry_options prefix arguments_var_name)
_qt_internal_get_sbom_purl_parsing_options(purl_opt_args purl_single_args purl_multi_args)
cmake_parse_arguments(${prefix} "${purl_opt_args}" "${purl_single_args}" "${purl_multi_args}"
${${arguments_var_name}})
_qt_internal_validate_all_args_are_parsed(${prefix})
endmacro()
# Helper macro to prepare forwarding all set purl options to some other function.
# Expects the options names to be set in the parent scope by calling
# _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args)
macro(_qt_internal_sbom_forward_purl_handling_options args_var_name)
if(NOT opt_args)
message(FATAL_ERROR
"Expected opt_args to be set by _qt_internal_get_sbom_purl_handling_options")
endif()
if(NOT single_args)
message(FATAL_ERROR
"Expected single_args to be set by _qt_internal_get_sbom_purl_handling_options")
endif()
if(NOT multi_args)
message(FATAL_ERROR
"Expected multi_args to be set by _qt_internal_get_sbom_purl_handling_options")
endif()
_qt_internal_forward_function_args(
FORWARD_PREFIX arg
FORWARD_OUT_VAR ${args_var_name}
FORWARD_OPTIONS
${opt_args}
FORWARD_SINGLE
${single_args}
FORWARD_MULTI
${multi_args}
)
endmacro()
# Handles purl arguments specified to functions like qt_internal_add_sbom.
#
# Synopsis
#
# qt_internal_add_sbom(<target>
# PURLS
# [[PURL_ENTRY
# PURL_ID <id>
# PURL_TYPE <type>
# PURL_NAMESPACE <namespace>
# PURL_NAME <name>
# PURL_VERSION <version>]...]
# PURL_VALUES
# [purl-string...]
# )
#
# Example
#
# qt_internal_add_sbom(<target>
# PURLS
# PURL_ENTRY
# PURL_ID "UPSTREAM"
# PURL_TYPE "github"
# PURL_NAMESPACE "harfbuzz"
# PURL_NAME "harfbuzz"
# PURL_VERSION "v8.5.0"
# PURL_ENTRY
# PURL_ID "MIRROR"
# PURL_TYPE "git"
# PURL_NAMESPACE "harfbuzz"
# PURL_NAME "harfbuzz"
# PURL_QUALIFIERS "vcs_url=https://code.qt.io/qt/qtbase"
# ....
# PURL_VALUES
# pkg:git/harfbuzz/harfbuzz@v8.5.0
# pkg:github/harfbuzz/harfbuzz@v8.5.0
# ....
#
#
# PURLS accepts multiple purl entries, each starting with the PURL_ENTRY keyword.
# PURL_VALUES takes a list of pre-built purl strings.
#
# If no arguments are specified, for qt entity types (e.g. libraries built as part of Qt repos),
# default purls will be generated.
#
# There is no limit to the number of purls that can be added to a target.
function(_qt_internal_sbom_handle_purl_values target)
_qt_internal_get_sbom_purl_handling_options(opt_args single_args multi_args)
list(APPEND single_args OUT_VAR)
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
_qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_OUT_VAR)
message(FATAL_ERROR "OUT_VAR must be set")
endif()
_qt_internal_get_sbom_purl_parsing_options(purl_opt_args purl_single_args purl_multi_args)
set(project_package_options "")
# Collect each PURL_ENTRY args into a separate variable.
set(purl_idx -1)
set(purl_entry_indices "")
foreach(purl_arg IN LISTS arg_PURLS)
if(purl_arg STREQUAL "PURL_ENTRY")
math(EXPR purl_idx "${purl_idx}+1")
list(APPEND purl_entry_indices "${purl_idx}")
elseif(purl_idx GREATER_EQUAL 0)
list(APPEND purl_${purl_idx}_args "${purl_arg}")
else()
message(FATAL_ERROR "Missing PURL_ENTRY keyword.")
endif()
endforeach()
# Validate the args for each collected entry.
foreach(purl_idx IN LISTS purl_entry_indices)
list(LENGTH purl_${purl_idx}_args num_args)
if(num_args LESS 1)
message(FATAL_ERROR "Empty PURL_ENTRY encountered.")
endif()
_qt_internal_sbom_parse_purl_entry_options(arg purl_${purl_idx}_args)
endforeach()
# Append qt specific placeholder entries when handling Qt entities.
if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL)
_qt_internal_sbom_forward_purl_handling_options(purl_handling_args)
_qt_internal_sbom_handle_qt_entity_purl_entries(${purl_handling_args}
OUT_VAR_IDS qt_purl_ids
)
if(qt_purl_ids)
# Create purl placeholder indices for each qt purl id.
foreach(qt_purl_id IN LISTS qt_purl_ids)
math(EXPR purl_idx "${purl_idx}+1")
list(APPEND purl_entry_indices "${purl_idx}")
list(APPEND purl_${purl_idx}_args PURL_ID "${qt_purl_id}")
endforeach()
endif()
endif()
foreach(purl_idx IN LISTS purl_entry_indices)
# Clear previous values.
foreach(option_name IN LISTS purl_opt_args purl_single_args purl_multi_args)
unset(arg_${option_name})
endforeach()
_qt_internal_sbom_parse_purl_entry_options(arg purl_${purl_idx}_args)
set(purl_args "")
# Override the purl version with the package version.
if(arg_PURL_USE_PACKAGE_VERSION AND arg_PACKAGE_VERSION)
set(arg_PURL_VERSION "${arg_PACKAGE_VERSION}")
endif()
# Append a vcs_url to the qualifiers if specified.
if(arg_PURL_VCS_URL)
list(APPEND arg_PURL_QUALIFIERS "vcs_url=${arg_PURL_VCS_URL}")
endif()
_qt_internal_forward_function_args(
FORWARD_APPEND
FORWARD_PREFIX arg
FORWARD_OUT_VAR purl_args
FORWARD_OPTIONS
${purl_opt_args}
FORWARD_SINGLE
${purl_single_args}
FORWARD_MULTI
${purl_multi_args}
)
# Qt entity types get special treatment to gather the required args.
if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL
AND arg_PURL_ID
AND arg_PURL_ID IN_LIST qt_purl_ids)
_qt_internal_sbom_handle_qt_entity_purl("${target}"
${purl_handling_args}
PURL_ID "${arg_PURL_ID}"
OUT_PURL_ARGS qt_purl_args
)
if(qt_purl_args)
list(APPEND purl_args "${qt_purl_args}")
endif()
endif()
_qt_internal_sbom_assemble_purl(${target}
${purl_args}
OUT_VAR package_manager_external_ref
)
list(APPEND project_package_options ${package_manager_external_ref})
endforeach()
foreach(purl_value IN LISTS arg_PURL_VALUES)
_qt_internal_sbom_get_purl_value_extref(
VALUE "${purl_value}" OUT_VAR package_manager_external_ref)
# The order in which the purls are generated, matters for tools that consume the SBOM.
# Some tools can only handle one PURL per package, so the first one should be the
# important one.
# For now, I deem that the directly specified ones (probably via a qt_attribution.json
# file) are the more important ones. So we prepend them.
list(PREPEND project_package_options ${package_manager_external_ref})
endforeach()
set(${arg_OUT_VAR} "${project_package_options}" PARENT_SCOPE)
endfunction()
# Assembles an external reference purl identifier.
# PURL_TYPE and PURL_NAME are required.
# Stores the result in the OUT_VAR.
# Accepted options:
# PURL_TYPE
# PURL_NAME
# PURL_NAMESPACE
# PURL_VERSION
# PURL_SUBPATH
# PURL_QUALIFIERS
function(_qt_internal_sbom_assemble_purl target)
set(opt_args "")
set(single_args
OUT_VAR
)
set(multi_args "")
_qt_internal_get_sbom_purl_parsing_options(purl_opt_args purl_single_args purl_multi_args)
list(APPEND opt_args ${purl_opt_args})
list(APPEND single_args ${purl_single_args})
list(APPEND multi_args ${purl_multi_args})
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
_qt_internal_validate_all_args_are_parsed(arg)
set(purl_scheme "pkg")
if(NOT arg_PURL_TYPE)
message(FATAL_ERROR "PURL_TYPE must be set")
endif()
if(NOT arg_PURL_NAME)
message(FATAL_ERROR "PURL_NAME must be set")
endif()
if(NOT arg_OUT_VAR)
message(FATAL_ERROR "OUT_VAR must be set")
endif()
# https://github.com/package-url/purl-spec
# Spec is 'scheme:type/namespace/name@version?qualifiers#subpath'
set(purl "${purl_scheme}:${arg_PURL_TYPE}")
if(arg_PURL_NAMESPACE)
string(APPEND purl "/${arg_PURL_NAMESPACE}")
endif()
string(APPEND purl "/${arg_PURL_NAME}")
if(arg_PURL_VERSION)
string(APPEND purl "@${arg_PURL_VERSION}")
endif()
if(arg_PURL_QUALIFIERS)
# TODO: Note that the qualifiers are expected to be URL encoded, which this implementation
# is not doing at the moment.
list(JOIN arg_PURL_QUALIFIERS "&" qualifiers)
string(APPEND purl "?${qualifiers}")
endif()
if(arg_PURL_SUBPATH)
string(APPEND purl "#${arg_PURL_SUBPATH}")
endif()
_qt_internal_sbom_get_purl_value_extref(VALUE "${purl}" OUT_VAR result)
set(${arg_OUT_VAR} "${result}" PARENT_SCOPE)
endfunction()
# Takes a PURL VALUE and returns an SBOM purl external reference in OUT_VAR.
function(_qt_internal_sbom_get_purl_value_extref)
set(opt_args "")
set(single_args
OUT_VAR
VALUE
)
set(multi_args "")
cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}")
_qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_OUT_VAR)
message(FATAL_ERROR "OUT_VAR must be set")
endif()
if(NOT arg_VALUE)
message(FATAL_ERROR "VALUE must be set")
endif()
# SPDX SBOM External reference type.
set(ext_ref_prefix "PACKAGE-MANAGER purl")
set(external_ref "${ext_ref_prefix} ${arg_VALUE}")
set(result "EXTREF" "${external_ref}")
set(${arg_OUT_VAR} "${result}" PARENT_SCOPE)
endfunction()
|