Fix NoMethodError when `report_source` is missing
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.
-
Enabled the feature flag using the rails console:
Feature.enable(:cyclonedx_sbom_ingestion)
-
Create a new project
-
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
-
The pipeline should run and succeed. Note down the pipeline ID.
-
Connect to postgres:
gdk psql
-
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.
-
I have evaluated the MR acceptance checklist for this MR.