mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 18:36:12 +01:00 
			
		
		
		
	 59ad3225ae
			
		
	
	
	59ad3225ae
	
	
	
		
			
			Do not produce CPE element in SBOM, if mariadb-connector-c commit hash is not tagged (and thus does not correspond to any released version)
		
			
				
	
	
		
			306 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
| INCLUDE(generate_submodule_info)
 | |
| INCLUDE(ExternalProject)
 | |
| 
 | |
| 
 | |
| # Extract user name and repository name from a github URL.
 | |
| FUNCTION (EXTRACT_REPO_NAME_AND_USER repo_url repo_name_var repo_user_var)
 | |
|   IF(repo_url MATCHES "^git@")
 | |
|     # normalize to https-style URLs
 | |
|     STRING(REGEX REPLACE "^git@([^:]+):(.*)$" "https://\\1/\\2" repo_url "${repo_url}")
 | |
|   ENDIF()
 | |
|   # Extract the repository user
 | |
|   STRING(REGEX REPLACE "https://([^/]+)/([^/]+)/.*" "\\2" repo_user "${repo_url}")
 | |
| 
 | |
|   STRING(REGEX REPLACE ".*/([^/]*)$" "\\1" repo_name "${repo_url}")
 | |
|   STRING(REGEX REPLACE "\\.git$" "" repo_name "${repo_name}")
 | |
| 
 | |
|   SET(${repo_name_var} ${repo_name} PARENT_SCOPE)
 | |
|   SET(${repo_user_var} ${repo_user} PARENT_SCOPE)
 | |
| ENDFUNCTION()
 | |
| 
 | |
| # Add a known 3rd party dependency for SBOM generation
 | |
| # Currently used for "vendored" (part of our repository) source code we know about
 | |
| # such as zlib, as well ExternalProject_Add() projects
 | |
| MACRO(ADD_THIRD_PARTY_DEPENDENCY name url tag rev version description)
 | |
|  LIST(FIND ALL_THIRD_PARTY ${name} idx)
 | |
|  IF (idx GREATER -1)
 | |
|    MESSAGE(FATAL_ERROR "${name} is already in ALL_THIRD_PARTY")
 | |
|  ENDIF()
 | |
|  SET(${name}_URL ${url})
 | |
|  SET(${name}_TAG ${tag})
 | |
|  SET(${name}_REVISION ${rev})
 | |
|  SET(${name}_DESCRIPTION "${description}")
 | |
|  SET(${name}_VERSION "${version}")
 | |
|  LIST(APPEND ALL_THIRD_PARTY ${name})
 | |
| ENDMACRO()
 | |
| 
 | |
| # Get CPE ID ( https://en.wikipedia.org/wiki/Common_Platform_Enumeration )
 | |
| # for given project name and version
 | |
| # Only "known" CPEs are handled here, e.g currently no CPE for rocksdb
 | |
| FUNCTION(SBOM_GET_CPE name version var)
 | |
|   SET(cpe_prefix_map
 | |
|     "zlib" "zlib:zlib"
 | |
|     "mariadb-connector-c" "mariadb:connector\\\\/c"
 | |
|     "wolfssl" "wolfssl:wolfssl"
 | |
|     "minizip" "zlib:zlib"
 | |
|     "pcre2" "pcre:pcre2"
 | |
|     "fmt" "fmt:fmt"
 | |
|     "boost" "boost:boost"
 | |
|     "thrift" "apache:thrift"
 | |
|   )
 | |
|   LIST(FIND cpe_prefix_map "${name}" idx_cpe_mapping)
 | |
|   # Version needs to have at least one dot character in it.
 | |
|   # Otherwise, we assume it is a git  hash, and do not generate CPE
 | |
|   STRING(FIND "${version}" "." idx_version_dot)
 | |
|   IF((idx_cpe_mapping GREATER -1) AND (idx_version_dot GREATER -1))
 | |
|     MATH(EXPR next_idx "${idx_cpe_mapping}+1")
 | |
|     LIST(GET cpe_prefix_map ${next_idx} cpe_name_and_vendor)
 | |
