OSV-SCALIBR style guide
October 7, 2025 ยท View on GitHub
OSV-SCALIBR, like most of Google's Go projects, follows the Google Go style guide. Apart from this, we have some specific OSV-SCALIBR specific best practices:
Code structure
Line length
Use 80 characters per line when possible. Exceptions apply if splitting something into several lines hurts readability.
Short functions
Prefer short functions. If a function is getting too large, consider moving self-contained parts of the business logic into separate private helper functions with descriptive names, even if they're only called once.
Similarly, if the list of params to a function is getting too long, consider moving them to an option structure. This shortens the function definitions and makes it easier to oversee the purpose of each param.
Function ordering: General to specific
Define the public structs/functions/etc. in a class first, then define the private functions.
Within private functions, define the higher-order ones first. E.g. if function
a() is calling b(), define a first, then b.
Short inline functions
Keep inline functions short. If they're getting long, prefer moving them into a separate named private function.
Since inline functions can capture vars from the parent function they can get hard to oversee if they grow too large. By factoring them into separate functions, any vars from the parent function have to be passed as parameters, making it easier to understand how the function affects the surrounding code.
Inline constants
If a constant is private and used only once, prefer inlining it where it's used instead of adding a top-level const declaration.
Regexes are exempt from this since they should be initialized at startup - See the section below for more details.
Avoid init()
Usage of init() makes it hard to keep track of the control flow. Prefer
avoiding it in production code. In tests you can use TestMain() instead.
Context propagation
OSV-SCALIBR library users can pass in a context.Context to control timeouts
and context cancellation. Make sure this top-level context is passed down to
lower functions (don't initialize a new context with context.Background()) and
check for context cancellation whenever something long-running is performed such
as looping
(example).
Error handling
Avoid panics
If a plugin encounters an error the rest of OSV-SCALIBR and the callers' code shouldn't crash. Avoid calling panics and prefer propagating errors instead.
Init regexes at startup time
Add all regex definitions that use MustCompile as global vars that initialize
at startup time
(example).
This allows the initialization computation to be done up front and catches any
potential crashes before the scan runs.
Propagate or log errors
In general, propagate errors upwards to the caller.
If the error is expected or not something that should make the module fail (e.g. an Extractor encountered an invalid package.json file) there's no need to propagate it but consider logging a warning instead.
Testing
Don't use t.Parallel()
While t.Parallel() allows tests to run faster, they cause test logs in our
internal systems to be mixed together for various test cases, making them harder
to read. OSV-SCALIBR unit tests also only take a couple of seconds to run so
there's not much benefit in adding t.Parallel() at the moment.
Avoid assertion libraries
Generally avoid creating helper libraries that perform test assertions. Instead, use helper libs to transform your data into a more easily comparable structure and perform the comparisions/assertions in the main test function. Example: the extracttest helper lib.
An exception is when the helper library is used to set up the testing environment (e.g. create specific files). In these cases it's fine to assert that the setup succeeded in the library function as long as the setup code is not related to the functionality being tested (example).
Use easy to find subtest descriptions
Use only alphanumeric characters and underscores in test descriptions. Don't use spaces. Test logs transform these descriptions by substituting the spaces which makes the failing tests from the logs harder to find in the code (example).
Test for multi-platform support
OSV-SCALIBR runs on Linux, Windows, and Mac. When adding new code, make sure your code is compatible with all 3 OSes or that you're adding a component that's only meant to run on a given OS. Check that the SCALIBR Github Actions for all 3 OSes pass.
When using OS specific helper libraries consider adding dummy implementations for other OSes (example).
One common change that fails on Window is introducing file path processing code
that uses the wrong kinds of slashes (/ vs \). When dealing with absolute
paths, use built-in functions such as filepath.Join() to handle path
operations. Virtual paths use the fs.FS interface which uses / even on
Windows. In these cases you can sanitize your paths with filepath.ToSlash
(example).
Performance
OSV-SCALIBR is meant to also run on systems with constrained resources and new code should thus try to keep its runtime and resource usage low. Plugins that have a high resource consumption will be able to run in less contexts and will thus be less useful.
Avoid expensive operations in FileRequired
Extractor plugins' FileRequired() function can get called on every file on the
scanned filesystem. Keep the checks simple by using simple string comparison
logic. Define the checks inside FileRequired() instead of separate functions
as function calls can add additional runtime overhead.
Avoid doing expensive file path comparisons such as regexp matching unless you've already pre-filtered the files and can be sure that the more expensive operations will only run on a small subset of the files.
Avoid reading full binaries into memory
When parsing binaries and lockfiles that can get large, avoid reading all of the
file contents into memory whenever possible. Prefer to use streaming readers.
For reading a specific section of a large file, prefer using
ReadAt() instead of slicing out the relevant
sections in memory.
Miscellaneous
Use the Unit lib for large numbers
OSV-SCALIBR has a
unit lib
for commonly used data size units. Use the values from these lib instead code
like "2 * 1024 * 1024".
Prefer %q over %s
When formatting strings, %q adds escapes and quotation marks and makes it
easier to see where a string variable in the log message starts. It also makes
it easier to see empty strings in logs
(example).
Add docstrings to public functions and types
All public functions and type should have doc comments.