Summary
Using -o flag in sbom mode produces a runtime error, because it never specifies the output directory
Steps to Reproduce
[[Blint]] sbom --src . -o sbom.json- Generate runtime error
▓ 09:49 main ? …/blint/c_tests blint sbom --src . -o sbom.json
sbom.json
Traceback (most recent call last):
File "/home/bay/Developer/blint/blint-py/bin/blint", line 8, in <module>
sys.exit(main())
~~~~^^
File "/home/bay/Developer/blint/blint-py/lib/python3.13/site-packages/blint/cli.py", line 255, in main
run_sbom_mode(blint_options)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "/home/bay/Developer/blint/blint-py/lib/python3.13/site-packages/blint/lib/runners.py", line 45, in run_sbom_mode
return generate(blint_options, exe_files, android_files)
File "/home/bay/Developer/blint/blint-py/lib/python3.13/site-packages/blint/lib/sbom.py", line 173, in generate
return create_sbom(
components,
...<4 lines>...
symbols_purl_map,
)
File "/home/bay/Developer/blint/blint-py/lib/python3.13/site-packages/blint/lib/sbom.py", line 235, in create_sbom
os.makedirs(output_dir)
~~~~~~~~~~~^^^^^^^^^^^^
File "<frozen os>", line 227, in makedirs
FileNotFoundError: [Errno 2] No such file or directory: ''Root cause
Inside of sbom.py in the function create_sbom on line 235 we can see this code snippet inside here where sbom files are created.
# Populate the dependencies
sbom.dependencies = dependencies
LOG.debug(
f"SBOM includes {len(sbom.components)} components and {len(sbom.dependencies)} dependencies"
)
if output_file is sys.stdout:
print(sbom.model_dump_json(indent=2, exclude_none=True, exclude_defaults=True, warnings=False, by_alias=True))
else:
output_dir = os.path.split(output_file)[0]
if not os.path.exists(output_dir):
os.makedirs(output_dir)
file_write(
output_file,
sbom.model_dump_json(
indent=None if deep_mode else 2,
exclude_none=True,
exclude_defaults=True,
warnings=False,
by_alias=True,
),
log=LOG,
)
return sbomoutput_dir is created here, its value is being given from os.path.split(output_file)[0]. When we pass in the -o we can see that the produced value of output_dir is an empty string. The error also tells us this too FileNotFoundError: [Errno 2] No such file or directory: ''
Solution
Since by default when using Blint sbom, it’ll create a directory named reports.
To keep confusion minimal I decided it be best to just name the output_dir for sbom mode reports.
But doing just this will place an output_dir reports and the the output_file sbom.json not inside the directory
- To fix this instead of writing the file
sbom.jsonwe write it into the output_dir using anos.path.join
else:
output_dir = "reports"
if not os.path.exists(output_dir):
os.makedirs(output_dir)
file_write(
os.path.join(output_dir, output_file),
sbom.model_dump_json(
indent=None if deep_mode else 2,
exclude_none=True,
exclude_defaults=True,
warnings=False,
by_alias=True,
),
log=LOG,
)
return sbomResults after fix
After this fix, you’re able to use the -o flag to specify the name of the sbom that will be generated. It won’t break the -o flag for the non sbom mode because that itself specifies the output directory and we only modified the Create_sbom function.
▒▓ 10:23 main !? …/blint/c_tests blint sbom --src . -o sbom.json
░▒▓ 10:23 main !? …/blint/c_tests ls ◄ 2s
reports a.out main.c
░▒▓ 10:23 main !? …/blint/c_tests ls reports/
sbom.json
░▒▓ 10:23 main !? …/blint/c_tests - I also made sure to test it on a normal sbom output too as to not break things
░▒▓ 10:24 main !? …/blint/c_tests rm -rf reports/
░▒▓ 10:24 main !? …/blint/c_tests blint sbom --src .
░▒▓ 10:24 main !? …/blint/c_tests ls ◄ 2s
reports a.out main.c
░▒▓ 10:24 main !? …/blint/c_tests ls reports/
bom-post-build.cdx.json
░▒▓ 10:24 main !? …/blint/c_tests