|     STRING(REGEX REPLACE "[^0-9\\.]" "" cleaned_version "${version}")
 | |
|     SET(${var} "cpe:2.3:a:${cpe_name_and_vendor}:${cleaned_version}:*:*:*:*:*:*:*" PARENT_SCOPE)
 | |
|   ELSE()
 | |
|     SET(${var} "" PARENT_SCOPE)
 | |
|   ENDIF()
 | |
| ENDFUNCTION()
 | |
| 
 | |
| # Add dependency on CMake ExternalProject.
 | |
| # Currently, only works for github hosted projects,
 | |
| # URL property of the external project needs to point to release source download
 | |
| MACRO(ADD_CMAKE_EXTERNAL_PROJECT_DEPENDENCY name)
 | |
|   ExternalProject_GET_PROPERTY(${name} URL)
 | |
|   STRING(REGEX REPLACE "https://github.com/([^/]+/[^/]+)/releases/download/([^/]+)/.*-([^-]+)\\..*" "\\1;\\2;\\3" parsed "${URL}")
 | |
|   # Split the result into components
 | |
|   LIST(LENGTH parsed parsed_length)
 | |
|   IF(parsed_length EQUAL 3)
 | |
|     LIST(GET parsed 0 project_path)
 | |
|     LIST(GET parsed 1 tag)
 | |
|     LIST(GET parsed 2 ver)
 | |
|   ELSE()
 | |
|     STRING(REGEX REPLACE "https://github.com/([^/]+/[^/]+)/archive/refs/tags/([^/]+)\\.(tar\\.gz|zip)$" "\\1;\\2;\\3" parsed "${URL}")
 | |
|     LIST(LENGTH parsed parsed_length)
 | |
|     IF(parsed_length GREATER 1)
 | |
|       LIST(GET parsed 0 project_path)
 | |
|       LIST(GET parsed 1 tag)
 | |
|       STRING(REGEX REPLACE "[^0-9.]" "" ver "${tag}")
 | |
|     ELSE()
 | |
|       MESSAGE(FATAL_ERROR "Unexpected format for the download URL of project ${name} : (${URL})")
 | |
|     ENDIF()
 | |
|   ENDIF()
 | |
|   ADD_THIRD_PARTY_DEPENDENCY(${name} "https://github.com/${project_path}" "${tag}" "${tag}" "${ver}" "")
 | |
| ENDMACRO()
 | |
| 
 | |
| 
 | |
| # Match third party component with supplier
 | |
| # CyclonDX documentation says it is
 | |
| #  "The organization that supplied the component.
 | |
| #  The supplier may often be the manufacturer, but may also be a distributor or repackager."
 | |
| #
 | |
| # Perhaps it can always be "MariaDB", but security team recommendation is different
 | |
| # more towards "author"
 | |
| FUNCTION (sbom_get_supplier repo_name repo_user varname)
 | |
|   IF("${repo_name_SUPPLIER}")
 | |
|     SET(${varname} "${repo_name_SUPPLIER}" PARENT_SCOPE)
 | |
|   ELSEIF (repo_name MATCHES "zlib|minizip")
 | |
|     # stuff that is checked into out repos
 | |
|     SET(${varname} "MariaDB" PARENT_SCOPE)
 | |
|   ELSEIF (repo_name MATCHES "boost")
 | |
|     SET(${varname} "Boost.org" PARENT_SCOPE)
 | |
|   ELSEIF(repo_user MATCHES "mariadb-corporation|mariadb")
 | |
|     SET(${varname} "MariaDB")
 | |
|   ELSE()
 | |
|     # Capitalize just first letter in repo_user
 | |
|     STRING(SUBSTRING "${repo_user}" 0 1 first_letter)
 | |
|     STRING(SUBSTRING "${repo_user}" 1 -1 rest)
 | |
|     STRING(TOUPPER "${first_letter}" first_letter_upper)
 | |
|     SET(${varname} "${first_letter_upper}${rest}" PARENT_SCOPE)
 | |
|   ENDIF()
 | |
| ENDFUNCTION()
 | |
| 
 | |
