Open source best practices for higher quality code to fundamentally strengthen your project
8 minute read time
Sonatype has partnered with the Cloud Native Computing Foundation (CNCF) for Security Slam, an event to help improve the security of open source projects. To extend the value of this event, we created a series of blog posts on best practices for open source maintainers.
Here in the third and final post of our series, we focus on a few best practices for higher quality code to help fundamentally strengthen your project. A strong foundation on which to build and grow your project starts with a return to fundamental practices that keep contributors and maintainers on the same page.
Modern threat vectors: An ongoing story
Open source software, by its very nature, is built by the community, for the community.
However, open source projects that gain even a modest level of visibility deal increasingly with more and more attacks by bad actors.
Bad actors no longer wait for public disclosure of vulnerabilities. They forge their own paths to gain unauthorized access and extract data. While they continue to carve out more threat vectors, a few current popular methods include:
-
Repository hijacking – They hijack a maintainer account and publish malicious packages to the repository.
-
Typosquatting – They try to trick developers into downloading deliberately misnamed malicious packages meant to closely resemble legitimate packages.
-
Dependency confusion – They trick an installer script into pulling a malicious code file from a public repository rather than the intended file with the same name from a private repository.
Recently, we see these tactics play out in a few notorious cases, such as a popular npm project, a PHP Git server hack, and a flood of dependency confusion PoCs on PyPI projects.
Opportunistic bad actors continually find new threat vectors and constantly renew tried-and-true tactics of attacking software projects. For open source projects, bad actors might bluntly attempt to inject malicious code into projects under the guise of a legitimate contribution.
Fortunately, in terms of open source software projects we detail a few basic practices below that can help you prioritize code quality, shore up your security, and control your own narrative as you try to not become a character in a bad actor's schemes.
Basic practices to put your project on a path to higher quality code
Code reviews
As attention to upstream open source projects disseminates amongst bad actors, code reviews can help you protect against the latest trends of malicious behavior. Furthermore, Sonatype's 8th Annual State of the Software Supply Chain Report revealed code review as the top factor that identifies a project's vulnerability.
Code review delivers multiple benefits:
-
Root out bugs that you may have otherwise missed.
-
Receive feedback on how to improve the quality of your code.
-
Create buy-in and help build trust within your community.
By having your code reviewed, you demonstrate a willingness to listen to feedback and make changes based on it. This in turn frames your project as a space for collaboration and makes users more likely to contribute.
The mere presence of a called-out code review process may also deter malicious contributors from attempting to outsmart your project in the first place. If you require code reviews before the merge of a pull request to the project, you can protect against any undue influence.
Overall, an established code review process can help find bugs, improve code quality, and build trust within the community.
Signed releases
A signed software release provides evidence (a cryptographic signature) that a piece of code originated with a particular developer or organization and guarantees the code has not been edited or corrupted since it was signed.
Signed releases can deter would-be attackers since tampering can be easily detected. Additionally, signed releases can provide a measure of assurance to users that the software they install is the software released by the project maintainers and not an imposter.
There are a few different ways to sign releases:
-
The most common way is to use GnuPG (GPG), which is a free and open source implementation of the OpenPGP standard. To sign a release with GPG, you first need to generate a key pair. The private key should be kept safe and secure, as it will be used to sign releases. The public key can be distributed to anyone who wants to verify the signature on a release.
-
Another way you can sign releases is via Sigstore. Sigstore uses OpenID authentication to tie certificates to identities. You can use your account or email address with an existing OpenID identity provider to sign your software.
Signing releases helps assure your users that releases really come from a canonical source and give a verifiable provenance they can use to ensure your project is what it seems.
Change control
No set of anointed best practices can ever completely prevent vulnerabilities or defects in your open source software project. But practices that encourage repeated interactions among developers help build trust and lay a foundation for a well-functioning development community. Visibility of your change control processes puts you on a path to better code quality.
If you use a common distributed version control system (VCS), such as Git, you typically have a number of change control features readily available, such as:
-
accessibility to previous versions and variants of your project which you can review at any time;
-
ability to restore previous versions of your project if you wish to undo your latest changes; and
-
chronology of your descriptions of changes you made to each release throughout your project’s history to track its evolution.
Additionally, unique version numbering helps your users stay out of dependency hell. Semantic Versioning (SemVer) and Calendar Versioning (CalVer) exist as common standards in this regard to help you safely move your project forward.
Release notes summarize changes of a given release and help your users decide if they should upgrade given potential impacts of doing so. Rather than the raw output of a version control log, this should be a published detailed document that describes:
-
features you added;
-
issues you resolved;
-
improvements you made; and
-
any publicly known run-time vulnerabilities you fixed in this release.
Release notes complement other key documents that help welcome new contributors to your project.
Elements to help strengthen code quality
OpenSSF Security Scorecard
The Open Source Software Foundation (OpenSSF) created a Security Scorecard tool that grades the security health of a project. The scoring process assesses a project’s practices such as code review, signed releases, and usage of dependency update tools and generates a quantitative output.
The resultant score gives you a measurement of your project’s security posture and gives you an idea of the possible risks introduced by your dependencies.
You can run Security Scorecards manually via command line or automatically on code you own via GitHub Actions.
Security Scorecards assigns a 0-10 score to a series of checks — heuristics commonly associated with software security. These checks include, but are not limited to:
-
Code review
-
Signed releases
-
Binary artifacts
-
Branch protection
-
Continuous integration tests
-
Vulnerabilities
If you want to further your development of best practices in addition to Security Scorecards, check out OpenSSF's Best Practices Badge Program.
CLOMonitor
The CNCF created a tool called CLOMonitor which you can use to periodically check your open source project repository and gauge health and security posture. Essentially, it serves as a dashboard for viewing your project’s progress as you work to improve its security relative to the checks system.
Notably, CLOMonitor runs a number of security checks from OpenSSF's Security Scorecard.
In addition to Security Scorecard checks on code reviews, signed releases, and binary artifacts, CLOMonitor checks also include:
-
Contributor license agreement
-
Developer certificate of origin
-
Security policy
For qualified projects, clomonitor.io provides a comprehensive user interface with automatic scans to keep the website up to date.
If you want to review or modify the checks being made for a project, check out the CLOMonitor configuration file. This YAML file will specify:
-
Which projects are checked;
-
Which repositories are considered as part of each project; and
-
Which subset of checks are executed for each repository.
For any use case not covered by clomonitor.io, you can take advantage of a local, Dockerized execution of the application.
You can also follow the docs to set up your development environment to build, test, and run CLOMonitor locally from source.
A basic foundation to support your project
While bad actors continue to weaponize new threat vectors in open source software, you as the maintainer can stand your ground with a strong foundation of development basics.
In leveraging tools and staying vigilant with basic practices such as code reviews, signed releases, and change control processes, you can ensure your code maintains a high level of quality control.
While you might already have enough on your plate dealing with low-quality contributions, you can mount a good defense against malicious behavior and other bad-actor techniques by shoring up a few basic practices and leveraging some helpful tools.
Written by Aaron Linskens
Aaron is a technical writer on Sonatype's Marketing team. He works at a crossroads of technical writing, developer advocacy, software development, and open source. He aims to get developers and non-technical collaborators to work well together via experimentation, feedback, and iteration so they can build the right software.
Explore All Posts by Aaron Linskens