diff options
| author | Pierre Pronchery <khorben@FreeBSD.org> | 2026-06-25 22:30:05 +0000 |
|---|---|---|
| committer | Pierre Pronchery <khorben@FreeBSD.org> | 2026-06-29 05:21:48 +0000 |
| commit | b0fc1b7a2fe8fcb18ee407227591bf25a86ffbaf (patch) | |
| tree | 0cc32f86bf808bcf9d79da95db969cd76f0feadb /cli/spdxtool | |
| parent | eaa637963bcfde283b411c14968b7903b02d6aa1 (diff) | |
Diffstat (limited to 'cli/spdxtool')
| -rw-r--r-- | cli/spdxtool/core.c | 113 | ||||
| -rw-r--r-- | cli/spdxtool/core.h | 6 | ||||
| -rw-r--r-- | cli/spdxtool/main.c | 16 | ||||
| -rw-r--r-- | cli/spdxtool/serialize.c | 15 | ||||
| -rw-r--r-- | cli/spdxtool/serialize.h | 6 | ||||
| -rw-r--r-- | cli/spdxtool/software.c | 100 | ||||
| -rw-r--r-- | cli/spdxtool/util.h | 2 |
7 files changed, 248 insertions, 10 deletions
diff --git a/cli/spdxtool/core.c b/cli/spdxtool/core.c index 5cf7f10e81e1..7dc7a8b41cce 100644 --- a/cli/spdxtool/core.c +++ b/cli/spdxtool/core.c @@ -222,8 +222,15 @@ spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_c if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) && spdxtool_serialize_object_add_string(object_list, "@id", creation->id) && - spdxtool_serialize_object_add_string(object_list, "created", creation->created) && - spdxtool_serialize_object_add_array(object_list, "createdBy", created_by) && + spdxtool_serialize_object_add_string(object_list, "created", creation->created))) + { + /* created_by has not been handed to the object list yet */ + spdxtool_serialize_array_free(created_by); + goto err; + } + + /* object_add_array takes ownership of created_by, freeing it on failure */ + if (!(spdxtool_serialize_object_add_array(object_list, "createdBy", created_by) && spdxtool_serialize_object_add_string(object_list, "specVersion", creation->spec_version))) { goto err; @@ -329,6 +336,13 @@ spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx) free(iter); } + PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->maintainers.head, iter_next, iter) + { + spdxtool_core_agent_t *maintainer = iter->data; + spdxtool_core_agent_free(maintainer); + free(iter); + } + PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->packages.head, iter_next, iter) { free(iter); @@ -547,6 +561,60 @@ spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_ /* * !doc * + * .. c:function:: const char *spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *name) + * + * Register a package maintainer as an Agent and add it to the SpdxDocument so that + * packages may reference it via their ``suppliedBy`` field. Maintainers are + * deduplicated by their spdxId, so a maintainer shared between packages is only + * emitted once. The first time a maintainer is seen, its spdxId is also added to + * the document element list. + * + * :param pkgconf_client_t *client: The pkgconf client being accessed. + * :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used. + * :param const char *name: Maintainer name as declared in the package. + * :return: the maintainer Agent spdxId (owned by the document) on success, NULL on failure + */ +const char * +spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *name) +{ + pkgconf_node_t *iter = NULL; + + if (!client || !spdx || !name) + return NULL; + + spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, spdx->creation_info, name); + if (!agent) + return NULL; + + PKGCONF_FOREACH_LIST_ENTRY(spdx->maintainers.head, iter) + { + spdxtool_core_agent_t *existing = iter->data; + if (!strcmp(existing->spdx_id, agent->spdx_id)) + { + spdxtool_core_agent_free(agent); + return existing->spdx_id; + } + } + + pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t)); + if (!node) + { + pkgconf_error(client, "spdxtool_core_spdx_document_add_maintainer: out of memory"); + spdxtool_core_agent_free(agent); + return NULL; + } + + pkgconf_node_insert_tail(node, agent, &spdx->maintainers); + + if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id)) + return NULL; + + return agent->spdx_id; +} + +/* + * !doc + * * .. c:function:: bool spdxtool_core_spdx_document_add_relationship(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, spdxtool_core_relationship_t *relationship) * * Add relationship rel to SpdxDocument @@ -650,6 +718,40 @@ err: /* * !doc * + * .. c:function:: bool spdxtool_core_relationship_set_scope(pkgconf_client_t *client, spdxtool_core_relationship_t *relationship, const char *scope) + * + * Promote a relationship to a /Core/LifecycleScopedRelationship by attaching a lifecycle + * scope (for example, ``development`` for a private build dependency). This is the SPDX 3.0 + * representation of SPDX 2.x's ``*_DEPENDENCY_OF`` relationship variants. + * + * :param pkgconf_client_t *client: The pkgconf client being accessed. + * :param spdxtool_core_relationship_t *relationship: Relationship struct to scope. + * :param const char *scope: LifecycleScopeType value, e.g. "development". + * :return: true on success, false on failure + */ +bool +spdxtool_core_relationship_set_scope(pkgconf_client_t *client, spdxtool_core_relationship_t *relationship, const char *scope) +{ + if (!relationship || !scope) + return false; + + char *scope_copy = strdup(scope); + if (!scope_copy) + { + pkgconf_error(client, "spdxtool_core_relationship_set_scope: out of memory"); + return false; + } + + free(relationship->scope); + relationship->scope = scope_copy; + relationship->type = "LifecycleScopedRelationship"; + + return true; +} + +/* + * !doc + * * .. c:function:: void spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship) * * Free /Core/Relationship struct @@ -669,6 +771,7 @@ spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship) pkgconf_license_free(relationship->to); free(relationship->to); free(relationship->relationship_type); + free(relationship->scope); free(relationship); } @@ -717,6 +820,12 @@ spdxtool_core_relationship_to_object(pkgconf_client_t *client, const spdxtool_co goto err; } + if (relationship->scope != NULL && + !spdxtool_serialize_object_add_string(object_list, "scope", relationship->scope)) + { + goto err; + } + ret = spdxtool_serialize_value_object(object_list); object_list = NULL; diff --git a/cli/spdxtool/core.h b/cli/spdxtool/core.h index 0cbb1f4b3d51..9575310ebd1f 100644 --- a/cli/spdxtool/core.h +++ b/cli/spdxtool/core.h @@ -55,6 +55,9 @@ spdxtool_core_spdx_document_add_package(pkgconf_client_t *client, spdxtool_core_ bool spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *element); +const char * +spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *name); + void spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx); @@ -64,6 +67,9 @@ spdxtool_core_spdx_document_to_object(pkgconf_client_t *client, spdxtool_core_sp spdxtool_core_relationship_t * spdxtool_core_relationship_new(pkgconf_client_t *client, const char *creation_info_id, const char *spdx_id, const char *from, pkgconf_list_t *to, const char *relationship_type); +bool +spdxtool_core_relationship_set_scope(pkgconf_client_t *client, spdxtool_core_relationship_t *relationship, const char *scope); + void spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship); diff --git a/cli/spdxtool/main.c b/cli/spdxtool/main.c index 70cdce2dd891..7d52abe56670 100644 --- a/cli/spdxtool/main.c +++ b/cli/spdxtool/main.c @@ -30,7 +30,6 @@ static int maximum_traverse_depth = 2000; static pkgconf_client_t pkg_client; static uint64_t want_flags; -static size_t maximum_package_count = 0; // static int maximum_traverse_depth = 2000; static FILE *error_msgout = NULL; static FILE *sbom_out = NULL; @@ -94,6 +93,15 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0); pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0); + if (pkg->maintainer != NULL) + { + const char *supplier = spdxtool_core_spdx_document_add_maintainer(client, document, pkg->maintainer); + if (!supplier) + goto err; + + pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0); + } + if (pkg->license.head != NULL) { pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER; @@ -364,12 +372,6 @@ main(int argc, char *argv[]) if (package == NULL) break; - /* check if there is a limit to the number of packages allowed to be included, if so and we have hit - * the limit, stop adding packages to the queue. - */ - if (maximum_package_count > 0 && pkgq.length > maximum_package_count) - break; - while (isspace((unsigned char)package[0])) package++; diff --git a/cli/spdxtool/serialize.c b/cli/spdxtool/serialize.c index 69ef3a70a3b1..fc5c460d77cb 100644 --- a/cli/spdxtool/serialize.c +++ b/cli/spdxtool/serialize.c @@ -169,7 +169,8 @@ spdxtool_serialize_object_add_take(spdxtool_serialize_object_list_t *object_list { free(node); free(keycopy); - spdxtool_serialize_object_free(object); + /* object->key/value are not assigned yet; free the struct itself */ + free(object); spdxtool_serialize_value_free(value); return NULL; } @@ -397,6 +398,18 @@ spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, goto err; pkgconf_node_t *iter = NULL; + PKGCONF_FOREACH_LIST_ENTRY(spdx->maintainers.head, iter) + { + spdxtool_core_agent_t *maintainer = iter->data; + if (!maintainer) + { + errstr = "maintainers list corrupted"; + goto err; + } + if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_agent_to_object(client, maintainer))) + goto err; + } + PKGCONF_FOREACH_LIST_ENTRY(spdx->licenses.head, iter) { spdxtool_simplelicensing_license_expression_t *expression = iter->data; diff --git a/cli/spdxtool/serialize.h b/cli/spdxtool/serialize.h index e04b7f38b741..a1eb99403406 100644 --- a/cli/spdxtool/serialize.h +++ b/cli/spdxtool/serialize.h @@ -203,7 +203,10 @@ spdxtool_serialize_value_object(spdxtool_serialize_object_list_t *object_list) { spdxtool_serialize_value_t *value = calloc(1, sizeof(spdxtool_serialize_value_t)); if (!value) + { + spdxtool_serialize_object_list_free(object_list); return NULL; + } value->type = SPDXTOOL_SERIALIZE_TYPE_OBJECT; value->value.o = object_list; @@ -227,7 +230,10 @@ spdxtool_serialize_value_array(spdxtool_serialize_array_t *array) { spdxtool_serialize_value_t *value = calloc(1, sizeof(spdxtool_serialize_value_t)); if (!value) + { + spdxtool_serialize_array_free(array); return NULL; + } value->type = SPDXTOOL_SERIALIZE_TYPE_ARRAY; value->value.a = array; diff --git a/cli/spdxtool/software.c b/cli/spdxtool/software.c index 4e9712ba6942..ac76cf73e7de 100644 --- a/cli/spdxtool/software.c +++ b/cli/spdxtool/software.c @@ -162,6 +162,37 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo free(spdx_id_relation); } + PKGCONF_FOREACH_LIST_ENTRY(sbom->rootElement->requires_private.head, node) + { + pkgconf_dependency_t *dep = node->data; + pkgconf_pkg_t *match = dep->match; + pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id); + char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); + if (!relationship_str) + goto err; + + char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); + free(relationship_str); + if (!spdx_id_relation) + goto err; + + if (!spdxtool_serialize_array_add_string(element_array, spdx_id_relation)) + { + free(spdx_id_relation); + goto err; + } + + if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, spdx_id_relation)) + { + free(spdx_id_relation); + goto err; + } + + free(spdx_id_relation); + } + char *value = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "hasDeclaredLicense"); if (value) { @@ -275,9 +306,11 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg spdxtool_serialize_value_t *ret = NULL; spdxtool_serialize_object_list_t *object_list = NULL; spdxtool_serialize_array_t *originated_by = NULL; + spdxtool_serialize_array_t *supplied_by = NULL; char *creation_info = NULL; char *spdx_id = NULL; char *agent = NULL; + char *supplier = NULL; char *spdx_id_license = NULL; pkgconf_list_t relations = PKGCONF_LIST_INITIALIZER; pkgconf_list_t *cpy_relations = NULL; @@ -314,6 +347,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; originated_by = NULL; + supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy"); + if (supplier) + { + supplied_by = spdxtool_serialize_array_new(); + if (!supplied_by) + goto err; + + if (!spdxtool_serialize_array_add_string(supplied_by, supplier)) + goto err; + + if (!spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by)) + goto err; + supplied_by = NULL; + } + if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright)) goto err; @@ -430,6 +478,56 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg cpy_relations = NULL; } + PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node) + { + pkgconf_dependency_t *dep = node->data; + pkgconf_pkg_t *match = dep->match; + pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; + + pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id); + char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); + if (!relationship_str) + goto err; + + char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); + free(relationship_str); + if (!spdx_id_relation) + goto err; + + char *spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->id); + if (!spdx_id_package) + { + free(spdx_id_relation); + goto err; + } + + cpy_relations = calloc(1, sizeof(pkgconf_list_t)); + if (!cpy_relations) + { + free(spdx_id_relation); + free(spdx_id_package); + goto err; + } + + pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package); + spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn"); + free(spdx_id_relation); + free(spdx_id_package); + if (!relationship) + goto err; + cpy_relations = NULL; + if (!spdxtool_core_relationship_set_scope(client, relationship, "development")) + { + spdxtool_core_relationship_free(relationship); + goto err; + } + if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) + { + spdxtool_core_relationship_free(relationship); + goto err; + } + } + ret = spdxtool_serialize_value_object(object_list); object_list = NULL; @@ -440,8 +538,10 @@ err: free(creation_info); free(spdx_id); free(agent); + free(supplier); free(spdx_id_license); spdxtool_serialize_object_list_free(object_list); spdxtool_serialize_array_free(originated_by); + spdxtool_serialize_array_free(supplied_by); return ret; } diff --git a/cli/spdxtool/util.h b/cli/spdxtool/util.h index e39c173e64c5..645d93a5a8e9 100644 --- a/cli/spdxtool/util.h +++ b/cli/spdxtool/util.h @@ -49,6 +49,7 @@ typedef struct spdxtool_core_spdx_document pkgconf_list_t rootElement; pkgconf_list_t relationships; pkgconf_list_t packages; + pkgconf_list_t maintainers; } spdxtool_core_spdx_document_t; typedef struct spdxtool_software_sbom_ @@ -76,6 +77,7 @@ typedef struct spdxtool_core_relationship_ char *from; pkgconf_list_t *to; char *relationship_type; + char *scope; } spdxtool_core_relationship_t; void |