| # Generate sbom.json in the top-level build directory
 | |
| FUNCTION(GENERATE_SBOM)
 | |
|   IF(EXISTS ${PROJECT_SOURCE_DIR}/cmake/submodule_info.cmake)
 | |
|     INCLUDE(${PROJECT_SOURCE_DIR}/cmake/submodule_info.cmake)
 | |
|   ELSE()
 | |
|     GENERATE_SUBMODULE_INFO(${PROJECT_BINARY_DIR}/cmake/submodule_info.cmake)
 | |
|     INCLUDE(${PROJECT_BINARY_DIR}/cmake/submodule_info.cmake)
 | |
|   ENDIF()
 | |
|   # Remove irrelevant for the current build submodule information
 | |
|   # That is, if we do not build say columnstore, do  not include
 | |
|   # dependency info into SBOM
 | |
|   IF(NOT TARGET wolfssl)
 | |
|     # using openssl, rather than wolfssl
 | |
|     LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX wolfssl)
 | |
|   ENDIF()
 | |
|   IF(NOT WITH_WSREP)
 | |
|     # wsrep is not compiled
 | |
|     LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX wsrep)
 | |
|   ENDIF()
 | |
|   IF(NOT TARGET columnstore)
 | |
|     LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX columnstore)
 | |
|   ENDIF()
 | |
|   IF(NOT TARGET rocksdb)
 | |
|     # Rocksdb is not compiled
 | |
|     LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX rocksdb)
 | |
|   ENDIF()
 | |
|   IF(NOT TARGET s3)
 | |
|     # S3 aria is not compiled
 | |
|     LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX storage/maria/libmarias3)
 | |
|   ENDIF()
 | |
|   # libmariadb/docs is not a library, so remove it
 | |
|   LIST(FILTER ALL_SUBMODULES EXCLUDE REGEX libmariadb/docs)
 | |
| 
 | |
|   # It is possible to provide  EXTRA_SBOM_DEPENDENCIES
 | |
|   # and accompanying per-dependency data, to extend generared sbom
 | |
|   # document.
 | |
|   # Example below injects an extra "ncurses" dependency  using several
 | |
|   # command line parameters for CMake.
 | |
|   # -DEXTRA_SBOM_DEPENDENCIES=ncurses
 | |
|   # -Dncurses_URL=https://github.com/mirror/ncurses
 | |
|   # -Dncurses_TAG=v6.4
 | |
|   # -Dncurses_VERSION=6.4
 | |
|   # -Dncurses_DESCRIPTION="A fake extra dependency"
 | |
|   SET(ALL_THIRD_PARTY ${ALL_SUBMODULES} ${EXTRA_SBOM_DEPENDENCIES})
 | |
| 
 | |
|   # Add dependencies on cmake ExternalProjects
 | |
|   FOREACH(ext_proj libfmt pcre2)
 | |
|     IF(TARGET ${ext_proj})
 | |
|       ADD_CMAKE_EXTERNAL_PROJECT_DEPENDENCY(${ext_proj})
 | |
|     ENDIF()
 | |
|   ENDFOREACH()
 | |
| 
 | |
|   # ZLIB
 | |
|   IF(TARGET zlib OR TARGET connect)
 | |
|     # Path to the zlib.h file
 | |
|     SET(ZLIB_HEADER_PATH "${PROJECT_SOURCE_DIR}/zlib/zlib.h")
 | |
|     # Variable to store the extracted version
 | |
|     SET(ZLIB_VERSION "")
 | |
|     # Read the version string from the file
 | |
|     file(STRINGS "${ZLIB_HEADER_PATH}" ZLIB_VERSION_LINE REGEX "#define ZLIB_VERSION.*")
 | |
|     # Extract the version number using a regex
 | |
|     IF (ZLIB_VERSION_LINE)
 | |
|       STRING(REGEX MATCH "\"([^\"]+)\"" ZLIB_VERSION_MATCH "${ZLIB_VERSION_LINE}")
 | |
|       IF (ZLIB_VERSION_MATCH)
 | |
