mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-30 18:29:37 -06:00
cmSbom: Add SPDX object model and serializers
Adds definitions for representing software bill of materials (SBOM) information and generating SPDX SBOMs. Issue: #26719 Issue: #27001
This commit is contained in:
committed by
Daniel Tierney
parent
985b0f5bcf
commit
0653620033
@@ -701,6 +701,8 @@ add_library(
|
||||
cmRemoveDefinitionsCommand.h
|
||||
cmReturnCommand.cxx
|
||||
cmReturnCommand.h
|
||||
cmSbomObject.h
|
||||
cmSbomSerializer.h
|
||||
cmSearchPath.cxx
|
||||
cmSearchPath.h
|
||||
cmSeparateArgumentsCommand.cxx
|
||||
@@ -721,9 +723,10 @@ add_library(
|
||||
cmSiteNameCommand.h
|
||||
cmSourceGroupCommand.cxx
|
||||
cmSourceGroupCommand.h
|
||||
cmSPDXSerializer.cxx
|
||||
cmSPDXSerializer.h
|
||||
cmSPDXTypes.def
|
||||
cmSpdx.cxx
|
||||
cmSpdx.h
|
||||
cmSpdxSerializer.cxx
|
||||
cmSpdxSerializer.h
|
||||
cmString.cxx
|
||||
cmString.hxx
|
||||
cmStringReplaceHelper.cxx
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,54 +0,0 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#ifndef X_SPDX
|
||||
# define X_SPDX(classtype, enumid, member, camel)
|
||||
#endif
|
||||
|
||||
// Convenience
|
||||
X_SPDX(cmSPDXIdentifierReference, CM_IDENTIFIER_REFERENCE, IdentifierReference,
|
||||
identifierReference)
|
||||
|
||||
// Core
|
||||
X_SPDX(cmSPDXAgent, CORE_AGENT, Agent, agent)
|
||||
X_SPDX(cmSPDXAnnotation, CORE_ANNOTATION, Annotation, annotation)
|
||||
X_SPDX(cmSPDXBom, CORE_BOM, Bom, bom)
|
||||
X_SPDX(cmSPDXBundle, CORE_BUNDLE, Bundle, bundle)
|
||||
X_SPDX(cmSPDXCreationInfo, CORE_CREATION_INFO, CreationInfo, creationInfo)
|
||||
X_SPDX(cmSPDXDictionaryEntry, CORE_DICTIONARY_ENTRY, DictionaryEntry,
|
||||
dictionaryEntry)
|
||||
X_SPDX(cmSPDXExternalIdentifier, CORE_EXTERNAL_IDENTIFIER, ExternalIdentifier,
|
||||
externalIdentifier)
|
||||
X_SPDX(cmSPDXExternalMap, CORE_EXTERNAL_MAP, ExternalMap, externalMap)
|
||||
X_SPDX(cmSPDXExternalRef, CORE_EXTERNAL_REF, ExternalRef, externalRef)
|
||||
X_SPDX(cmSPDXHash, CORE_HASH, Hash, hash)
|
||||
X_SPDX(cmSPDXIndividualElement, CORE_INDIVIDUAL_ELEMENT, IndividualElement,
|
||||
individualElement)
|
||||
X_SPDX(cmSPDXLifecycleScopedRelationship, CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
|
||||
LifecycleScopedRelationship, lifecycleScopedRelationship)
|
||||
X_SPDX(cmSPDXNamespaceMap, CORE_NAMESPACE_MAP, NamespaceMap, namespaceMap)
|
||||
X_SPDX(cmSPDXOrganization, CORE_ORGANIZATION, Organization, organization)
|
||||
X_SPDX(cmSPDXPackageVerificationCode, CORE_PACKAGE_VERIFICATION_CODE,
|
||||
PackageVerificationCode, packageVerificationCode)
|
||||
X_SPDX(cmSPDXPerson, CORE_PERSON, Person, person)
|
||||
X_SPDX(cmSPDXPositiveIntegerRange, CORE_POSITIVE_INTEGER_RANGE,
|
||||
PositiveIntegerRange, positiveIntegerRange)
|
||||
X_SPDX(cmSPDXRelationship, CORE_RELATIONSHIP, Relationship, relationship)
|
||||
X_SPDX(cmSPDXSoftwareAgent, CORE_SOFTWARE_AGENT, SoftwareAgent, softwareAgent)
|
||||
X_SPDX(cmSPDXSpdxDocument, CORE_SPDX_DOCUMENT, SpdxDocument, spdxDocument)
|
||||
X_SPDX(cmSPDXTool, CORE_TOOL, Tool, tool)
|
||||
|
||||
// Software
|
||||
X_SPDX(cmSPDXContentIdentifier, SOFTWARE_CONTENT_IDENTIFIER, ContentIdentifier,
|
||||
contentIdentifier)
|
||||
X_SPDX(cmSPDXFile, SOFTWARE_FILE, File, file)
|
||||
X_SPDX(cmSPDXPackage, SOFTWARE_PACKAGE, Package, package)
|
||||
X_SPDX(cmSPDXSbom, SOFTWARE_SBOM, Sbom, sbom)
|
||||
X_SPDX(cmSPDXSnippet, SOFTWARE_SNIPPET, Snippet, snippet)
|
||||
|
||||
// SimpleLicensing
|
||||
X_SPDX(cmSPDXLicenseExpression, SIMPLE_LICENSING_LICENSE_EXPRESSION,
|
||||
LicenseExpression, licenseExpression)
|
||||
X_SPDX(cmSPDXSimpleLicensingText, SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT,
|
||||
SimpleLicensingText, simpleLicensingText)
|
||||
|
||||
#undef X_SPDX
|
||||
270
Source/cmSbomObject.h
Normal file
270
Source/cmSbomObject.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/type_traits>
|
||||
|
||||
#include "cmSbomSerializer.h"
|
||||
|
||||
class cmSbomObject;
|
||||
|
||||
template <typename T>
|
||||
inline void SerializeDispatch(T const& t, cmSbomSerializer& serializer)
|
||||
{
|
||||
serializer.BeginObject();
|
||||
t.Serialize(serializer);
|
||||
serializer.EndObject();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SerializeDispatch(T* p, cmSbomSerializer& serializer)
|
||||
{
|
||||
if (p->SpdxId) {
|
||||
serializer.AddReference(*p->SpdxId);
|
||||
}
|
||||
}
|
||||
|
||||
inline void SerializeDispatch(std::nullptr_t, cmSbomSerializer&)
|
||||
{
|
||||
}
|
||||
|
||||
struct ObjectInterface
|
||||
{
|
||||
virtual ObjectInterface* Copy(void* storage) const = 0;
|
||||
virtual ObjectInterface* Move(void* storage) = 0;
|
||||
virtual void* Addr() noexcept = 0;
|
||||
virtual void const* Addr() const noexcept = 0;
|
||||
virtual void SerializeImpl(cmSbomSerializer& os) const = 0;
|
||||
virtual ~ObjectInterface() = default;
|
||||
|
||||
ObjectInterface() = default;
|
||||
ObjectInterface(ObjectInterface const&) = default;
|
||||
ObjectInterface& operator=(ObjectInterface const&) = default;
|
||||
ObjectInterface(ObjectInterface&&) noexcept = default;
|
||||
ObjectInterface& operator=(ObjectInterface&&) noexcept = default;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20150623
|
||||
using max_align_t = ::max_align_t;
|
||||
#else
|
||||
using max_align_t = std::max_align_t;
|
||||
#endif
|
||||
|
||||
enum class StorageKind
|
||||
{
|
||||
Stack,
|
||||
Heap
|
||||
};
|
||||
|
||||
template <typename, StorageKind>
|
||||
struct Storage
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Storage<T, StorageKind::Stack> : ObjectInterface
|
||||
{
|
||||
using ValueType = cm::decay_t<T>;
|
||||
|
||||
explicit Storage(T x)
|
||||
: Value(std::move(x))
|
||||
{
|
||||
}
|
||||
|
||||
Storage(Storage&&) noexcept(
|
||||
std::is_nothrow_move_constructible<ValueType>::value) = default;
|
||||
~Storage() override = default;
|
||||
|
||||
void* Addr() noexcept override { return std::addressof(Value); }
|
||||
void const* Addr() const noexcept override { return std::addressof(Value); }
|
||||
|
||||
ValueType& get() { return Value; }
|
||||
ValueType const& get() const { return Value; }
|
||||
|
||||
private:
|
||||
ValueType Value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Storage<T, StorageKind::Heap> : ObjectInterface
|
||||
{
|
||||
using ValueType = cm::decay_t<T>;
|
||||
|
||||
explicit Storage(T x)
|
||||
: Ptr(new T(std::move(x)))
|
||||
{
|
||||
}
|
||||
|
||||
Storage(Storage&&) noexcept = default;
|
||||
~Storage() override = default;
|
||||
|
||||
void* Addr() noexcept override { return Ptr.get(); }
|
||||
void const* Addr() const noexcept override { return Ptr.get(); }
|
||||
|
||||
ValueType& get() { return *Ptr; }
|
||||
ValueType const& get() const { return *Ptr; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<ValueType> Ptr;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Storage<std::nullptr_t, StorageKind::Stack> : ObjectInterface
|
||||
{
|
||||
explicit Storage(std::nullptr_t) {}
|
||||
|
||||
Storage(Storage&&) noexcept = default;
|
||||
~Storage() override = default;
|
||||
|
||||
void* Addr() noexcept override { return nullptr; }
|
||||
void const* Addr() const noexcept override { return nullptr; }
|
||||
|
||||
void SerializeImpl(cmSbomSerializer&) const override {}
|
||||
|
||||
std::nullptr_t get() { return nullptr; }
|
||||
std::nullptr_t get() const { return nullptr; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct ObjectStorage
|
||||
{
|
||||
template <typename T>
|
||||
using Stack = impl::Storage<T, impl::StorageKind::Stack>;
|
||||
template <typename T>
|
||||
using Heap = impl::Storage<T, impl::StorageKind::Heap>;
|
||||
|
||||
static constexpr std::size_t BufferSize = 128u;
|
||||
|
||||
static constexpr std::size_t Size = sizeof(Heap<std::nullptr_t>) > BufferSize
|
||||
? sizeof(Heap<std::nullptr_t>)
|
||||
: BufferSize;
|
||||
static constexpr std::size_t Align = alignof(impl::max_align_t);
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
alignas(Align) unsigned char Data[Size];
|
||||
};
|
||||
|
||||
template <typename Concrete>
|
||||
using Model = cm::conditional_t<sizeof(Stack<Concrete>) <= Size &&
|
||||
alignof(Stack<Concrete>) <= Align,
|
||||
Stack<Concrete>, Heap<Concrete>>;
|
||||
};
|
||||
|
||||
class cmSbomObject
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
struct Instance : ObjectStorage::Model<T>
|
||||
{
|
||||
using Base = ObjectStorage::Model<T>;
|
||||
using Base::Base;
|
||||
Instance(Instance&&) noexcept = default;
|
||||
|
||||
ObjectInterface* Copy(void* storage) const override
|
||||
{
|
||||
return ::new (storage) Instance(this->get());
|
||||
}
|
||||
|
||||
ObjectInterface* Move(void* storage) override
|
||||
{
|
||||
return ::new (storage) Instance(std::move(*this));
|
||||
}
|
||||
|
||||
void SerializeImpl(cmSbomSerializer& os) const override
|
||||
{
|
||||
SerializeDispatch(this->get(), os);
|
||||
}
|
||||
};
|
||||
|
||||
cmSbomObject() { ::new (Storage()) Instance<std::nullptr_t>(nullptr); }
|
||||
cmSbomObject(std::nullptr_t)
|
||||
: cmSbomObject()
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename T, typename Decayed = cm::remove_cv_t<cm::remove_reference_t<T>>,
|
||||
typename = cm::enable_if_t<!std::is_same<Decayed, cmSbomObject>::value>>
|
||||
cmSbomObject(T&& x)
|
||||
{
|
||||
::new (Storage()) Instance<Decayed>(std::forward<T>(x));
|
||||
}
|
||||
|
||||
cmSbomObject(cmSbomObject const& other)
|
||||
{
|
||||
other.Interface().Copy(Storage());
|
||||
}
|
||||
cmSbomObject(cmSbomObject&& other) noexcept
|
||||
{
|
||||
other.Interface().Move(Storage());
|
||||
}
|
||||
|
||||
~cmSbomObject() noexcept { Interface().~ObjectInterface(); }
|
||||
|
||||
cmSbomObject& operator=(cmSbomObject rhs)
|
||||
{
|
||||
Interface().~ObjectInterface();
|
||||
rhs.Interface().Move(Storage());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IsNull() const noexcept { return Interface().Addr() == nullptr; }
|
||||
explicit operator bool() const noexcept { return !IsNull(); }
|
||||
|
||||
void Serialize(cmSbomSerializer& os) const { Interface().SerializeImpl(os); }
|
||||
|
||||
template <typename T>
|
||||
T& CastUnchecked()
|
||||
{
|
||||
return *static_cast<T*>(Interface().Addr());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T const& CastUnchecked() const
|
||||
{
|
||||
return *static_cast<T const*>(Interface().Addr());
|
||||
}
|
||||
|
||||
ObjectInterface& Interface()
|
||||
{
|
||||
return *static_cast<ObjectInterface*>(Storage());
|
||||
}
|
||||
ObjectInterface const& Interface() const
|
||||
{
|
||||
return *static_cast<ObjectInterface const*>(Storage());
|
||||
}
|
||||
|
||||
void* Storage() { return &Data.Data; }
|
||||
void const* Storage() const { return &Data.Data; }
|
||||
|
||||
template <typename U>
|
||||
U* ptr() noexcept
|
||||
{
|
||||
return std::addressof(this->template CastUnchecked<U>());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
U const* ptr() const noexcept
|
||||
{
|
||||
return std::addressof(this->template CastUnchecked<U>());
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectStorage::Buffer Data{};
|
||||
};
|
||||
|
||||
template <typename T, typename U = cm::decay_t<T>>
|
||||
U* insert_back(std::vector<cmSbomObject>& vec, T&& obj) noexcept
|
||||
{
|
||||
vec.emplace_back(std::forward<U>(obj));
|
||||
return std::addressof(vec.back().CastUnchecked<U>());
|
||||
}
|
||||
38
Source/cmSbomSerializer.h
Normal file
38
Source/cmSbomSerializer.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
class cmSbomObject;
|
||||
class cmSbomSerializer
|
||||
{
|
||||
public:
|
||||
cmSbomSerializer() = default;
|
||||
cmSbomSerializer(cmSbomSerializer const&) = default;
|
||||
cmSbomSerializer(cmSbomSerializer&&) = default;
|
||||
cmSbomSerializer& operator=(cmSbomSerializer const&) = default;
|
||||
cmSbomSerializer& operator=(cmSbomSerializer&&) = default;
|
||||
|
||||
virtual void BeginObject() {}
|
||||
virtual void EndObject() {}
|
||||
virtual void BeginArray() {}
|
||||
virtual void EndArray() {}
|
||||
|
||||
virtual void AddReference(std::string const& id) = 0;
|
||||
|
||||
virtual void AddString(std::string const& key, std::string const& value) = 0;
|
||||
virtual void AddVisitable(std::string const& key,
|
||||
cmSbomObject const& visitable) = 0;
|
||||
|
||||
virtual void AddVectorIfPresent(std::string const& key,
|
||||
std::vector<cmSbomObject> const& vec) = 0;
|
||||
virtual void AddVectorIfPresent(std::string const& key,
|
||||
std::vector<std::string> const& vec) = 0;
|
||||
|
||||
virtual bool WriteSbom(std::ostream& os, cmSbomObject const& document) = 0;
|
||||
virtual ~cmSbomSerializer() = default;
|
||||
};
|
||||
520
Source/cmSpdx.cxx
Normal file
520
Source/cmSpdx.cxx
Normal file
@@ -0,0 +1,520 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmSpdx.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "cmSbomSerializer.h"
|
||||
|
||||
inline void SerializeIfPresent(cmSbomSerializer& s, std::string const& key,
|
||||
cm::optional<std::string> const& v)
|
||||
{
|
||||
if (v) {
|
||||
s.AddString(key, *v);
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxIntegrityMethod::HashAlgorithmId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::ADLER32:
|
||||
return "ADLER32";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B256:
|
||||
return "BLAKE2B256";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B384:
|
||||
return "BLAKE2B384";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B512:
|
||||
return "BLAKE2B512";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE3:
|
||||
return "BLAKE3";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::MD2:
|
||||
return "MD2";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::MD4:
|
||||
return "MD4";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::MD5:
|
||||
return "MD5";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::MD6:
|
||||
return "MD6";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA1:
|
||||
return "SHA1";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA224:
|
||||
return "SHA224";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA256:
|
||||
return "SHA256";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA384:
|
||||
return "SHA384";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA512:
|
||||
return "SHA512";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_256:
|
||||
return "SHA3_256";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_384:
|
||||
return "SHA3_384";
|
||||
case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_512:
|
||||
return "SHA3_512";
|
||||
}
|
||||
throw std::invalid_argument("Unknown HashAlgorithmId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxSoftwareArtifact::PurposeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxSoftwareArtifact::PurposeId::APPLICATION:
|
||||
return "APPLICATION";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::ARCHIVE:
|
||||
return "ARCHIVE";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::CONTAINER:
|
||||
return "CONTAINER";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::DATA:
|
||||
return "DATA";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::DEVICE:
|
||||
return "DEVICE";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::FIRMWARE:
|
||||
return "FIRMWARE";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::FILE:
|
||||
return "FILE";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::INSTALL:
|
||||
return "INSTALL";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::LIBRARY:
|
||||
return "LIBRARY";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::MODULE:
|
||||
return "MODULE";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::OPERATING_SYSTEM:
|
||||
return "OPERATING_SYSTEM";
|
||||
case cmSpdxSoftwareArtifact::PurposeId::SOURCE:
|
||||
return "SOURCE";
|
||||
}
|
||||
throw std::invalid_argument("Unknown PurposeId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxSbom::TypeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxSbom::TypeId::ANALYZED:
|
||||
return "ANALYZED";
|
||||
case cmSpdxSbom::TypeId::BUILD:
|
||||
return "BUILD";
|
||||
case cmSpdxSbom::TypeId::DEPLOYED:
|
||||
return "DEPLOYED";
|
||||
case cmSpdxSbom::TypeId::DESIGN:
|
||||
return "DESIGN";
|
||||
case cmSpdxSbom::TypeId::RUNTIME:
|
||||
return "RUNTIME";
|
||||
case cmSpdxSbom::TypeId::SOURCE:
|
||||
return "SOURCE";
|
||||
case cmSpdxSbom::TypeId::TEST:
|
||||
return "TEST";
|
||||
}
|
||||
throw std::invalid_argument("Unknown Sbom::TypeId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxFile::FileKindId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxFile::FileKindId::DIRECTORY:
|
||||
return "DIRECTORY";
|
||||
case cmSpdxFile::FileKindId::FILE:
|
||||
return "FILE";
|
||||
}
|
||||
throw std::invalid_argument("Unknown File::FileKindId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxRelationship::RelationshipTypeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxRelationship::RelationshipTypeId::DESCRIBES:
|
||||
return "DESCRIBES";
|
||||
case cmSpdxRelationship::RelationshipTypeId::CONTAINS:
|
||||
return "CONTAINS";
|
||||
case cmSpdxRelationship::RelationshipTypeId::DEPENDS_ON:
|
||||
return "DEPENDS_ON";
|
||||
case cmSpdxRelationship::RelationshipTypeId::OTHER:
|
||||
return "OTHER";
|
||||
}
|
||||
throw std::invalid_argument("Unknown RelationshipTypeId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxLifecycleScopedRelationship::ScopeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxLifecycleScopedRelationship::ScopeId::BUILD:
|
||||
return "BUILD";
|
||||
case cmSpdxLifecycleScopedRelationship::ScopeId::DESIGN:
|
||||
return "DESIGN";
|
||||
case cmSpdxLifecycleScopedRelationship::ScopeId::RUNTIME:
|
||||
return "RUNTIME";
|
||||
case cmSpdxLifecycleScopedRelationship::ScopeId::TEST:
|
||||
return "TEST";
|
||||
}
|
||||
throw std::invalid_argument("Unknown Lifecycle ScopeId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxAnnotation::AnnotationTypeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxAnnotation::AnnotationTypeId::REVIEW:
|
||||
return "REVIEW";
|
||||
case cmSpdxAnnotation::AnnotationTypeId::OTHER:
|
||||
return "OTHER";
|
||||
}
|
||||
throw std::invalid_argument("Unknown AnnotationTypeId");
|
||||
}
|
||||
|
||||
std::string to_string(cmSpdxArtifact::SupportTypeId id)
|
||||
{
|
||||
switch (id) {
|
||||
case cmSpdxArtifact::SupportTypeId::COMMUNITY:
|
||||
return "COMMUNITY";
|
||||
case cmSpdxArtifact::SupportTypeId::COMMERCIAL:
|
||||
return "COMMERCIAL";
|
||||
case cmSpdxArtifact::SupportTypeId::NONE:
|
||||
return "NONE";
|
||||
}
|
||||
throw std::invalid_argument("Unknown SupportTypeId");
|
||||
}
|
||||
|
||||
void cmSpdxExternalIdentifier::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "ExternalIdentifier");
|
||||
SerializeIfPresent(serializer, "externalIdentifierType",
|
||||
ExternalIdentifierType);
|
||||
SerializeIfPresent(serializer, "identifier", Identifier);
|
||||
SerializeIfPresent(serializer, "comment", Comment);
|
||||
SerializeIfPresent(serializer, "identifierLocation", IdentifierLocation);
|
||||
SerializeIfPresent(serializer, "issuingAuthority", IssuingAuthority);
|
||||
}
|
||||
|
||||
void cmSpdxExternalRef::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "ExternalRef");
|
||||
SerializeIfPresent(serializer, "externalRefType", ExternalRefType);
|
||||
SerializeIfPresent(serializer, "locator", Locator);
|
||||
SerializeIfPresent(serializer, "contentType", ContentType);
|
||||
SerializeIfPresent(serializer, "comment", Comment);
|
||||
}
|
||||
|
||||
void cmSpdxChecksum::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "Checksum");
|
||||
serializer.AddString("algorithm", to_string(Algorithm));
|
||||
serializer.AddString("checksumValue", ChecksumValue);
|
||||
}
|
||||
|
||||
void cmSpdxCreationInfo::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "CreationInfo");
|
||||
SerializeIfPresent(serializer, "@id", SpdxId);
|
||||
if (SpecVersion) {
|
||||
serializer.AddString("specVersion", *SpecVersion);
|
||||
}
|
||||
SerializeIfPresent(serializer, "comment", Comment);
|
||||
SerializeIfPresent(serializer, "created", Created);
|
||||
if (!CreatedBy.empty()) {
|
||||
serializer.AddVectorIfPresent("createdBy", CreatedBy);
|
||||
}
|
||||
if (!CreatedUsing.empty()) {
|
||||
serializer.AddVectorIfPresent("createdUsing", CreatedUsing);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxIntegrityMethod::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "IntegrityMethod");
|
||||
SerializeIfPresent(serializer, "comment", Comment);
|
||||
}
|
||||
|
||||
void cmSpdxElement::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "Element");
|
||||
SerializeIfPresent(serializer, "@id", SpdxId);
|
||||
SerializeIfPresent(serializer, "name", Name);
|
||||
SerializeIfPresent(serializer, "summary", Summary);
|
||||
SerializeIfPresent(serializer, "description", Description);
|
||||
SerializeIfPresent(serializer, "comment", Comment);
|
||||
if (CreationInfo) {
|
||||
serializer.AddVisitable("creationInfo", *CreationInfo);
|
||||
}
|
||||
if (VerifiedUsing) {
|
||||
serializer.AddVisitable("verifiedUsing", *VerifiedUsing);
|
||||
}
|
||||
if (!ExternalRef.empty()) {
|
||||
serializer.AddVectorIfPresent("externalRef", ExternalRef);
|
||||
}
|
||||
if (!ExternalIdentifier.empty()) {
|
||||
serializer.AddVectorIfPresent("externalIdentifier", ExternalIdentifier);
|
||||
}
|
||||
if (Extension) {
|
||||
serializer.AddVisitable("extension", *Extension);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxTool::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "Tool");
|
||||
}
|
||||
|
||||
void cmSpdxAgent::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "Agent");
|
||||
}
|
||||
|
||||
void cmSpdxOrganization::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxAgent::Serialize(serializer);
|
||||
serializer.AddString("type", "Organization");
|
||||
}
|
||||
|
||||
void cmSpdxPerson::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxAgent::Serialize(serializer);
|
||||
serializer.AddString("type", "Person");
|
||||
}
|
||||
|
||||
void cmSpdxSoftwareAgent::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxAgent::Serialize(serializer);
|
||||
serializer.AddString("type", "SoftwareAgent");
|
||||
}
|
||||
|
||||
void cmSpdxPositiveIntegerRange::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "PositiveIntegerRange");
|
||||
SerializeIfPresent(serializer, "beginIntegerRange", BeginIntegerRange);
|
||||
SerializeIfPresent(serializer, "endIntegerRange", EndIntegerRange);
|
||||
}
|
||||
|
||||
void cmSpdxRelationship::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "Relationship");
|
||||
if (From) {
|
||||
serializer.AddVisitable("from", *From);
|
||||
}
|
||||
if (!To.empty()) {
|
||||
serializer.AddVectorIfPresent("to", To);
|
||||
}
|
||||
if (RelationshipType) {
|
||||
serializer.AddString("relationshipType", to_string(*RelationshipType));
|
||||
}
|
||||
SerializeIfPresent(serializer, "startTime", StartTime);
|
||||
SerializeIfPresent(serializer, "endTime", EndTime);
|
||||
}
|
||||
|
||||
void cmSpdxLifecycleScopedRelationship::Serialize(
|
||||
cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxRelationship::Serialize(serializer);
|
||||
serializer.AddString("type", "LifecycleScopedRelationship");
|
||||
if (Scope) {
|
||||
serializer.AddString("scope", to_string(*Scope));
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxArtifact::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "Artifact");
|
||||
if (!OriginatedBy.empty()) {
|
||||
serializer.AddVectorIfPresent("originatedBy", OriginatedBy);
|
||||
}
|
||||
if (SuppliedBy) {
|
||||
serializer.AddVisitable("suppliedBy", *SuppliedBy);
|
||||
}
|
||||
SerializeIfPresent(serializer, "builtTime", BuiltTime);
|
||||
SerializeIfPresent(serializer, "releaseTime", ReleaseTime);
|
||||
SerializeIfPresent(serializer, "validUntilTime", ValidUntilTime);
|
||||
SerializeIfPresent(serializer, "standardName", StandardName);
|
||||
if (Support) {
|
||||
serializer.AddString("support", to_string(*Support));
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxIndividualElement::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "IndividualElement");
|
||||
}
|
||||
|
||||
void cmSpdxAnnotation::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "Annotation");
|
||||
if (AnnotationType) {
|
||||
serializer.AddString("annotationType", to_string(*AnnotationType));
|
||||
}
|
||||
SerializeIfPresent(serializer, "contentType", ContentType);
|
||||
SerializeIfPresent(serializer, "statement", Statement);
|
||||
if (Element) {
|
||||
serializer.AddVisitable("element", *Element);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxExternalMap::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "ExternalMap");
|
||||
SerializeIfPresent(serializer, "externalSpdxId", ExternalSpdxId);
|
||||
if (VerifiedUsing) {
|
||||
serializer.AddVisitable("verifiedUsing", *VerifiedUsing);
|
||||
}
|
||||
SerializeIfPresent(serializer, "locationHistory", LocationHistory);
|
||||
if (DefiningArtifact) {
|
||||
serializer.AddVisitable("definingArtifact", *DefiningArtifact);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxNamespaceMap::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "NamespaceMap");
|
||||
SerializeIfPresent(serializer, "prefix", Prefix);
|
||||
SerializeIfPresent(serializer, "namespace", Namespace);
|
||||
}
|
||||
|
||||
void cmSpdxElementCollection::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElement::Serialize(serializer);
|
||||
serializer.AddString("type", "ElementCollection");
|
||||
if (!Elements.empty()) {
|
||||
serializer.AddVectorIfPresent("element", Elements);
|
||||
}
|
||||
if (!RootElements.empty()) {
|
||||
serializer.AddVectorIfPresent("rootElement", RootElements);
|
||||
}
|
||||
if (!ProfileConformance.empty()) {
|
||||
serializer.AddVectorIfPresent("profileConformance", ProfileConformance);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxPackageVerificationCode::Serialize(
|
||||
cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "PackageVerificationCode");
|
||||
if (Algorithm) {
|
||||
serializer.AddString("algorithm", to_string(*Algorithm));
|
||||
}
|
||||
SerializeIfPresent(serializer, "hashValue", HashValue);
|
||||
SerializeIfPresent(serializer, "packageVerificationCodeExcludedFile",
|
||||
PackageVerificationCodeExcludedFile);
|
||||
}
|
||||
|
||||
void cmSpdxHash::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString("type", "Hash");
|
||||
serializer.AddString("hashAlgorithm", to_string(HashAlgorithm));
|
||||
serializer.AddString("hashValue", HashValue);
|
||||
}
|
||||
|
||||
void cmSpdxBundle::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElementCollection::Serialize(serializer);
|
||||
serializer.AddString("type", "Bundle");
|
||||
SerializeIfPresent(serializer, "context", Context);
|
||||
}
|
||||
|
||||
void cmSpdxBom::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxBundle::Serialize(serializer);
|
||||
serializer.AddString("type", "Bom");
|
||||
}
|
||||
|
||||
void cmSpdxSbom::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxBom::Serialize(serializer);
|
||||
serializer.AddString("type", "software_Sbom");
|
||||
if (Types) {
|
||||
for (auto const& t : *Types) {
|
||||
serializer.AddString("sbomType", to_string(t));
|
||||
}
|
||||
}
|
||||
if (LifecycleScope) {
|
||||
serializer.AddString("lifecycleScope", to_string(*LifecycleScope));
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxSoftwareArtifact::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxArtifact::Serialize(serializer);
|
||||
serializer.AddString("type", "software_SoftwareArtifact");
|
||||
if (PrimaryPurpose) {
|
||||
serializer.AddString("primaryPurpose", to_string(*PrimaryPurpose));
|
||||
}
|
||||
if (AdditionalPurpose) {
|
||||
for (auto const& p : *AdditionalPurpose) {
|
||||
serializer.AddString("additionalPurpose", to_string(p));
|
||||
}
|
||||
}
|
||||
SerializeIfPresent(serializer, "copyrightText", CopyrightText);
|
||||
SerializeIfPresent(serializer, "attributionText", AttributionText);
|
||||
if (ContentIdentifier) {
|
||||
serializer.AddVisitable("contentIdentifier", *ContentIdentifier);
|
||||
}
|
||||
SerializeIfPresent(serializer, "artifactSize", ArtifactSize);
|
||||
}
|
||||
|
||||
void cmSpdxPackage::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxSoftwareArtifact::Serialize(serializer);
|
||||
serializer.AddString("type", "software_Package");
|
||||
SerializeIfPresent(serializer, "downloadLocation", DownloadLocation);
|
||||
SerializeIfPresent(serializer, "homePage", Homepage);
|
||||
SerializeIfPresent(serializer, "packageVersion", PackageVersion);
|
||||
SerializeIfPresent(serializer, "packageUrl", PackageUrl);
|
||||
SerializeIfPresent(serializer, "sourceInfo", SourceInfo);
|
||||
}
|
||||
|
||||
void cmSpdxFile::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxArtifact::Serialize(serializer);
|
||||
serializer.AddString("type", "software_File");
|
||||
if (ContentType) {
|
||||
serializer.AddString("contentType", *ContentType);
|
||||
}
|
||||
if (FileType) {
|
||||
serializer.AddString("fileType", to_string(*FileType));
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxContentIdentifier::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxIntegrityMethod::Serialize(serializer);
|
||||
serializer.AddString("type", "software_ContentIdentifier");
|
||||
SerializeIfPresent(serializer, "contentIdentifierType",
|
||||
ContentIdentifierType);
|
||||
SerializeIfPresent(serializer, "contentValue", ContentValue);
|
||||
}
|
||||
|
||||
void cmSpdxSnippet::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxSoftwareArtifact::Serialize(serializer);
|
||||
serializer.AddString("type", "software_Snippet");
|
||||
SerializeIfPresent(serializer, "byteRange", ByteRange);
|
||||
SerializeIfPresent(serializer, "lineRange", LineRange);
|
||||
if (SnippetFromFile) {
|
||||
serializer.AddVisitable("snippetFromFile", *SnippetFromFile);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxDocument::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
cmSpdxElementCollection::Serialize(serializer);
|
||||
|
||||
serializer.AddString("type", "SpdxDocument");
|
||||
if (ExternalMap) {
|
||||
serializer.AddVisitable("externalMap", *ExternalMap);
|
||||
}
|
||||
if (NamespaceMap) {
|
||||
serializer.AddVisitable("namespaceMap", *NamespaceMap);
|
||||
}
|
||||
SerializeIfPresent(serializer, "dataLicense", DataLicense);
|
||||
}
|
||||
|
||||
void cmSbomDocument::Serialize(cmSbomSerializer& serializer) const
|
||||
{
|
||||
serializer.AddString(
|
||||
"@context",
|
||||
Context.value_or("https://spdx.org/rdf/3.0.1/spdx-context.jsonld"));
|
||||
if (!Graph.empty()) {
|
||||
serializer.AddVectorIfPresent("@graph", Graph);
|
||||
}
|
||||
}
|
||||
390
Source/cmSpdx.h
Normal file
390
Source/cmSpdx.h
Normal file
@@ -0,0 +1,390 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmSbomObject.h"
|
||||
|
||||
class cmSbomSerializer;
|
||||
|
||||
using Datetime = std::string;
|
||||
using MediaType = std::string;
|
||||
using SemVer = std::string;
|
||||
|
||||
struct cmSpdxExternalIdentifier
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> ExternalIdentifierType;
|
||||
cm::optional<std::string> Identifier;
|
||||
cm::optional<std::string> Comment;
|
||||
cm::optional<std::string> IdentifierLocation;
|
||||
cm::optional<std::string> IssuingAuthority;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxExternalRef
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> ExternalRefType;
|
||||
cm::optional<std::string> Locator;
|
||||
cm::optional<std::string> ContentType;
|
||||
cm::optional<std::string> Comment;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxCreationInfo
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<SemVer> SpecVersion;
|
||||
cm::optional<std::string> Comment;
|
||||
cm::optional<Datetime> Created;
|
||||
std::vector<cmSbomObject> CreatedBy;
|
||||
std::vector<cmSbomObject> CreatedUsing;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxIntegrityMethod
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> Comment;
|
||||
|
||||
enum HashAlgorithmId
|
||||
{
|
||||
ADLER32,
|
||||
BLAKE2B256,
|
||||
BLAKE2B384,
|
||||
BLAKE2B512,
|
||||
BLAKE3,
|
||||
MD2,
|
||||
MD4,
|
||||
MD5,
|
||||
MD6,
|
||||
SHA1,
|
||||
SHA224,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
SHA3_256,
|
||||
SHA3_384,
|
||||
SHA3_512,
|
||||
};
|
||||
|
||||
cmSpdxIntegrityMethod() = default;
|
||||
cmSpdxIntegrityMethod(cmSpdxIntegrityMethod const&) = default;
|
||||
cmSpdxIntegrityMethod(cmSpdxIntegrityMethod&&) = default;
|
||||
cmSpdxIntegrityMethod& operator=(cmSpdxIntegrityMethod const&) = default;
|
||||
cmSpdxIntegrityMethod& operator=(cmSpdxIntegrityMethod&&) = default;
|
||||
|
||||
virtual void Serialize(cmSbomSerializer&) const;
|
||||
virtual ~cmSpdxIntegrityMethod() = default;
|
||||
};
|
||||
|
||||
struct cmSpdxChecksum
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cmSpdxIntegrityMethod::HashAlgorithmId Algorithm;
|
||||
std::string ChecksumValue;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxElement
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> Name;
|
||||
cm::optional<std::string> Summary;
|
||||
cm::optional<std::string> Description;
|
||||
cm::optional<std::string> Comment;
|
||||
cm::optional<cmSbomObject> CreationInfo;
|
||||
cm::optional<cmSbomObject> VerifiedUsing;
|
||||
std::vector<cmSbomObject> ExternalRef;
|
||||
std::vector<cmSbomObject> ExternalIdentifier;
|
||||
cm::optional<cmSbomObject> Extension;
|
||||
|
||||
cmSpdxElement() = default;
|
||||
cmSpdxElement(cmSpdxElement const&) = default;
|
||||
cmSpdxElement(cmSpdxElement&&) = default;
|
||||
cmSpdxElement& operator=(cmSpdxElement const&) = default;
|
||||
cmSpdxElement& operator=(cmSpdxElement&&) = default;
|
||||
|
||||
virtual ~cmSpdxElement() = default;
|
||||
virtual void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxTool final : cmSpdxElement
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxAgent : cmSpdxElement
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxOrganization final : cmSpdxAgent
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxPerson final : cmSpdxAgent
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxSoftwareAgent final : cmSpdxAgent
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxPositiveIntegerRange
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> BeginIntegerRange;
|
||||
cm::optional<std::string> EndIntegerRange;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxRelationship : cmSpdxElement
|
||||
{
|
||||
enum RelationshipTypeId
|
||||
{
|
||||
DESCRIBES,
|
||||
CONTAINS,
|
||||
DEPENDS_ON,
|
||||
OTHER
|
||||
};
|
||||
|
||||
cm::optional<cmSbomObject> From;
|
||||
std::vector<cmSbomObject> To;
|
||||
cm::optional<RelationshipTypeId> RelationshipType;
|
||||
cm::optional<Datetime> StartTime;
|
||||
cm::optional<Datetime> EndTime;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxLifecycleScopedRelationship final : cmSpdxRelationship
|
||||
{
|
||||
enum ScopeId
|
||||
{
|
||||
BUILD,
|
||||
DESIGN,
|
||||
RUNTIME,
|
||||
TEST
|
||||
};
|
||||
|
||||
cm::optional<ScopeId> Scope;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxArtifact : cmSpdxElement
|
||||
{
|
||||
enum SupportTypeId
|
||||
{
|
||||
COMMUNITY,
|
||||
COMMERCIAL,
|
||||
NONE
|
||||
};
|
||||
|
||||
std::vector<cmSbomObject> OriginatedBy;
|
||||
cm::optional<cmSbomObject> SuppliedBy;
|
||||
cm::optional<Datetime> BuiltTime;
|
||||
cm::optional<Datetime> ReleaseTime;
|
||||
cm::optional<Datetime> ValidUntilTime;
|
||||
cm::optional<std::string> StandardName;
|
||||
cm::optional<SupportTypeId> Support;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxIndividualElement final : cmSpdxElement
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxAnnotation final : cmSpdxElement
|
||||
{
|
||||
enum AnnotationTypeId
|
||||
{
|
||||
REVIEW,
|
||||
OTHER
|
||||
};
|
||||
|
||||
cm::optional<AnnotationTypeId> AnnotationType;
|
||||
cm::optional<MediaType> ContentType;
|
||||
cm::optional<std::string> Statement;
|
||||
cm::optional<cmSbomObject> Element;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxExternalMap
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> ExternalSpdxId;
|
||||
cm::optional<cmSbomObject> VerifiedUsing;
|
||||
cm::optional<std::string> LocationHistory;
|
||||
cm::optional<cmSbomObject> DefiningArtifact;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxNamespaceMap
|
||||
{
|
||||
cm::optional<std::string> SpdxId;
|
||||
cm::optional<std::string> Prefix;
|
||||
cm::optional<std::string> Namespace;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
|
||||
struct cmSpdxElementCollection : cmSpdxElement
|
||||
{
|
||||
std::vector<cmSbomObject> Elements;
|
||||
std::vector<cmSbomObject> RootElements;
|
||||
std::vector<std::string> ProfileConformance;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxPackageVerificationCode final : cmSpdxIntegrityMethod
|
||||
{
|
||||
cm::optional<HashAlgorithmId> Algorithm;
|
||||
cm::optional<std::string> HashValue;
|
||||
cm::optional<std::string> PackageVerificationCodeExcludedFile;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxHash final : cmSpdxIntegrityMethod
|
||||
{
|
||||
HashAlgorithmId HashAlgorithm;
|
||||
std::string HashValue;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxBundle : cmSpdxElementCollection
|
||||
{
|
||||
cm::optional<std::string> Context;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxBom : cmSpdxBundle
|
||||
{
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxSbom final : cmSpdxBom
|
||||
{
|
||||
enum TypeId
|
||||
{
|
||||
ANALYZED,
|
||||
BUILD,
|
||||
DEPLOYED,
|
||||
DESIGN,
|
||||
RUNTIME,
|
||||
SOURCE,
|
||||
TEST
|
||||
};
|
||||
|
||||
cm::optional<std::vector<TypeId>> Types;
|
||||
cm::optional<TypeId> LifecycleScope;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxSoftwareArtifact : cmSpdxArtifact
|
||||
{
|
||||
enum PurposeId
|
||||
{
|
||||
APPLICATION,
|
||||
ARCHIVE,
|
||||
CONTAINER,
|
||||
DATA,
|
||||
DEVICE,
|
||||
FIRMWARE,
|
||||
FILE,
|
||||
INSTALL,
|
||||
LIBRARY,
|
||||
MODULE,
|
||||
OPERATING_SYSTEM,
|
||||
SOURCE
|
||||
};
|
||||
|
||||
cm::optional<PurposeId> PrimaryPurpose;
|
||||
cm::optional<std::vector<PurposeId>> AdditionalPurpose;
|
||||
cm::optional<std::string> CopyrightText;
|
||||
cm::optional<std::string> AttributionText;
|
||||
cm::optional<cmSbomObject> ContentIdentifier;
|
||||
cm::optional<std::string> ArtifactSize;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxPackage final : cmSpdxSoftwareArtifact
|
||||
{
|
||||
cm::optional<std::string> DownloadLocation;
|
||||
cm::optional<std::string> Homepage;
|
||||
cm::optional<std::string> PackageVersion;
|
||||
cm::optional<std::string> PackageUrl;
|
||||
cm::optional<std::string> SourceInfo;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxDocument final : cmSpdxElementCollection
|
||||
{
|
||||
cm::optional<cmSbomObject> ExternalMap;
|
||||
cm::optional<cmSbomObject> NamespaceMap;
|
||||
std::string DataLicense;
|
||||
|
||||
void Serialize(cmSbomSerializer& serializer) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxContentIdentifier final : cmSpdxIntegrityMethod
|
||||
{
|
||||
cm::optional<std::string> ContentIdentifierType;
|
||||
cm::optional<std::string> ContentValue;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxFile final : cmSpdxArtifact
|
||||
{
|
||||
enum FileKindId
|
||||
{
|
||||
DIRECTORY,
|
||||
FILE
|
||||
};
|
||||
cm::optional<MediaType> ContentType;
|
||||
cm::optional<FileKindId> FileType;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSpdxSnippet final : cmSpdxSoftwareArtifact
|
||||
{
|
||||
cm::optional<std::string> ByteRange;
|
||||
cm::optional<std::string> LineRange;
|
||||
cm::optional<cmSbomObject> SnippetFromFile;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const override;
|
||||
};
|
||||
|
||||
struct cmSbomDocument
|
||||
{
|
||||
cm::optional<std::string> Context;
|
||||
std::vector<cmSbomObject> Graph;
|
||||
|
||||
void Serialize(cmSbomSerializer&) const;
|
||||
};
|
||||
119
Source/cmSpdxSerializer.cxx
Normal file
119
Source/cmSpdxSerializer.cxx
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmSpdxSerializer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <cm3p/json/writer.h>
|
||||
|
||||
#include "cmSbomObject.h"
|
||||
|
||||
cmSpdxSerializer::cmSpdxSerializer()
|
||||
{
|
||||
Json::StreamWriterBuilder builder = Json::StreamWriterBuilder();
|
||||
builder["indentation"] = " ";
|
||||
Writer.reset(builder.newStreamWriter());
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::BeginObject()
|
||||
{
|
||||
CurrentValue = Json::objectValue;
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::BeginArray()
|
||||
{
|
||||
CurrentValue = Json::arrayValue;
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::EndObject()
|
||||
{
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::EndArray()
|
||||
{
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::AddReference(std::string const& id)
|
||||
{
|
||||
CurrentValue = id;
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::AddString(std::string const& key,
|
||||
std::string const& value)
|
||||
{
|
||||
if (!value.empty()) {
|
||||
CurrentValue[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::AddVisitable(std::string const& key,
|
||||
cmSbomObject const& visitable)
|
||||
{
|
||||
if (visitable.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value parentValue = std::move(CurrentValue);
|
||||
visitable.Serialize(*this);
|
||||
Json::Value childValue = std::move(CurrentValue);
|
||||
|
||||
CurrentValue = std::move(parentValue);
|
||||
CurrentValue[key] = std::move(childValue);
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::AddVectorIfPresent(std::string const& key,
|
||||
std::vector<cmSbomObject> const& vec)
|
||||
{
|
||||
if (vec.empty()) {
|
||||
return;
|
||||
}
|
||||
Json::Value parentValue = std::move(CurrentValue);
|
||||
Json::Value childValue(Json::arrayValue);
|
||||
|
||||
for (auto const& item : vec) {
|
||||
if (item.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item.Serialize(*this);
|
||||
|
||||
if (!CurrentValue.isNull()) {
|
||||
childValue.append(std::move(CurrentValue));
|
||||
}
|
||||
}
|
||||
|
||||
CurrentValue = std::move(parentValue);
|
||||
CurrentValue[key] = std::move(childValue);
|
||||
}
|
||||
|
||||
void cmSpdxSerializer::AddVectorIfPresent(std::string const& key,
|
||||
std::vector<std::string> const& vec)
|
||||
{
|
||||
if (vec.empty()) {
|
||||
return;
|
||||
}
|
||||
Json::Value parentValue = std::move(CurrentValue);
|
||||
Json::Value childValue(Json::arrayValue);
|
||||
|
||||
for (auto const& item : vec) {
|
||||
if (item.empty()) {
|
||||
continue;
|
||||
}
|
||||
childValue.append(item);
|
||||
}
|
||||
|
||||
CurrentValue = std::move(parentValue);
|
||||
CurrentValue[key] = std::move(childValue);
|
||||
}
|
||||
|
||||
bool cmSpdxSerializer::WriteSbom(std::ostream& os,
|
||||
cmSbomObject const& document)
|
||||
{
|
||||
if (document.IsNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
document.Serialize(*this);
|
||||
Writer->write(CurrentValue, &os);
|
||||
return os.good();
|
||||
}
|
||||
52
Source/cmSpdxSerializer.h
Normal file
52
Source/cmSpdxSerializer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
#include <cm3p/json/writer.h>
|
||||
|
||||
#include "cmSbomSerializer.h"
|
||||
|
||||
class cmSbomObject;
|
||||
|
||||
struct cmSpdxSerializer final : cmSbomSerializer
|
||||
{
|
||||
cmSpdxSerializer();
|
||||
|
||||
~cmSpdxSerializer() override = default;
|
||||
|
||||
void BeginObject() override;
|
||||
|
||||
void BeginArray() override;
|
||||
|
||||
void EndObject() override;
|
||||
|
||||
void EndArray() override;
|
||||
|
||||
void AddReference(std::string const& id) override;
|
||||
|
||||
void AddString(std::string const& key, std::string const& value) override;
|
||||
|
||||
void AddVisitable(std::string const& key,
|
||||
cmSbomObject const& visitable) override;
|
||||
|
||||
void AddVectorIfPresent(std::string const& key,
|
||||
std::vector<cmSbomObject> const& vec) override;
|
||||
|
||||
void AddVectorIfPresent(std::string const& key,
|
||||
std::vector<std::string> const& vec) override;
|
||||
|
||||
bool WriteSbom(std::ostream& os, cmSbomObject const& document) override;
|
||||
|
||||
Json::Value GetJson() { return CurrentValue; }
|
||||
|
||||
private:
|
||||
Json::Value CurrentValue;
|
||||
std::string CurrentKey;
|
||||
std::unique_ptr<Json::StreamWriter> Writer;
|
||||
};
|
||||
@@ -25,7 +25,7 @@ set(CMakeLib_TESTS
|
||||
testRange.cxx
|
||||
testOptional.cxx
|
||||
testPathResolver.cxx
|
||||
testSPDXSerializer.cxx
|
||||
testSpdxSerializer.cxx
|
||||
testStdIo.cxx
|
||||
testString.cxx
|
||||
testStringAlgorithms.cxx
|
||||
|
||||
@@ -1,649 +0,0 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cm/type_traits>
|
||||
|
||||
#include <cm3p/json/reader.h>
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
#include "cmSPDXSerializer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::string const nonOptional(R"================({
|
||||
"@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
|
||||
"@graph": [
|
||||
{
|
||||
"@id": "_:contentIdentifier_0",
|
||||
"contentIdentifierType": "INVALID_CONTENT_IDENTIFIER_TYPE_ID",
|
||||
"contentIdentifierValue": "",
|
||||
"type": "ContentIdentifier"
|
||||
},
|
||||
{
|
||||
"@id": "_:creationInfo_0",
|
||||
"created": "",
|
||||
"createdBy": [],
|
||||
"type": "CreationInfo"
|
||||
},
|
||||
{
|
||||
"@id": "_:creationInfo_1",
|
||||
"created": "",
|
||||
"createdBy": [],
|
||||
"type": "CreationInfo"
|
||||
},
|
||||
{
|
||||
"@id": "_:dictionaryEntry_0",
|
||||
"key": "",
|
||||
"type": "DictionaryEntry"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalIdentifier_0",
|
||||
"externalIdentifierType": "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID",
|
||||
"identifier": "",
|
||||
"type": "ExternalIdentifier"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalMap_0",
|
||||
"externalSpdxId": "",
|
||||
"type": "ExternalMap"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalRef_0",
|
||||
"type": "ExternalRef"
|
||||
},
|
||||
{
|
||||
"@id": "_:hash_0",
|
||||
"algorithm": "INVALID_HASH_TYPE_ID",
|
||||
"hashValue": "",
|
||||
"type": "Hash"
|
||||
},
|
||||
{
|
||||
"@id": "_:namespaceMap_0",
|
||||
"namespace": "",
|
||||
"prefix": "",
|
||||
"type": "NamespaceMap"
|
||||
},
|
||||
{
|
||||
"@id": "_:packageVerificationCode_0",
|
||||
"algorithm": "INVALID_HASH_TYPE_ID",
|
||||
"hashValue": "",
|
||||
"type": "PackageVerificationCode"
|
||||
},
|
||||
{
|
||||
"@id": "_:positiveIntegerRange_0",
|
||||
"beginIntegerRange": 0,
|
||||
"endIntegerRange": 0,
|
||||
"type": "PositiveIntegerRange"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
|
||||
"type": "Agent"
|
||||
},
|
||||
{
|
||||
"annotationType": "INVALID_ANNOTATION_TYPE_ID",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
|
||||
"subject": "",
|
||||
"type": "Annotation"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
|
||||
"type": "SpdxDocument"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
|
||||
"type": "Tool"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
|
||||
"type": "File"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
|
||||
"type": "Package"
|
||||
},
|
||||
{
|
||||
"context": "",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
|
||||
"type": "Sbom"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"snippetFromFile": "",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
|
||||
"type": "Snippet"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"licenseExpression": "",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
|
||||
"type": "LicenseExpression"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"licenseText": "",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
|
||||
"type": "SimpleLicensingText"
|
||||
},
|
||||
{
|
||||
"context": "",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
|
||||
"type": "Bom"
|
||||
},
|
||||
{
|
||||
"context": "",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
|
||||
"type": "Bundle"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
|
||||
"type": "IndividualElement"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"from": "",
|
||||
"relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
|
||||
"to": [],
|
||||
"type": "LifecycleScopedRelationship"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
|
||||
"type": "Organization"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
|
||||
"type": "Person"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"from": "",
|
||||
"relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
|
||||
"to": [],
|
||||
"type": "Relationship"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
|
||||
"type": "SoftwareAgent"
|
||||
}
|
||||
]
|
||||
})================");
|
||||
|
||||
std::string const Optional(R"================({
|
||||
"@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
|
||||
"@graph": [
|
||||
{
|
||||
"@id": "_:contentIdentifier_0",
|
||||
"contentIdentifierType": "gitoid",
|
||||
"contentIdentifierValue": "ContentIdentifierValue",
|
||||
"type": "ContentIdentifier"
|
||||
},
|
||||
{
|
||||
"@id": "_:creationInfo_0",
|
||||
"created": "",
|
||||
"createdBy": [],
|
||||
"type": "CreationInfo"
|
||||
},
|
||||
{
|
||||
"@id": "_:creationInfo_1",
|
||||
"Comment": "Comment",
|
||||
"created": "Created",
|
||||
"createdBy": [
|
||||
"testRef"
|
||||
],
|
||||
"createdUsing": [
|
||||
"testRef"
|
||||
],
|
||||
"type": "CreationInfo"
|
||||
},
|
||||
{
|
||||
"@id": "_:dictionaryEntry_0",
|
||||
"key": "Key",
|
||||
"type": "DictionaryEntry",
|
||||
"value": "Value"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalIdentifier_0",
|
||||
"comment": "Comment",
|
||||
"externalIdentifierType": "other",
|
||||
"identifier": "Identifier",
|
||||
"identifierLocator": [
|
||||
"IdentifierLocator"
|
||||
],
|
||||
"issuingAuthority": "IssuingAuthority",
|
||||
"type": "ExternalIdentifier"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalMap_0",
|
||||
"definingArtifact": "testRef",
|
||||
"externalSpdxId": "ExternalSpdxId",
|
||||
"integrityMethod": [
|
||||
"testRef"
|
||||
],
|
||||
"locationHint": "LocationHint",
|
||||
"type": "ExternalMap"
|
||||
},
|
||||
{
|
||||
"@id": "_:externalRef_0",
|
||||
"comment": "Comment",
|
||||
"contentType": "ContentType",
|
||||
"externalRefType": "other",
|
||||
"locator": [
|
||||
"Locator"
|
||||
],
|
||||
"type": "ExternalRef"
|
||||
},
|
||||
{
|
||||
"@id": "_:hash_0",
|
||||
"algorithm": "other",
|
||||
"hashValue": "HashValue",
|
||||
"type": "Hash"
|
||||
},
|
||||
{
|
||||
"@id": "_:namespaceMap_0",
|
||||
"namespace": "Namespace",
|
||||
"prefix": "Namespace",
|
||||
"type": "NamespaceMap"
|
||||
},
|
||||
{
|
||||
"@id": "_:packageVerificationCode_0",
|
||||
"algorithm": "other",
|
||||
"hashValue": "HashValue",
|
||||
"type": "PackageVerificationCode"
|
||||
},
|
||||
{
|
||||
"@id": "_:positiveIntegerRange_0",
|
||||
"beginIntegerRange": 1,
|
||||
"endIntegerRange": 2,
|
||||
"type": "PositiveIntegerRange"
|
||||
},
|
||||
{
|
||||
"comment": "Comment",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"description": "Description",
|
||||
"extension": [
|
||||
"testRef"
|
||||
],
|
||||
"externalIdentifier": [
|
||||
"testRef"
|
||||
],
|
||||
"externalRef": [
|
||||
"testRef"
|
||||
],
|
||||
"name": "Name",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
|
||||
"summary": "Summary",
|
||||
"type": "Agent",
|
||||
"verifiedUsing": [
|
||||
"testRef"
|
||||
]
|
||||
},
|
||||
{
|
||||
"annotationType": "other",
|
||||
"contentType": "ContentType",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
|
||||
"statement": "Statement",
|
||||
"subject": "testRef",
|
||||
"type": "Annotation"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"dataLicense": "testRef",
|
||||
"externalMap": "testRef",
|
||||
"namespaceMap": "testRef",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
|
||||
"type": "SpdxDocument"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
|
||||
"type": "Tool"
|
||||
},
|
||||
{
|
||||
"additionalPurpose": [
|
||||
"other"
|
||||
],
|
||||
"attributionText": "AttributionText",
|
||||
"contentIdentifier": "testRef",
|
||||
"contentType": "ContentType",
|
||||
"copyrightText": "CopyrightText",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"fileKind": "file",
|
||||
"primaryPurpose": "file",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
|
||||
"type": "File"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"downloadLocation": "DownloadLocation",
|
||||
"homePage": "HomePage",
|
||||
"packageUrl": "PackageUrl",
|
||||
"packageVersion": "PackageVersion",
|
||||
"sourceInfo": "SourceInfo",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
|
||||
"type": "Package"
|
||||
},
|
||||
{
|
||||
"context": "",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"sbomType": [
|
||||
"build"
|
||||
],
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
|
||||
"type": "Sbom"
|
||||
},
|
||||
{
|
||||
"byteRange": "testRef",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"lineRange": "testRef",
|
||||
"snippetFromFile": "testRef",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
|
||||
"type": "Snippet"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"customIdToUri": [
|
||||
"testRef"
|
||||
],
|
||||
"licenseExpression": "LicenseExpression",
|
||||
"licenseListVersion": "LicenseListVersion",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
|
||||
"type": "LicenseExpression"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"licenseText": "LicenseText",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
|
||||
"type": "SimpleLicensingText"
|
||||
},
|
||||
{
|
||||
"context": "Context",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
|
||||
"type": "Bom"
|
||||
},
|
||||
{
|
||||
"context": "",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
|
||||
"type": "Bundle"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
|
||||
"type": "IndividualElement"
|
||||
},
|
||||
{
|
||||
"completeness": "noAssertion",
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"endTime": "EndTime",
|
||||
"from": "testRef",
|
||||
"relationshipType": "other",
|
||||
"scope": "other",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
|
||||
"startTime": "StartTime",
|
||||
"to": [
|
||||
"testRef"
|
||||
],
|
||||
"type": "LifecycleScopedRelationship"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
|
||||
"type": "Organization"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
|
||||
"type": "Person"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"from": "",
|
||||
"relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
|
||||
"to": [],
|
||||
"type": "Relationship"
|
||||
},
|
||||
{
|
||||
"creationInfo": "_:creationInfo_0",
|
||||
"spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
|
||||
"type": "SoftwareAgent"
|
||||
}
|
||||
]
|
||||
})================");
|
||||
}
|
||||
|
||||
int testNonOptional()
|
||||
{
|
||||
cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
|
||||
|
||||
// Core
|
||||
graph.insert<cmSPDXAgent>();
|
||||
graph.insert<cmSPDXAnnotation>();
|
||||
graph.insert<cmSPDXBom>();
|
||||
graph.insert<cmSPDXBundle>();
|
||||
graph.insert<cmSPDXCreationInfo>();
|
||||
graph.insert<cmSPDXDictionaryEntry>();
|
||||
graph.insert<cmSPDXExternalIdentifier>();
|
||||
graph.insert<cmSPDXExternalMap>();
|
||||
graph.insert<cmSPDXExternalRef>();
|
||||
graph.insert<cmSPDXHash>();
|
||||
graph.insert<cmSPDXIndividualElement>();
|
||||
graph.insert<cmSPDXLifecycleScopedRelationship>();
|
||||
graph.insert<cmSPDXNamespaceMap>();
|
||||
graph.insert<cmSPDXOrganization>();
|
||||
graph.insert<cmSPDXPackageVerificationCode>();
|
||||
graph.insert<cmSPDXPerson>();
|
||||
graph.insert<cmSPDXPositiveIntegerRange>();
|
||||
graph.insert<cmSPDXRelationship>();
|
||||
graph.insert<cmSPDXSoftwareAgent>();
|
||||
graph.insert<cmSPDXSpdxDocument>();
|
||||
graph.insert<cmSPDXTool>();
|
||||
|
||||
// Software
|
||||
graph.insert<cmSPDXContentIdentifier>();
|
||||
graph.insert<cmSPDXFile>();
|
||||
graph.insert<cmSPDXPackage>();
|
||||
graph.insert<cmSPDXSbom>();
|
||||
graph.insert<cmSPDXSnippet>();
|
||||
|
||||
// SimpleLicensing
|
||||
graph.insert<cmSPDXLicenseExpression>();
|
||||
graph.insert<cmSPDXSimpleLicensingText>();
|
||||
|
||||
Json::Value root;
|
||||
Json::Reader().parse(nonOptional.c_str(), root);
|
||||
|
||||
std::cout << "NonOptional SPDX:";
|
||||
std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
|
||||
std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
|
||||
|
||||
// Convert to string to disregard differences in number signedness
|
||||
return root.toStyledString() == graph.toJsonLD().toStyledString();
|
||||
};
|
||||
|
||||
int testOptional()
|
||||
{
|
||||
cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
|
||||
|
||||
cmSPDXIdentifierReference ident("testRef");
|
||||
|
||||
// Core
|
||||
auto& agent = graph.insert<cmSPDXAgent>();
|
||||
agent.Comment = "Comment";
|
||||
agent.Description = "Description";
|
||||
agent.Extension.emplace().push_back(ident);
|
||||
agent.ExternalIdentifier.emplace().push_back(ident);
|
||||
agent.ExternalRef.emplace().push_back(ident);
|
||||
agent.Name = "Name";
|
||||
agent.Summary = "Summary";
|
||||
agent.VerifiedUsing.emplace().push_back(ident);
|
||||
|
||||
auto& annotation = graph.insert<cmSPDXAnnotation>();
|
||||
annotation.AnnotationType = cmSPDXAnnotationType::OTHER;
|
||||
annotation.ContentType = "ContentType";
|
||||
annotation.Statement = "Statement";
|
||||
annotation.Subject = ident;
|
||||
|
||||
auto& bom = graph.insert<cmSPDXBom>();
|
||||
bom.Context = "Context";
|
||||
|
||||
graph.insert<cmSPDXBundle>();
|
||||
|
||||
auto& creationInfo = graph.insert<cmSPDXCreationInfo>();
|
||||
creationInfo.Comment = "Comment";
|
||||
creationInfo.Created = "Created";
|
||||
creationInfo.CreatedBy.push_back(ident);
|
||||
creationInfo.CreatedUsing.emplace().push_back(ident);
|
||||
|
||||
auto& dictionaryEntry = graph.insert<cmSPDXDictionaryEntry>();
|
||||
dictionaryEntry.Key = "Key";
|
||||
dictionaryEntry.Value = "Value";
|
||||
|
||||
auto& externalIdentifier = graph.insert<cmSPDXExternalIdentifier>();
|
||||
externalIdentifier.Comment = "Comment";
|
||||
externalIdentifier.ExternalIdentifierType =
|
||||
cmSPDXExternalIdentifierType::OTHER;
|
||||
externalIdentifier.Identifier = "Identifier";
|
||||
externalIdentifier.IdentifierLocator.emplace().push_back(
|
||||
"IdentifierLocator");
|
||||
externalIdentifier.IssuingAuthority = "IssuingAuthority";
|
||||
|
||||
auto& externalMap = graph.insert<cmSPDXExternalMap>();
|
||||
externalMap.DefiningArtifact = ident;
|
||||
externalMap.ExternalSpdxId = "ExternalSpdxId";
|
||||
externalMap.LocationHint = "LocationHint";
|
||||
externalMap.IntegrityMethod.emplace().push_back(ident);
|
||||
|
||||
auto& externalRef = graph.insert<cmSPDXExternalRef>();
|
||||
externalRef.Comment = "Comment";
|
||||
externalRef.ContentType = "ContentType";
|
||||
externalRef.ExternalRefType = cmSPDXExternalRefType::OTHER;
|
||||
externalRef.Locator.emplace().push_back("Locator");
|
||||
|
||||
auto& hash = graph.insert<cmSPDXHash>();
|
||||
hash.Algorithm = cmSPDXHashAlgorithm::OTHER;
|
||||
hash.HashValue = "HashValue";
|
||||
|
||||
graph.insert<cmSPDXIndividualElement>();
|
||||
|
||||
auto& lifecycleScopedRelationship =
|
||||
graph.insert<cmSPDXLifecycleScopedRelationship>();
|
||||
lifecycleScopedRelationship.Completeness =
|
||||
cmSPDXRelationshipCompletenessType::NO_ASSERTION;
|
||||
lifecycleScopedRelationship.EndTime = "EndTime";
|
||||
lifecycleScopedRelationship.From = ident;
|
||||
lifecycleScopedRelationship.RelationshipType = cmSPDXRelationshipType::OTHER;
|
||||
lifecycleScopedRelationship.StartTime = "StartTime";
|
||||
lifecycleScopedRelationship.To.push_back(ident);
|
||||
lifecycleScopedRelationship.Scope = cmSPDXLifecycleScopeType::OTHER;
|
||||
|
||||
auto& namespaceMap = graph.insert<cmSPDXNamespaceMap>();
|
||||
namespaceMap.Namespace = "Namespace";
|
||||
namespaceMap.Prefix = "Prefix";
|
||||
|
||||
graph.insert<cmSPDXOrganization>();
|
||||
|
||||
auto& packageVerificationCode =
|
||||
graph.insert<cmSPDXPackageVerificationCode>();
|
||||
packageVerificationCode.Algorithm = cmSPDXHashAlgorithm::OTHER;
|
||||
packageVerificationCode.HashValue = "HashValue";
|
||||
packageVerificationCode.PackageVerificationCodeExcludedFile.emplace()
|
||||
.push_back("PacakgeVerificationCodeExcludeFile");
|
||||
|
||||
graph.insert<cmSPDXPerson>();
|
||||
|
||||
auto& positiveIntegerRange = graph.insert<cmSPDXPositiveIntegerRange>();
|
||||
positiveIntegerRange.BeginIntegerRange = 1;
|
||||
positiveIntegerRange.EndIntegerRange = 2;
|
||||
|
||||
graph.insert<cmSPDXRelationship>();
|
||||
|
||||
graph.insert<cmSPDXSoftwareAgent>();
|
||||
|
||||
auto& spdxDocument = graph.insert<cmSPDXSpdxDocument>();
|
||||
spdxDocument.DataLicense = ident;
|
||||
spdxDocument.ExternalMap = ident;
|
||||
spdxDocument.NamespaceMap = ident;
|
||||
|
||||
graph.insert<cmSPDXTool>();
|
||||
|
||||
// Software
|
||||
auto& contentIdentifier = graph.insert<cmSPDXContentIdentifier>();
|
||||
contentIdentifier.ContentIdentifierType =
|
||||
cmSPDXContentIdentifierType::GITOID;
|
||||
contentIdentifier.ContentIdentifierValue = "ContentIdentifierValue";
|
||||
|
||||
auto& file = graph.insert<cmSPDXFile>();
|
||||
file.AdditionalPurpose.emplace().push_back(cmSPDXSoftwarePurpose::OTHER);
|
||||
file.AttributionText = "AttributionText";
|
||||
file.ContentIdentifier = ident;
|
||||
file.CopyrightText = "CopyrightText";
|
||||
file.PrimaryPurpose = cmSPDXSoftwarePurpose::FILE;
|
||||
file.ContentType = "ContentType";
|
||||
file.FileKind = cmSPDXFileKindType::FILE;
|
||||
|
||||
auto& package = graph.insert<cmSPDXPackage>();
|
||||
package.DownloadLocation = "DownloadLocation";
|
||||
package.HomePage = "HomePage";
|
||||
package.PackageUrl = "PackageUrl";
|
||||
package.PackageVersion = "PackageVersion";
|
||||
package.SourceInfo = "SourceInfo";
|
||||
|
||||
auto& sbom = graph.insert<cmSPDXSbom>();
|
||||
sbom.SbomType.emplace().push_back(cmSPDXSbomType::BUILD);
|
||||
|
||||
auto& snippet = graph.insert<cmSPDXSnippet>();
|
||||
snippet.ByteRange = ident;
|
||||
snippet.LineRange = ident;
|
||||
snippet.SnippetFromFile = ident;
|
||||
|
||||
// SimpleLicensing
|
||||
auto& licenseExpression = graph.insert<cmSPDXLicenseExpression>();
|
||||
licenseExpression.CustomIdToUri.emplace().push_back(ident);
|
||||
licenseExpression.LicenseExpression = "LicenseExpression";
|
||||
licenseExpression.LicenseListVersion = "LicenseListVersion";
|
||||
|
||||
auto& simpleLicensingText = graph.insert<cmSPDXSimpleLicensingText>();
|
||||
simpleLicensingText.LicenseText = "LicenseText";
|
||||
|
||||
Json::Value root;
|
||||
Json::Reader().parse(Optional.c_str(), root);
|
||||
|
||||
std::cout << "Optional SPDX:";
|
||||
std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
|
||||
std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
|
||||
|
||||
// Convert to string to disregard differences in number signedness
|
||||
return root.toStyledString() == graph.toJsonLD().toStyledString();
|
||||
};
|
||||
|
||||
int testSPDXSerializer(int /* argc */, char* /* argv */[])
|
||||
{
|
||||
if (!testNonOptional())
|
||||
return -1;
|
||||
|
||||
if (!testOptional())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
84
Tests/CMakeLib/testSpdxSerializer.cxx
Normal file
84
Tests/CMakeLib/testSpdxSerializer.cxx
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
#include "cmSbomObject.h"
|
||||
#include "cmSpdx.h"
|
||||
#include "cmSpdxSerializer.h"
|
||||
|
||||
#include "testCommon.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool testSerializeSpdxJson()
|
||||
{
|
||||
|
||||
auto constexpr contextUrl = "https://spdx.org/rdf/3.0.1/spdx-context.jsonld";
|
||||
|
||||
cmSbomDocument doc;
|
||||
doc.Context = contextUrl;
|
||||
|
||||
cmSpdxDocument spdxValue;
|
||||
spdxValue.SpdxId = "_:SPDXRef-Document";
|
||||
spdxValue.DataLicense = "CC0-1.0";
|
||||
auto spdx = insert_back(doc.Graph, std::move(spdxValue));
|
||||
|
||||
{
|
||||
cmSpdxCreationInfo ci;
|
||||
ci.SpdxId = "_:SPDXRef-CreationInfo";
|
||||
ci.SpecVersion = "3.0.1";
|
||||
spdx->CreationInfo = std::move(ci);
|
||||
}
|
||||
|
||||
{
|
||||
cmSpdxPackage pkg;
|
||||
pkg.Name = "sample-package";
|
||||
pkg.SpdxId = "_:SPDXRef-Package";
|
||||
|
||||
spdx->RootElements.emplace_back(std::move(pkg));
|
||||
}
|
||||
|
||||
{
|
||||
cmSpdxSerializer serializer;
|
||||
doc.Serialize(serializer);
|
||||
auto value = serializer.GetJson();
|
||||
|
||||
ASSERT_TRUE(value.isObject());
|
||||
|
||||
Json::Value const& context = value["@context"];
|
||||
ASSERT_EQUAL(context.asString(), contextUrl);
|
||||
|
||||
Json::Value const& graph = value["@graph"];
|
||||
ASSERT_TRUE(graph.isArray());
|
||||
|
||||
Json::Value const& docValue = graph[0];
|
||||
ASSERT_TRUE(docValue.isObject());
|
||||
ASSERT_EQUAL(docValue["type"].asString(), "SpdxDocument");
|
||||
ASSERT_EQUAL(docValue["@id"].asString(), "_:SPDXRef-Document");
|
||||
|
||||
auto const& creationInfo = docValue["creationInfo"];
|
||||
ASSERT_EQUAL(creationInfo["@id"].asString(), "_:SPDXRef-CreationInfo");
|
||||
ASSERT_EQUAL(creationInfo["type"].asString(), "CreationInfo");
|
||||
|
||||
auto const& package = docValue["rootElement"][0];
|
||||
ASSERT_EQUAL(package["type"].asString(), "software_Package");
|
||||
ASSERT_EQUAL(package["@id"].asString(), "_:SPDXRef-Package");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int testSpdxSerializer(int /*unused*/, char* /*unused*/[])
|
||||
{
|
||||
return runTests({ testSerializeSpdxJson });
|
||||
}
|
||||
Reference in New Issue
Block a user