From e20f63a8de58bf8d91cb28cf59c90bdc012beb65 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Sat, 2 Mar 2024 15:33:23 +0100 Subject: [PATCH] introduce QA pipeline for protobuf schemas (#385) current protobuf schema files are not perfect. this PR aims to prevent mistakes in the future, while acknowledging issues from the past. fixes #384 ---- ## status - [x] introduce protobuf QA tools and configure them to our needs - [x] baseline existing protobuf QA violations - as acknowledgement - [x] introduce the protobuf QA tools in automated pipeline - [x] introduce tools that detect and prevent breaking changes (BCD) in protobuf - [x] introduce the protobuf BCD tools in automated pipeline - [x] have our own protobuf test files checked against the schemas ## followup - [ ] add the appropriate header to `*.textproto` see https://github.com/CycloneDX/specification/issues/384#issuecomment-1959512503 - [ ] create ticket for BC: fix the proto3 schema enum value `0` -- they are intended to be fallbacks, not actual values. --------- Signed-off-by: Jan Kowalleck --- .github/dependabot.yml | 13 +- .github/workflows/test_proto.yml | 28 ++ schema/bom-1.6.proto | 270 +++++++++++------- tools/src/test/proto-test.sh | 6 - tools/src/test/proto/buf_breaking-remote.yaml | 7 + .../src/test/proto/buf_breaking-version.yaml | 10 + tools/src/test/proto/buf_lint.yaml | 22 ++ tools/src/test/proto/test.sh | 165 +++++++++++ .../1.4/valid-release-notes-1.4.textproto | 2 +- .../1.5/valid-release-notes-1.5.textproto | 2 +- .../1.6/valid-release-notes-1.6.textproto | 2 +- 11 files changed, 414 insertions(+), 113 deletions(-) create mode 100644 .github/workflows/test_proto.yml delete mode 100755 tools/src/test/proto-test.sh create mode 100644 tools/src/test/proto/buf_breaking-remote.yaml create mode 100644 tools/src/test/proto/buf_breaking-version.yaml create mode 100644 tools/src/test/proto/buf_lint.yaml create mode 100755 tools/src/test/proto/test.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d56bb1e7..5baaf962 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,4 @@ -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: 'github-actions' @@ -12,3 +11,13 @@ updates: prefix: 'chore' ## prefix maximum string length of 15 include: 'scope' open-pull-requests-limit: 999 + - package-ecosystem: 'docker' + directory: '/' + schedule: + interval: 'weekly' + day: 'saturday' + labels: [ 'dependencies' ] + commit-message: + prefix: 'chore' ## prefix maximum string length of 15 + include: 'scope' + open-pull-requests-limit: 999 diff --git a/.github/workflows/test_proto.yml b/.github/workflows/test_proto.yml new file mode 100644 index 00000000..0dfe8cae --- /dev/null +++ b/.github/workflows/test_proto.yml @@ -0,0 +1,28 @@ +# docs: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions + +name: CT ProtoBuf + +on: + push: + branches: ['master', 'main'] + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + working-directory: tools/src/test/proto + +jobs: + test: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - name: Checkout + # see https://github.com/actions/checkout + uses: actions/checkout@v4 + - name: Run test + run: ./test.sh diff --git a/schema/bom-1.6.proto b/schema/bom-1.6.proto index 88c3347a..b432f03d 100644 --- a/schema/bom-1.6.proto +++ b/schema/bom-1.6.proto @@ -46,6 +46,7 @@ message Bom { } enum Classification { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` CLASSIFICATION_NULL = 0; // A software application. Refer to https://en.wikipedia.org/wiki/Application_software for information about applications. CLASSIFICATION_APPLICATION = 1; @@ -168,7 +169,9 @@ message DataFlow { } // Specifies the flow direction of the data. Valid values are: inbound, outbound, bi-directional, and unknown. Direction is relative to the service. Inbound flow states that data enters the service. Outbound flow states that data leaves the service. Bi-directional states that data flows both ways, and unknown states that the direction is not known. +// buf:lint:ignore ENUM_VALUE_PREFIX -- Enum value names should be prefixed with "DATA_FLOW_DIRECTION_" enum DataFlowDirection { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` DATA_FLOW_NULL = 0; DATA_FLOW_INBOUND = 1; DATA_FLOW_OUTBOUND = 2; @@ -205,6 +208,7 @@ message ExternalReference { enum ExternalReferenceType { // Use this if no other types accurately describe the purpose of the external reference + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `other` is our fallback, doubling `unspecified` EXTERNAL_REFERENCE_TYPE_OTHER = 0; // Version Control System EXTERNAL_REFERENCE_TYPE_VCS = 1; @@ -291,6 +295,7 @@ enum ExternalReferenceType { } enum HashAlg { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` HASH_ALG_NULL = 0; HASH_ALG_MD_5 = 1; HASH_ALG_SHA_1 = 2; @@ -324,6 +329,7 @@ message IdentifiableAction { } enum IssueClassification { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` ISSUE_CLASSIFICATION_NULL = 0; // A fault, flaw, or bug in software ISSUE_CLASSIFICATION_DEFECT = 1; @@ -407,7 +413,9 @@ message OrganizationalEntityOrContact { } } +// buf:lint:ignore ENUM_VALUE_PREFIX -- Enum value names should be prefixed with "LICENSING_TYPE_ENUM_" enum LicensingTypeEnum { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` LICENSING_TYPE_NULL = 0; // A license that grants use of software solely for the purpose of education or research. LICENSING_TYPE_ACADEMIC = 1; @@ -479,6 +487,7 @@ message Lifecycles { enum LifecyclePhase { // BOM produced early in the development lifecycle containing inventory of components and services that are proposed or planned to be used. The inventory may need to be procured, retrieved, or resourced prior to use. + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema LIFECYCLE_PHASE_DESIGN = 0; // BOM consisting of information obtained prior to a build process and may contain source files and development artifacts and manifests. The inventory may need to be resolved and retrieved prior to use. LIFECYCLE_PHASE_PRE_BUILD = 1; @@ -517,6 +526,7 @@ message OrganizationalEntity { } enum PatchClassification { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` PATCH_CLASSIFICATION_NULL = 0; // A patch which is not developed by the creators or maintainers of the software being patched. Refer to https://en.wikipedia.org/wiki/Unofficial_patch PATCH_CLASSIFICATION_UNOFFICIAL = 1; @@ -640,6 +650,7 @@ message Property { enum Aggregate { // The relationship completeness is not specified. + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `not specified` is our fallback, doubling `unspecified` AGGREGATE_NOT_SPECIFIED = 0; // The relationship is complete. No further relationships including constituent components, services, or dependencies are known to exist. AGGREGATE_COMPLETE = 1; @@ -744,7 +755,9 @@ message EvidenceOccurrences { optional string additionalContext = 6; } +// buf:lint:ignore ENUM_VALUE_PREFIX -- Enum value names should be prefixed with "EVIDENCE_FIELD_TYPE_" enum EvidenceFieldType { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` EVIDENCE_FIELD_NULL = 0; EVIDENCE_FIELD_GROUP = 1; EVIDENCE_FIELD_NAME = 2; @@ -756,6 +769,7 @@ enum EvidenceFieldType { } enum EvidenceTechnique { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema EVIDENCE_TECHNIQUE_SOURCE_CODE_ANALYSIS = 0; EVIDENCE_TECHNIQUE_BINARY_ANALYSIS = 1; EVIDENCE_TECHNIQUE_MANIFEST_ANALYSIS = 2; @@ -877,6 +891,7 @@ message VulnerabilityRating { } enum Severity { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `unknown` is our fallback, doubling `unspecified` SEVERITY_UNKNOWN = 0; SEVERITY_CRITICAL = 1; SEVERITY_HIGH = 2; @@ -888,6 +903,7 @@ enum Severity { enum ScoreMethod { // An undefined score method + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` SCORE_METHOD_NULL = 0; // Common Vulnerability Scoring System v2 - https://www.first.org/cvss/v2/ SCORE_METHOD_CVSSV2 = 1; @@ -936,6 +952,7 @@ message VulnerabilityAnalysis { enum ImpactAnalysisState { // An undefined impact analysis state + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` IMPACT_ANALYSIS_STATE_NULL = 0; // The vulnerability has been remediated. IMPACT_ANALYSIS_STATE_RESOLVED = 1; @@ -953,6 +970,7 @@ enum ImpactAnalysisState { enum ImpactAnalysisJustification { // An undefined impact analysis justification + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` IMPACT_ANALYSIS_JUSTIFICATION_NULL = 0; // The code has been removed or tree-shaked. IMPACT_ANALYSIS_JUSTIFICATION_CODE_NOT_PRESENT = 1; @@ -975,6 +993,8 @@ enum ImpactAnalysisJustification { } enum VulnerabilityResponse { + // unspecified value + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `null` is our fallback, doubling `unspecified` VULNERABILITY_RESPONSE_NULL = 0; VULNERABILITY_RESPONSE_CAN_NOT_FIX = 1; VULNERABILITY_RESPONSE_WILL_NOT_FIX = 2; @@ -1001,8 +1021,10 @@ message VulnerabilityAffectedVersions { optional VulnerabilityAffectedStatus status = 3; } +// The vulnerability status of a given version or range of versions of a product. The statuses 'affected' and 'unaffected' indicate that the version is affected or unaffected by the vulnerability. The status 'unknown' indicates that it is unknown or unspecified whether the given version is affected. There can be many reasons for an 'unknown' status, including that an investigation has not been undertaken or that a vendor has not disclosed the status. enum VulnerabilityAffectedStatus { - // The vulnerability status of a given version or range of versions of a product. The statuses 'affected' and 'unaffected' indicate that the version is affected or unaffected by the vulnerability. The status 'unknown' indicates that it is unknown or unspecified whether the given version is affected. There can be many reasons for an 'unknown' status, including that an investigation has not been undertaken or that a vendor has not disclosed the status. + // It is unknown (or unspecified) whether the given version is affected. + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- `unknown` is our fallback, doubling `unspecified` VULNERABILITY_AFFECTED_STATUS_UNKNOWN = 0; VULNERABILITY_AFFECTED_STATUS_AFFECTED = 1; VULNERABILITY_AFFECTED_STATUS_NOT_AFFECTED = 2; @@ -1132,6 +1154,7 @@ message ModelCard { } enum ModelParameterApproachType { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema MODEL_PARAMETER_APPROACH_TYPE_SUPERVISED = 0; MODEL_PARAMETER_APPROACH_TYPE_UNSUPERVISED = 1; MODEL_PARAMETER_APPROACH_TYPE_REINFORCED_LEARNING = 2; @@ -1187,6 +1210,7 @@ message DataGovernance { enum ComponentDataType { // Any type of code, code snippet, or data-as-code + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema COMPONENT_DATA_TYPE_SOURCE_CODE = 0; // Parameters or settings that may be used by other components. COMPONENT_DATA_TYPE_CONFIGURATION = 1; @@ -1345,6 +1369,7 @@ message Workspace { optional Volume volume = 12; enum AccessMode { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema ACCESS_MODE_READ_ONLY = 0; ACCESS_MODE_READ_WRITE = 1; ACCESS_MODE_READ_WRITE_ONCE = 2; @@ -1373,6 +1398,7 @@ message Volume { repeated Property properties = 8; enum VolumeMode { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema VOLUME_MODE_FILESYSTEM = 0; VOLUME_MODE_BLOCK = 1; } @@ -1406,6 +1432,7 @@ message Trigger { repeated OutputType outputs = 12; enum TriggerType { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema TRIGGER_TYPE_MANUAL = 0; TRIGGER_TYPE_API = 1; TRIGGER_TYPE_WEBHOOK = 2; @@ -1465,7 +1492,9 @@ message OutputType { // Additional properties of the output data. repeated Property properties = 7; + // buf:lint:ignore ENUM_VALUE_PREFIX -- Enum value names should be prefixed with "OUTPUT_TYPE_TYPE_" enum OutputTypeType { + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema OUTPUT_TYPE_ARTIFACT = 0; OUTPUT_TYPE_ATTESTATION = 1; OUTPUT_TYPE_LOG = 2; @@ -1494,6 +1523,7 @@ message Condition { enum TaskType { // A task that copies software or data used to accomplish other tasks in the workflow. + // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX -- value `0` is a fallback(meaning "unspecified") in protobuf3. this usage here is an error, it shall be fixed with v2.0 of this very schema TASK_TYPE_COPY = 0; // A task that clones a software repository into the workflow in order to retrieve its source code or data for use in a build step. TASK_TYPE_CLONE = 1; @@ -1727,87 +1757,113 @@ message Definition { message CryptoProperties { enum CryptoAssetType { - CRYPTO_ASSET_TYPE_ALGORITHM = 0; - CRYPTO_ASSET_TYPE_CERTIFICATE = 1; - CRYPTO_ASSET_TYPE_PROTOCOL = 2; - CRYPTO_ASSET_TYPE_RELATED_CRYPTO_MATERIAL = 3; + // ProtoBuff's default value + CRYPTO_ASSET_TYPE_UNSPECIFIED = 0; + CRYPTO_ASSET_TYPE_ALGORITHM = 1; + CRYPTO_ASSET_TYPE_CERTIFICATE = 2; + CRYPTO_ASSET_TYPE_PROTOCOL = 3; + CRYPTO_ASSET_TYPE_RELATED_CRYPTO_MATERIAL = 4; } message AlgorithmProperties { enum CryptoPrimitive { - CRYPTO_PRIMITIVE_DRBG = 0; - CRYPTO_PRIMITIVE_MAC = 1; - CRYPTO_PRIMITIVE_BLOCK_CIPHER = 2; - CRYPTO_PRIMITIVE_STREAM_CIPHER = 3; - CRYPTO_PRIMITIVE_SIGNATURE = 4; - CRYPTO_PRIMITIVE_HASH = 5; - CRYPTO_PRIMITIVE_PKE = 6; - CRYPTO_PRIMITIVE_XOF = 7; - CRYPTO_PRIMITIVE_KDF = 8; - CRYPTO_PRIMITIVE_KEY_AGREE = 9; - CRYPTO_PRIMITIVE_KEM = 10; - CRYPTO_PRIMITIVE_AE = 11; - CRYPTO_PRIMITIVE_COMBINER = 12; - CRYPTO_PRIMITIVE_OTHER = 13; - CRYPTO_PRIMITIVE_UNKNOWN = 14; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_PRIMITIVE_UNSPECIFIED = 0; + // The primitive is not known + CRYPTO_PRIMITIVE_UNKNOWN = 1; + // Another primitive type - none of the following + CRYPTO_PRIMITIVE_OTHER = 2; + CRYPTO_PRIMITIVE_DRBG = 3; + CRYPTO_PRIMITIVE_MAC = 4; + CRYPTO_PRIMITIVE_BLOCK_CIPHER = 5; + CRYPTO_PRIMITIVE_STREAM_CIPHER = 6; + CRYPTO_PRIMITIVE_SIGNATURE = 7; + CRYPTO_PRIMITIVE_HASH = 8; + CRYPTO_PRIMITIVE_PKE = 9; + CRYPTO_PRIMITIVE_XOF = 10; + CRYPTO_PRIMITIVE_KDF = 11; + CRYPTO_PRIMITIVE_KEY_AGREE = 12; + CRYPTO_PRIMITIVE_KEM = 13; + CRYPTO_PRIMITIVE_AE = 14; + CRYPTO_PRIMITIVE_COMBINER = 15; } enum CryptoExecutionEnvironment { - CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_PLAIN_RAM = 0; - CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_ENCRYPTED_RAM = 1; - CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_TEE = 2; - CRYPTO_EXECUTION_ENVIRONMENT_HARDWARE = 3; - CRYPTO_EXECUTION_ENVIRONMENT_OTHER = 4; - CRYPTO_EXECUTION_ENVIRONMENT_UNKNOWN = 5; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_EXECUTION_ENVIRONMENT_UNSPECIFIED = 0; + // The execution environment is not known + CRYPTO_EXECUTION_ENVIRONMENT_UNKNOWN = 1; + // Another implementation environment - none of the following + CRYPTO_EXECUTION_ENVIRONMENT_OTHER = 2; + CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_PLAIN_RAM = 3; + CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_ENCRYPTED_RAM = 4; + CRYPTO_EXECUTION_ENVIRONMENT_SOFTWARE_TEE = 5; + CRYPTO_EXECUTION_ENVIRONMENT_HARDWARE = 6; } enum CryptoImplementationPlatform { - CRYPTO_IMPLEMENTATION_PLATFORM_GENERIC = 0; - CRYPTO_IMPLEMENTATION_PLATFORM_X86_32 = 1; - CRYPTO_IMPLEMENTATION_PLATFORM_X86_64 = 2; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV7A = 3; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV7M = 4; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV8A = 5; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV8M = 6; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV9A = 7; - CRYPTO_IMPLEMENTATION_PLATFORM_ARMV9M = 8; - CRYPTO_IMPLEMENTATION_PLATFORM_X390X = 9; - CRYPTO_IMPLEMENTATION_PLATFORM_PPC64 = 10; - CRYPTO_IMPLEMENTATION_PLATFORM_PPC64LE = 11; - CRYPTO_IMPLEMENTATION_PLATFORM_OTHER = 12; - CRYPTO_IMPLEMENTATION_PLATFORM_UNKNOWN = 13; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_IMPLEMENTATION_PLATFORM_UNSPECIFIED = 0; + // the platform is not known + CRYPTO_IMPLEMENTATION_PLATFORM_UNKNOWN = 1; + // none of the following + CRYPTO_IMPLEMENTATION_PLATFORM_OTHER = 2; + CRYPTO_IMPLEMENTATION_PLATFORM_GENERIC = 3; + CRYPTO_IMPLEMENTATION_PLATFORM_X86_32 = 4; + CRYPTO_IMPLEMENTATION_PLATFORM_X86_64 = 5; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV7A = 6; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV7M = 7; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV8A = 8; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV8M = 9; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV9A = 10; + CRYPTO_IMPLEMENTATION_PLATFORM_ARMV9M = 11; + CRYPTO_IMPLEMENTATION_PLATFORM_X390X = 12; + CRYPTO_IMPLEMENTATION_PLATFORM_PPC64 = 13; + CRYPTO_IMPLEMENTATION_PLATFORM_PPC64LE = 14; } enum CryptoAlgorithmMode { - CRYPTO_ALGORITHM_MODE_CBC = 0; - CRYPTO_ALGORITHM_MODE_ECB = 1; - CRYPTO_ALGORITHM_MODE_CCM = 2; - CRYPTO_ALGORITHM_MODE_GCM = 3; - CRYPTO_ALGORITHM_MODE_CFB = 4; - CRYPTO_ALGORITHM_MODE_OFB = 5; - CRYPTO_ALGORITHM_MODE_CTR = 6; - CRYPTO_ALGORITHM_MODE_OTHER = 7; - CRYPTO_ALGORITHM_MODE_UNKNOWN = 8; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_ALGORITHM_MODE_UNSPECIFIED = 0; + // The mode of operation is not known + CRYPTO_ALGORITHM_MODE_UNKNOWN = 1; + // Another mode of operation - none of the following + CRYPTO_ALGORITHM_MODE_OTHER = 2; + CRYPTO_ALGORITHM_MODE_CBC = 3; + CRYPTO_ALGORITHM_MODE_ECB = 4; + CRYPTO_ALGORITHM_MODE_CCM = 5; + CRYPTO_ALGORITHM_MODE_GCM = 6; + CRYPTO_ALGORITHM_MODE_CFB = 7; + CRYPTO_ALGORITHM_MODE_OFB = 8; + CRYPTO_ALGORITHM_MODE_CTR = 9; } enum CryptoAlgorithmPadding { - CRYPTO_ALGORITHM_PADDING_PKCS5 = 0; - CRYPTO_ALGORITHM_PADDING_PKCS7 = 1; - CRYPTO_ALGORITHM_PADDING_PKCS1V15 = 2; - CRYPTO_ALGORITHM_PADDING_OAEP = 3; - CRYPTO_ALGORITHM_PADDING_RAW = 4; - CRYPTO_ALGORITHM_PADDING_OTHER = 5; - CRYPTO_ALGORITHM_PADDING_UNKNOWN = 6; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_ALGORITHM_PADDING_UNSPECIFIED = 0; + // The padding scheme is not known + CRYPTO_ALGORITHM_PADDING_UNKNOWN = 1; + // Another padding scheme - none of the following + CRYPTO_ALGORITHM_PADDING_OTHER = 2; + CRYPTO_ALGORITHM_PADDING_PKCS5 = 3; + CRYPTO_ALGORITHM_PADDING_PKCS7 = 4; + CRYPTO_ALGORITHM_PADDING_PKCS1V15 = 5; + CRYPTO_ALGORITHM_PADDING_OAEP = 6; + CRYPTO_ALGORITHM_PADDING_RAW = 7; } enum CryptoAlgorithmFunction { - CRYPTO_ALGORITHM_FUNCTION_GENERATE = 0; - CRYPTO_ALGORITHM_FUNCTION_KEYGEN = 1; - CRYPTO_ALGORITHM_FUNCTION_ENCRYPT = 2; - CRYPTO_ALGORITHM_FUNCTION_DECRYPT = 3; - CRYPTO_ALGORITHM_FUNCTION_DIGEST = 4; - CRYPTO_ALGORITHM_FUNCTION_TAG = 5; - CRYPTO_ALGORITHM_FUNCTION_KEYDERIVE = 6; - CRYPTO_ALGORITHM_FUNCTION_SIGN = 7; - CRYPTO_ALGORITHM_FUNCTION_VERIFY = 8; - CRYPTO_ALGORITHM_FUNCTION_ENCAPSULATE = 9; - CRYPTO_ALGORITHM_FUNCTION_DECAPSULATE = 10; - CRYPTO_ALGORITHM_FUNCTION_OTHER = 11; - CRYPTO_ALGORITHM_FUNCTION_UNKNOWN = 12; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_ALGORITHM_FUNCTION_UNSPECIFIED = 0; + // meaning "there is some, but it is unclear which one" + CRYPTO_ALGORITHM_FUNCTION_UNKNOWN = 1; + // none of the following + CRYPTO_ALGORITHM_FUNCTION_OTHER = 2; + CRYPTO_ALGORITHM_FUNCTION_GENERATE = 3; + CRYPTO_ALGORITHM_FUNCTION_KEYGEN = 4; + CRYPTO_ALGORITHM_FUNCTION_ENCRYPT = 5; + CRYPTO_ALGORITHM_FUNCTION_DECRYPT = 6; + CRYPTO_ALGORITHM_FUNCTION_DIGEST = 7; + CRYPTO_ALGORITHM_FUNCTION_TAG = 8; + CRYPTO_ALGORITHM_FUNCTION_KEYDERIVE = 9; + CRYPTO_ALGORITHM_FUNCTION_SIGN = 10; + CRYPTO_ALGORITHM_FUNCTION_VERIFY = 11; + CRYPTO_ALGORITHM_FUNCTION_ENCAPSULATE = 12; + CRYPTO_ALGORITHM_FUNCTION_DECAPSULATE = 13; } // Cryptographic building blocks used in higher-level cryptographic systems and protocols. Primitives represent different cryptographic routines: deterministic random bit generators (drbg, e.g. CTR_DRBG from NIST SP800-90A-r1), message authentication codes (mac, e.g. HMAC-SHA-256), blockciphers (e.g. AES), streamciphers (e.g. Salsa20), signatures (e.g. ECDSA), hash functions (e.g. SHA-256), public-key encryption schemes (pke, e.g. RSA), extended output functions (xof, e.g. SHAKE256), key derivation functions (e.g. pbkdf2), key agreement algorithms (e.g. ECDH), key encapsulation mechanisms (e.g. ML-KEM), authenticated encryption (ae, e.g. AES-GCM) and the combination of multiple algorithms (combiner, e.g. SP800-56Cr2). optional CryptoPrimitive primitive = 1; @@ -1852,33 +1908,39 @@ message CryptoProperties { } // end of CertificateProperties message RelatedCryptoMaterialProperties { enum CryptoRelatedType { - CRYPTO_RELATED_TYPE_PRIVATE_KEY = 0; - CRYPTO_RELATED_TYPE_PUBLIC_KEY = 1; - CRYPTO_RELATED_TYPE_SECRET_KEY = 2; - CRYPTO_RELATED_TYPE_KEY = 3; - CRYPTO_RELATED_TYPE_CIPHERTEXT = 4; - CRYPTO_RELATED_TYPE_SIGNATURE = 5; - CRYPTO_RELATED_TYPE_DIGEST = 6; - CRYPTO_RELATED_TYPE_INITIALIZATION_VECTOR = 7; - CRYPTO_RELATED_TYPE_NONCE = 8; - CRYPTO_RELATED_TYPE_SEED = 9; - CRYPTO_RELATED_TYPE_SALT = 10; - CRYPTO_RELATED_TYPE_SHARED_SECRET = 11; - CRYPTO_RELATED_TYPE_TAG = 12; - CRYPTO_RELATED_TYPE_ADDITIONAL_DATA = 13; - CRYPTO_RELATED_TYPE_PASSWORD = 14; - CRYPTO_RELATED_TYPE_CREDENTIAL = 15; - CRYPTO_RELATED_TYPE_TOKEN = 16; - CRYPTO_RELATED_TYPE_OTHER = 17; - CRYPTO_RELATED_TYPE_UNKNOWN = 18; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_RELATED_TYPE_UNSPECIFIED = 0; + // The type of cryptographic asset is not known. + CRYPTO_RELATED_TYPE_UNKNOWN = 1; + // Another type of cryptographic asset - none of the following + CRYPTO_RELATED_TYPE_OTHER = 2; + CRYPTO_RELATED_TYPE_PRIVATE_KEY = 3; + CRYPTO_RELATED_TYPE_PUBLIC_KEY = 4; + CRYPTO_RELATED_TYPE_SECRET_KEY = 5; + CRYPTO_RELATED_TYPE_KEY = 6; + CRYPTO_RELATED_TYPE_CIPHERTEXT = 7; + CRYPTO_RELATED_TYPE_SIGNATURE = 8; + CRYPTO_RELATED_TYPE_DIGEST = 9; + CRYPTO_RELATED_TYPE_INITIALIZATION_VECTOR = 10; + CRYPTO_RELATED_TYPE_NONCE = 11; + CRYPTO_RELATED_TYPE_SEED = 12; + CRYPTO_RELATED_TYPE_SALT = 13; + CRYPTO_RELATED_TYPE_SHARED_SECRET = 14; + CRYPTO_RELATED_TYPE_TAG = 15; + CRYPTO_RELATED_TYPE_ADDITIONAL_DATA = 16; + CRYPTO_RELATED_TYPE_PASSWORD = 17; + CRYPTO_RELATED_TYPE_CREDENTIAL = 18; + CRYPTO_RELATED_TYPE_TOKEN = 19; } enum CryptoRelatedState { - CRYPTO_RELATED_STATE_PRE_ACTIVATION = 0; - CRYPTO_RELATED_STATE_ACTIVE = 1; - CRYPTO_RELATED_STATE_SUSPENDED = 2; - CRYPTO_RELATED_STATE_DEACTIVATED = 3; - CRYPTO_RELATED_STATE_COMPROMISED = 4; - CRYPTO_RELATED_STATE_DESTROYED = 5; + // Default + CRYPTO_RELATED_STATE_UNSPECIFIED = 0; + CRYPTO_RELATED_STATE_PRE_ACTIVATION = 1; + CRYPTO_RELATED_STATE_ACTIVE = 2; + CRYPTO_RELATED_STATE_SUSPENDED = 3; + CRYPTO_RELATED_STATE_DEACTIVATED = 4; + CRYPTO_RELATED_STATE_COMPROMISED = 5; + CRYPTO_RELATED_STATE_DESTROYED = 6; } message CryptoRelatedSecuredBy { // Specifies the mechanism by which the cryptographic asset is secured by. Examples include HSM, TPM, SGX, Software, and None @@ -1913,14 +1975,18 @@ message CryptoProperties { } // end of RelatedCryptoMaterialProperties message ProtocolProperties { enum CryptoProtocolType { - CRYPTO_PROTOCOL_TYPE_TLS = 0; - CRYPTO_PROTOCOL_TYPE_SSH = 1; - CRYPTO_PROTOCOL_TYPE_IPSEC = 2; - CRYPTO_PROTOCOL_TYPE_IKE = 3; - CRYPTO_PROTOCOL_TYPE_SSTP = 4; - CRYPTO_PROTOCOL_TYPE_WPA = 5; - CRYPTO_PROTOCOL_TYPE_OTHER = 6; - CRYPTO_PROTOCOL_TYPE_UNKNOWN = 7; + // ProtoBuff's default value -- it differs from "unknown" + CRYPTO_PROTOCOL_TYPE_UNSPECIFIED = 0; + // The protocol type is not known + CRYPTO_PROTOCOL_TYPE_UNKNOWN = 1; + // Another protocol type - none of the following + CRYPTO_PROTOCOL_TYPE_OTHER = 2; + CRYPTO_PROTOCOL_TYPE_TLS = 3; + CRYPTO_PROTOCOL_TYPE_SSH = 4; + CRYPTO_PROTOCOL_TYPE_IPSEC = 5; + CRYPTO_PROTOCOL_TYPE_IKE = 6; + CRYPTO_PROTOCOL_TYPE_SSTP = 7; + CRYPTO_PROTOCOL_TYPE_WPA = 8; } message CryptoProtocolCipherSuite { // A common name for the cipher suite. For example: TLS_DHE_RSA_WITH_AES_128_CCM diff --git a/tools/src/test/proto-test.sh b/tools/src/test/proto-test.sh deleted file mode 100755 index fa3377aa..00000000 --- a/tools/src/test/proto-test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -mkdir -p proto-test -for filename in resources/1.3/*.textproto; -do - protoc --proto_path=../../../schema/ --encode=cyclonedx.v1_3.Bom bom-1.3-SNAPSHOT.proto < $filename | protoc --proto_path=../../../schema/ --decode=cyclonedx.v1_3.Bom bom-1.3-SNAPSHOT.proto > proto-test/${filename##*/} -done; \ No newline at end of file diff --git a/tools/src/test/proto/buf_breaking-remote.yaml b/tools/src/test/proto/buf_breaking-remote.yaml new file mode 100644 index 00000000..7c3dbf25 --- /dev/null +++ b/tools/src/test/proto/buf_breaking-remote.yaml @@ -0,0 +1,7 @@ +# This is the config for "Buf" - a ProtocolBuffer linter/checker/more +# see https://buf.build/docs/configuration/v1/buf-yaml +version: v1 +breaking: # https://buf.build/docs/configuration/v1/buf-yaml#breaking + use: # see https://buf.build/docs/breaking/overview#rules-and-categories + - FILE + - WIRE_JSON \ No newline at end of file diff --git a/tools/src/test/proto/buf_breaking-version.yaml b/tools/src/test/proto/buf_breaking-version.yaml new file mode 100644 index 00000000..fcc81b05 --- /dev/null +++ b/tools/src/test/proto/buf_breaking-version.yaml @@ -0,0 +1,10 @@ +# This is the config for "Buf" - a ProtocolBuffer linter/checker/more +# see https://buf.build/docs/configuration/v1/buf-yaml +version: v1 +breaking: # https://buf.build/docs/configuration/v1/buf-yaml#breaking + use: # see https://buf.build/docs/breaking/overview#rules-and-categories + - FILE + - WIRE_JSON + except: + # scope is to detect changes from one version to the other -> so ignore "FILE_SAME_PACKAGE" + - FILE_SAME_PACKAGE \ No newline at end of file diff --git a/tools/src/test/proto/buf_lint.yaml b/tools/src/test/proto/buf_lint.yaml new file mode 100644 index 00000000..0b78a3cb --- /dev/null +++ b/tools/src/test/proto/buf_lint.yaml @@ -0,0 +1,22 @@ +# This is the config for "Buf" - a ProtocolBuffer linter/checker/more +# see https://buf.build/docs/configuration/v1/buf-yaml +version: v1 +lint: # https://buf.build/docs/configuration/v1/buf-yaml#lint + use: # see https://buf.build/docs/lint/rules + - DEFAULT # https://buf.build/docs/lint/rules#default + except: + # directory/file layout does not match the recommendation/framework of the tool + - DIRECTORY_SAME_PACKAGE # https://buf.build/docs/lint/rules#directory_same_package + - PACKAGE_DIRECTORY_MATCH # https://buf.build/docs/lint/rules#package_lower_snake_case + - FILE_LOWER_SNAKE_CASE # https://buf.build/docs/lint/rules#file_lower_snake_case + # we do not stick to the following best-practices and recommendations: + # (shall be fixed with v2.0 of this very schema) + - PACKAGE_VERSION_SUFFIX # https://buf.build/docs/lint/rules#package_version_suffix + - FIELD_LOWER_SNAKE_CASE # https://buf.build/docs/lint/rules#field_lower_snake_case + ignore_only: + DEFAULT: # https://buf.build/docs/lint/rules#default + # legacy schema files may NOT stick to the rules -- this is acknowledged. + - "schema/bom-1.5.proto" + - "schema/bom-1.4.proto" + - "schema/bom-1.3.proto" + allow_comment_ignores: true # the so-called "baseline" is done by annotating exceptions diff --git a/tools/src/test/proto/test.sh b/tools/src/test/proto/test.sh new file mode 100755 index 00000000..a09b4dc7 --- /dev/null +++ b/tools/src/test/proto/test.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +set -ue + +THIS_PATH="$(realpath "$(dirname "$0")")" +ROOT_PATH="$(realpath "${THIS_PATH}/../../../..")" + +# paths relative to $ROOT_PATH +SCHEMA_DIR='schema' +TEST_RES_DIR='tools/src/test/resources' + +REMOTE="https://github.com/${GITHUB_REPOSITORY:-CycloneDX/specification}.git" + + +## ---- + + +function schema-lint () { + echo '> lint schema files' >&2 + + if [[ -n "${CI:-}" ]] + then + LOG_FORMAT='github-actions' + else + LOG_FORMAT='text' + fi + + docker run --rm \ + --volume "${ROOT_PATH}/${SCHEMA_DIR}:/workspace/${SCHEMA_DIR}:ro" \ + --volume "${THIS_PATH}/buf_lint.yaml:/workspace/buf.yaml:ro" \ + --workdir '/workspace' \ + bufbuild/buf:1.29.0 \ + lint --path "$SCHEMA_DIR" \ + --config 'buf.yaml' \ + --error-format "$LOG_FORMAT" + + echo '>> OK.' >&2 +} + + +function schema-breaking-version () { + echo '> test schema for breaking changes against previous version' >&2 + + if [[ -n "${GITHUB_WORKFLOW:-}" ]] + then + LOG_FORMAT='github-actions' + else + LOG_FORMAT='text' + fi + + function compare() { + NEW="bom-${1}.proto" + OLD="bom-${2}.proto" + SCHEMA_DIR_OLD="${SCHEMA_DIR}_old" + + echo ">> compare new:${NEW} -VS- old:${OLD}" >&2 + # stick with the original path of "$NEW", so the reporting makes sense... + docker run --rm \ + --volume "${ROOT_PATH}/${SCHEMA_DIR}/${NEW}:/workspace/${SCHEMA_DIR}/${NEW}:ro" \ + --volume "${ROOT_PATH}/${SCHEMA_DIR}/${OLD}:/workspace/${SCHEMA_DIR_OLD}/${NEW}:ro" \ + --volume "${THIS_PATH}/buf_breaking-version.yaml:/workspace/buf.yaml:ro" \ + --workdir '/workspace' \ + bufbuild/buf:1.29.0 \ + breaking "$SCHEMA_DIR" \ + --against "$SCHEMA_DIR_OLD" \ + --config 'buf.yaml' \ + --error-format "$LOG_FORMAT" + } + + compare '1.6' '1.5' + echo '>> skip compare' '1.5' '1.4' >&2 # <-- had breaking changes, which is acknowledged + compare '1.4' '1.3' + + echo '>> OK.' >&2 +} + +function schema-breaking-remote () { + echo '> test schema for breaking changes against remote' >&2 + + if [[ -n "${GITHUB_WORKFLOW:-}" ]] + then + LOG_FORMAT='github-actions' + else + LOG_FORMAT='text' + fi + + docker run --rm \ + --volume "${ROOT_PATH}/${SCHEMA_DIR}:/workspace/${SCHEMA_DIR}:ro" \ + --volume "${THIS_PATH}/buf_breaking-remote.yaml:/workspace/buf.yaml:ro" \ + --workdir '/workspace' \ + bufbuild/buf:1.29.0 \ + breaking "$SCHEMA_DIR" \ + --against "${REMOTE}#subdir=${SCHEMA_DIR}" \ + --config 'buf.yaml' \ + --error-format "$LOG_FORMAT" + + echo '>> OK.' >&2 +} + +function schema-functional () { + echo '> test all examples against the respective schema' >&2 + + function validate() { + FILE="$1" + SCHEMA_VERS="$2" + SCHEMA_FILE="bom-${SCHEMA_VERS}.proto" + MESSAGE="cyclonedx.v${SCHEMA_VERS/./_}.Bom" + + echo ">> validate $(realpath --relative-to="$PWD" "$FILE") as ${MESSAGE} of ${SCHEMA_FILE}" >&2 + + docker run --rm \ + --volume "${ROOT_PATH}/${SCHEMA_DIR}:/workspace/${SCHEMA_DIR}:ro" \ + --volume "${FILE}:/workspace/test_res:ro" \ + --workdir '/workspace' \ + bufbuild/buf:1.29.0 \ + convert "${SCHEMA_DIR}/${SCHEMA_FILE}" \ + --type "$MESSAGE" \ + --from 'test_res#format=txtpb' \ + --to /dev/null + } + + shopt -s globstar + for test_res in "$ROOT_PATH"/"$TEST_RES_DIR"/*/valid-*.textproto + do + SCHEMA_VERS="$(basename "$(dirname "$test_res")")" + validate "$test_res" "$SCHEMA_VERS" + done + + echo '>> OK.' >&2 +} + + +## ---- + + +case "${1:-all}" in + 'schema-lint') + schema-lint + ;; + 'schema-breaking-version') + schema-breaking-version + ;; + 'schema-breaking-remote') + schema-breaking-remote + ;; + 'schema-breaking') + schema-breaking-version + schema-breaking-remote + ;; + 'schema-functional') + schema-functional + ;; + 'all') + # all the above + schema-lint + schema-breaking-version + schema-breaking-remote + schema-functional + ;; + *) + echo 'unexpected argument. known arguments:' \ + 'schema-lint,schema-breaking-version,schema-breaking-remote,schema-breaking,schema-functional,all' \ + >&2 + exit 1 + ;; +esac \ No newline at end of file diff --git a/tools/src/test/resources/1.4/valid-release-notes-1.4.textproto b/tools/src/test/resources/1.4/valid-release-notes-1.4.textproto index 2d2b7ca1..b728ca92 100644 --- a/tools/src/test/resources/1.4/valid-release-notes-1.4.textproto +++ b/tools/src/test/resources/1.4/valid-release-notes-1.4.textproto @@ -85,7 +85,7 @@ services { url: "http://api.partner.org/swagger" } releaseNotes: { - type: RELEASE_TYPE_MAJOR + type: "major" title: "My new release" featuredImage: "https://example.com/featured_image.png" socialImage: "https://example.com/social_image.png" diff --git a/tools/src/test/resources/1.5/valid-release-notes-1.5.textproto b/tools/src/test/resources/1.5/valid-release-notes-1.5.textproto index 0c6c0d40..b113d108 100644 --- a/tools/src/test/resources/1.5/valid-release-notes-1.5.textproto +++ b/tools/src/test/resources/1.5/valid-release-notes-1.5.textproto @@ -85,7 +85,7 @@ services { url: "http://api.partner.org/swagger" } releaseNotes: { - type: RELEASE_TYPE_MAJOR + type: "major" title: "My new release" featuredImage: "https://example.com/featured_image.png" socialImage: "https://example.com/social_image.png" diff --git a/tools/src/test/resources/1.6/valid-release-notes-1.6.textproto b/tools/src/test/resources/1.6/valid-release-notes-1.6.textproto index f2a79cd7..a227035a 100644 --- a/tools/src/test/resources/1.6/valid-release-notes-1.6.textproto +++ b/tools/src/test/resources/1.6/valid-release-notes-1.6.textproto @@ -85,7 +85,7 @@ services { url: "http://api.partner.org/swagger" } releaseNotes: { - type: RELEASE_TYPE_MAJOR + type: "major" title: "My new release" featuredImage: "https://example.com/featured_image.png" socialImage: "https://example.com/social_image.png"