|         STRING(REPLACE "\"" "" ZLIB_VERSION "${ZLIB_VERSION_MATCH}")
 | |
|         IF(NOT ("${ZLIB_VERSION}" MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+"))
 | |
|           MESSAGE(FATAL_ERROR "Unexpected zlib version '${ZLIB_VERSION}' parsed from ${ZLIB_HEADER_PATH}")
 | |
|         ENDIF()
 | |
|       ELSE()
 | |
|         MESSAGE(FATAL_ERROR "Could not extract ZLIB version from the line: ${ZLIB_VERSION_LINE}")
 | |
|       ENDIF()
 | |
|     ELSE()
 | |
|       MESSAGE(FATAL_ERROR "ZLIB_VERSION definition not found in ${ZLIB_HEADER_PATH}")
 | |
|     ENDIF()
 | |
|     IF(TARGET zlib)
 | |
|       ADD_THIRD_PARTY_DEPENDENCY(zlib "https://github.com/madler/zlib"
 | |
|       "v${ZLIB_VERSION}" "v${ZLIB_VERSION}" "${ZLIB_VERSION}" "Vendored zlib included into server source")
 | |
|     ENDIF()
 | |
|     IF(TARGET ha_connect OR TARGET connect)
 | |
|       SET(minizip_PURL "pkg:github/madler/zlib@${ZLIB_VERSION}?path=contrib/minizip")
 | |
|       ADD_THIRD_PARTY_DEPENDENCY(minizip "https://github.com/madler/zlib?path=contrib/minizip"
 | |
|       "v${ZLIB_VERSION}-minizip" "v${ZLIB_VERSION}-minizip" "${ZLIB_VERSION}"
 | |
|       "Vendored minizip (zip.c, unzip.c, ioapi.c) in connect engine, copied from zlib/contributions")
 | |
|     ENDIF()
 | |
|   ENDIF()
 | |
| 
 | |
|   IF(TARGET columnstore)
 | |
|     # Determining if Columnstore builds Boost is tricky.
 | |
|     # The presence of the external_boost target isn't reliable, it is always
 | |
|     # present. Instead, we check indirectly by verifying if one of the libraries
 | |
|     # built by the external project exists in the build directory.
 | |
|     IF(TARGET external_boost AND TARGET boost_filesystem)
 | |
|       GET_TARGET_PROPERTY(boost_filesystem_loc boost_filesystem IMPORTED_LOCATION)
 | |
|       STRING(FIND "${boost_filesystem_loc}" "${CMAKE_BINARY_DIR}" idx)
 | |
|       IF(idx EQUAL 0)
 | |
|         # Now we can be reasonably sure, external_boost is indeed an external project
 | |
|         ExternalProject_GET_PROPERTY(external_boost URL)
 | |
|         # Extract the version from the URL using string manipulation.
 | |
|         STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" BOOST_VERSION ${URL})
 | |
|         SET(tag boost-${BOOST_VERSION})
 | |
|         ADD_THIRD_PARTY_DEPENDENCY(boost
 | |
|           "https://github.com/boostorg/boost" "${tag}" "${tag}" "${BOOST_VERSION}"
 | |
|           "Boost library, linked with columnstore engine")
 | |
|       ENDIF()
 | |
|     ENDIF()
 | |
|     IF(TARGET external_thrift)
 | |
|       ADD_CMAKE_EXTERNAL_PROJECT_DEPENDENCY(external_thrift)
 | |
|     ENDIF()
 | |
|   ENDIF()
 | |
| 
 | |
|   SET(sbom_components "")
 | |
|   SET(sbom_dependencies "\n    {
 | |
|       \"ref\": \"${CPACK_PACKAGE_NAME}\",
 | |
|       \"dependsOn\": [" )
 | |
| 
 | |
|   SET(first ON)
 | |
|   FOREACH(dep ${ALL_THIRD_PARTY})
 | |
|     # Extract the part after the last "/" from URL
 | |
|     SET(revision ${${dep}_REVISION})
 | |
|     SET(tag ${${dep}_TAG})
 | |
|     SET(desc ${${dep}_DESCRIPTION})
 | |
|     IF((tag STREQUAL "no-tag") OR (NOT tag))
 | |
|      SET(tag ${revision})
 | |
|     ENDIF()
 | |
|     IF (NOT "${revision}" AND "${tag}")
 | |
|       SET(revision ${tag})
 | |
|     ENDIF()
 | |
|     SET(version ${${dep}_VERSION})
 | |
| 
 | |
|     IF (version)
 | |
|     ELSEIF(tag)
 | |
|       SET(version ${tag})
 | |
|     ELSEIF(revision)
 | |
|       SET(version ${revision})
 | |
|     ENDIF()
 | |
| 
 | |
|     EXTRACT_REPO_NAME_AND_USER("${${dep}_URL}"  repo_name repo_user)
 | |
| 
 | |
|     IF(first)
 | |
|       SET(first OFF)
 | |
|     ELSE()
 | |
|       STRING(APPEND sbom_components ",")
 | |
|       STRING(APPEND sbom_dependencies ",")
 | |
|     ENDIF()
 | |
|     SET(bom_ref "${repo_name}-${version}")
 | |
|     IF(desc)
 | |
|       SET(desc_line "\n      \"description\": \"${desc}\",")
 | |
|     ELSE()
 | |
|       SET(desc_line "")
 | |
|     ENDIF()
 | |
|     STRING(TOLOWER "${repo_user}" repo_user_lower)
 | |
|     STRING(TOLOWER "${repo_name}" repo_name_lower)
 | |
|     IF (${repo_name_lower}_PURL)
 | |
|       SET(purl "${${repo_name_lower}_PURL}")
 | |
|     ELSE()
 | |
|       SET(purl "pkg:github/${repo_user_lower}/${repo_name_lower}@${revision}")
 | |
|     ENDIF()
 | |
|     SBOM_GET_SUPPLIER(${repo_name_lower} ${repo_user_lower} supplier)
 | |
|     SBOM_GET_CPE(${repo_name_lower} "${version}" cpe)
 | |
|     IF(cpe)
 | |
|       SET(cpe "\n      \"cpe\": \"${cpe}\",")
 | |
|     ENDIF()
 | |
|     STRING(APPEND sbom_components "
 | |
|     {
 | |
|       \"bom-ref\": \"${bom_ref}\",
 | |
|       \"type\": \"library\",
 | |
|       \"name\": \"${repo_name}\",
 | |
|       \"version\": \"${version}\",${desc_line}
 | |
|       \"purl\": \"${purl}\",${cpe}
 | |
|       \"supplier\": {
 | |
|           \"name\": \"${supplier}\"
 | |
|        }
 | |
|     }")
 | |
|     STRING(APPEND sbom_dependencies "
 | |
|         \"${bom_ref}\"")
 | |
|     STRING(APPEND reflist ",\n    {\"ref\": \"${bom_ref}\"}")
 | |
|   ENDFOREACH()
 | |
|   STRING(APPEND sbom_dependencies "\n      ]\n    }${reflist}\n")
 | |
|   STRING(UUID UUID NAMESPACE ee390ca3-e70f-4b35-808e-a512489156f5 NAME SBOM TYPE SHA1)
 | |
|   STRING(TIMESTAMP TIMESTAMP "%Y-%m-%dT%H:%M:%SZ" UTC)
 | |
|   EXTRACT_REPO_NAME_AND_USER("${GIT_REMOTE_ORIGIN_URL}" GITHUB_REPO_NAME GITHUB_REPO_USER)
 | |
|   #github-purl needs lowercased user and project names
 | |
|   STRING(TOLOWER "${GITHUB_REPO_NAME}" GITHUB_REPO_NAME)
 | |
|   STRING(TOLOWER "${GITHUB_REPO_USER}" GITHUB_REPO_USER)
 | |
|   IF(NOT DEFINED CPACK_PACKAGE_VERSION)
 | |
|     SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
 | |
|   ENDIF()
 | |
|   configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/sbom.json.in ${CMAKE_BINARY_DIR}/sbom.json)
 | |
| ENDFUNCTION()
 |