Skip to content

Fix NoMethodError when `report_source` is missing

Brian Williams requested to merge bwill/fix-nil-source-error into master

What does this MR do and why?

Describe in detail what your merge request does and why.

Source data in a CycloneDX report is optional, but we forgot to guard against this in the OccurrenceMap class. Ingesting a CycloneDX report without source properties causes a NoMethodError when we try to create the OccurrenceMap hash.

This MR changes OccurrenceMap#to_h to use safe accessors for the report source, so that we return nil instead. Downstream, we access this data via the IngestSources task, which already expects the report_source to possibly be nil.

This bug is not user-facing as this feature is currently behind a feature flag, so a changelog is not needed.

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

  1. Ensure that you have an EE license

  2. Enabled the feature flag using the rails console: Feature.enable(:cyclonedx_sbom_ingestion)

  3. Setup gitlab runner

  4. Create a new project

  5. Add the following .gitlab-ci.yml to the project:

    persist_sbom:
      image: alpine:latest
      script:
        - wget https://gitlab.com/-/snippets/2378046/raw/main/gl-sbom-missing-source-data.cdx.json
      artifacts:
        reports:
          cyclonedx:
            - gl-sbom-missing-source-data.cdx.json
  6. The pipeline should run and succeed. Note down the pipeline ID.

  7. Connect to postgres: gdk psql

  8. Run this query and verify that data is returned:

    select
      name, version, component_type, source_id
    from
      sbom_components
    inner join sbom_component_versions
      on sbom_components.id = sbom_component_versions.component_id
    inner join sbom_occurrences
      on sbom_component_versions.id = sbom_occurrences.component_version_id
    where pipeline_id = YOUR_PIPELINE_ID;
Example data
         name         |   version    | component_type | source_id 
----------------------+--------------+----------------+-----------
 source-map           | 0.5.7        |              0 |          
 source-map           | 0.4.4        |              0 |          
 @types/babel-types   | 7.0.4        |              0 |          
 @types/babylon       | 6.16.3       |              0 |          
 accepts              | 1.3.5        |              0 |          
 acorn                | 4.0.13       |              0 |          
 acorn                | 3.3.0        |              0 |          
 acorn-globals        | 3.1.0        |              0 |          
 align-text           | 0.1.4        |              0 |          
 amdefine             | 1.0.1        |              0 |          
 array-flatten        | 1.1.1        |              0 |          
 asap                 | 2.0.6        |              0 |          
 asynckit             | 0.4.0        |              0 |          
 babel-runtime        | 6.26.0       |              0 |          
 once                 | 1.4.0        |              0 |          
 path-is-absolute     | 1.0.1        |              0 |          
 path-parse           | 1.0.5        |              0 |          
 window-size          | 0.1.0        |              0 |          
 wordwrap             | 0.0.2        |              0 |          
 wrappy               | 1.0.2        |              0 |          
 yargs                | 3.10.0       |              0 |          
 babel-types          | 6.26.0       |              0 |          
 babylon              | 6.18.0       |              0 |          
 balanced-match       | 1.0.0        |              0 |          
 basic-auth           | 2.0.0        |              0 |          
 body-parser          | 1.18.2       |              0 |          
 brace-expansion      | 1.1.11       |              0 |          
 browser-stdout       | 1.3.1        |              0 |          
 bytes                | 3.0.0        |              0 |          
 camelcase            | 1.2.1        |              0 |          
 center-align         | 0.1.3        |              0 |          
 character-parser     | 2.2.0        |              0 |          
 clean-css            | 3.4.28       |              0 |          
 cliui                | 2.1.0        |              0 |          
 combined-stream      | 1.0.6        |              0 |          
 commander            | 2.8.1        |              0 |          
 commander            | 2.15.1       |              0 |          
 component-emitter    | 1.2.1        |              0 |          
 concat-map           | 0.0.1        |              0 |          
 constantinople       | 3.1.2        |              0 |          
 content-disposition  | 0.5.2        |              0 |          
 content-type         | 1.0.4        |              0 |          
 cookie               | 0.3.1        |              0 |          
 cookie-parser        | 1.4.3        |              0 |          
 cookie-signature     | 1.0.6        |              0 |          
 cookiejar            | 2.1.2        |              0 |          
 core-js              | 2.5.7        |              0 |          
 core-util-is         | 1.0.2        |              0 |          
 debug                | 3.1.0        |              0 |          
 debug                | 2.6.9        |              0 |          
 decamelize           | 1.2.0        |              0 |          
 delayed-stream       | 1.0.0        |              0 |          
 depd                 | 1.1.2        |              0 |          
 depd                 | 1.1.1        |              0 |          
 destroy              | 1.0.4        |              0 |          
 diff                 | 3.5.0        |              0 |          
 doctypes             | 1.1.0        |              0 |          
 ee-first             | 1.1.1        |              0 |          
 encodeurl            | 1.0.2        |              0 |          
 escape-html          | 1.0.3        |              0 |          
 escape-string-regexp | 1.0.5        |              0 |          
 esutils              | 2.0.2        |              0 |          
 etag                 | 1.8.1        |              0 |          
 express              | 4.16.3       |              0 |          
 extend               | 3.0.2        |              0 |          
 finalhandler         | 1.1.1        |              0 |          
 form-data            | 2.3.2        |              0 |          
 formidable           | 1.2.1        |              0 |          
 forwarded            | 0.1.2        |              0 |          
 fresh                | 0.5.2        |              0 |          
 fs.realpath          | 1.0.0        |              0 |          
 function-bind        | 1.1.1        |              0 |          
 graceful-readlink    | 1.0.1        |              0 |          
 growl                | 1.10.5       |              0 |          
 has                  | 1.0.3        |              0 |          
 he                   | 1.1.1        |              0 |          
 http-errors          | 1.6.3        |              0 |          
 http-errors          | 1.6.2        |              0 |          
 ipaddr.js            | 1.8.0        |              0 |          
 is-expression        | 3.0.0        |              0 |          
 is-promise           | 2.1.0        |              0 |          
 is-regex             | 1.0.4        |              0 |          
 js-stringify         | 1.0.2        |              0 |          
 jstransformer        | 1.0.0        |              0 |          
 media-typer          | 0.3.0        |              0 |          
 merge-descriptors    | 1.0.1        |              0 |          
 methods              | 1.1.2        |              0 |          
 mime                 | 1.4.1        |              0 |          
 mime-db              | 1.35.0       |              0 |          
 mime-types           | 2.1.19       |              0 |          
 minimatch            | 3.0.4        |              0 |          
 minimist             | 0.0.8        |              0 |          
 mkdirp               | 0.5.1        |              0 |          
 mocha                | 5.2.0        |              0 |          
 morgan               | 1.9.0        |              0 |          
 ms                   | 2.0.0        |              0 |          
 negotiator           | 0.6.1        |              0 |          
 object-assign        | 4.1.1        |              0 |          
 on-finished          | 2.3.0        |              0 |          
 on-headers           | 1.0.1        |              0 |          
 parseurl             | 1.3.2        |              0 |          
 path-to-regexp       | 0.1.7        |              0 |          
 process-nextick-args | 2.0.0        |              0 |          
 promise              | 7.3.1        |              0 |          
 proxy-addr           | 2.0.4        |              0 |          
 pug                  | 2.0.0-beta11 |              0 |          
 pug-attrs            | 2.0.3        |              0 |          
 pug-code-gen         | 1.1.1        |              0 |          
 pug-error            | 1.3.2        |              0 |          
 pug-filters          | 2.1.5        |              0 |          
 pug-lexer            | 3.1.0        |              0 |          
 pug-linker           | 2.0.3        |              0 |          
 pug-load             | 2.0.11       |              0 |          
 pug-parser           | 2.0.2        |              0 |          
 pug-runtime          | 2.0.4        |              0 |          
 pug-strip-comments   | 1.0.3        |              0 |          
 pug-walk             | 1.1.7        |              0 |          
 range-parser         | 1.2.0        |              0 |          
 raw-body             | 2.3.2        |              0 |          
 readable-stream      | 2.3.6        |              0 |          
 resolve              | 1.8.1        |              0 |          
 send                 | 0.16.2       |              0 |          
 serve-static         | 1.13.2       |              0 |          
 setprototypeof       | 1.1.0        |              0 |          
 setprototypeof       | 1.0.3        |              0 |          
 statuses             | 1.4.0        |              0 |          
 string_decoder       | 1.1.1        |              0 |          
 superagent           | 3.8.2        |              0 |          
 supertest            | 3.1.0        |              0 |          
 supports-color       | 5.4.0        |              0 |          
 to-fast-properties   | 1.0.3        |              0 |          
 token-stream         | 0.0.1        |              0 |          
 type-is              | 1.6.16       |              0 |          
 uglify-js            | 2.8.29       |              0 |          
 uglify-to-browserify | 1.0.2        |              0 |          
 unpipe               | 1.0.0        |              0 |          
 util-deprecate       | 1.0.2        |              0 |          
 utils-merge          | 1.0.1        |              0 |          
 vary                 | 1.1.2        |              0 |          
 void-elements        | 2.0.1        |              0 |          
 with                 | 5.1.1        |              0 |          
 glob                 | 7.1.2        |              0 |          
 has-flag             | 3.0.0        |              0 |          
 iconv-lite           | 0.4.19       |              0 |          
 inflight             | 1.0.6        |              0 |          
 inherits             | 2.0.3        |              0 |          
 is-buffer            | 1.1.6        |              0 |          
 isarray              | 1.0.0        |              0 |          
 kind-of              | 3.2.2        |              0 |          
 lazy-cache           | 1.0.4        |              0 |          
 lodash               | 4.17.10      |              0 |          
 longest              | 1.0.1        |              0 |          
 qs                   | 6.5.1        |              0 |          
 regenerator-runtime  | 0.11.1       |              0 |          
 repeat-string        | 1.6.1        |              0 |          
 right-align          | 0.1.3        |              0 |          
 safe-buffer          | 5.1.1        |              0 |          
(157 rows)

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Brian Williams

Merge request reports