Written by Andrew Lilley Brinker
Posted on March 14, 2025
Hipcheck 3.12.0 is out! Featuring support for SemVer constraints for plugins,
a new --arch
flag for hc ready
, support for managing the plugin cache with
hc cache plugin
, and more. With 3.12.0, Hipcheck now requires glibc
2.35
or newer on x86 Linux hosts.
For the unfamiliar, Hipcheck is a tool to help open source software users decide what dependencies to use by assessing project practices and by detecting possible malicious activity.
If you have Hipcheck 3.11.0 installed through our official installer,
run hc update
to get the latest version, or hc update --version 3.12.0
to
get 3.12.0.
For more options, follow our Install Instructions.
mold
for Linking on LinuxIn 3.12.0, we've made two changes which impact our prebuilt Linux binaries and building on Linux hosts.
First, our GitHub Actions runner for building x86 Linux binaries for new releases has moved from Ubuntu 20.04 to Ubuntu 22.04. This is because GitHub is phasing out support for Ubuntu 20.04 in their free actions tier. GitHub's policy is to support the two most recent stable releases of Ubuntu for free, and with Ubuntu 24.04 released last year, GitHub has begun to sunset 20.04.
For users this means our prebuilt Linux binaries are now built with glibc version 2.35-0ubuntu3.9, which is an Ubuntu-patched variant of glibc 2.35. Since glibc versions are forward-compatible but not backward-compatible, our prebuilt binaries should link and run on any system with glibc 2.35 or newer, but not with any older versions.
To use our prebuilt binaries on Ubuntu 20.04, you'll need to install a
new-enough version of glibc, which can be done by upgrading the libc6
package to its latest version.
You'll likely still be able to build Hipcheck yourself on Ubuntu 20.04 in the near-term. Though we won't be testing it in CI anymore and can't guarantee continued compatibility.
Our second change is to start using mold
for linking on x86 Linux
hosts. mold
is a highly parallel linker, which in our testing has improved
the performance of our whole-workspace Linux builds by around 30% in CI.
This change won't matter for anyone using prebuilt binaries from our releases.
If you're building Hipcheck yourself, you'll either need to install mold
or remove it as the configured linker by deleting the following block from
.cargo/config.toml
in Hipcheck's source repository:
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
In the future, we'd like to also offer prebuilt binaries compiled with musl libc instead of glibc, and to perform regular CI testing with musl. For more updates you can follow our open issue on musl support.
When you specify plugins to use in your policy file, you include a version
attribute which specifies what version to use for that plugin. Previously, this
only accepted a fully-specified SemVer version, of the form X.Y.Z
. This was
overly restrictive, and meant that if a plugin had a new patch version you
would not get it without manually updating the requested version in your policy
file.
With 3.12.0, we now accept a set of "version constraints," specifically the
set defined in the Rust semver
crate, which implements the set of operators
accepted by Cargo, Rust's standard build tool. Those operators
are:
^1.2.3
): Permits any SemVer-compatible updates.~1.2.3
): Permits only minimal updates.
Specifically:
~X.Y.Z
or ~X.Y
: Only patch updates are allowed.~X
: Minor or patch updates are allowed.1.2.*
): Allows any version where the
wildcard is placed. Only one wildcard allowed at a time, *
is not acceptable
as a version requirement.>= 1.2.3
): Specifies a version range,
which may be bounded or unbounded, using the <
, <=
, >
, >=
and =
operators.For any of the above, multiple bounds can be provided, separated by a comma.
For example: >= 1.0.0, < 2.0.0
, which would be equivalent to ~1
.
Our one difference from Cargo is that, for backwards-compatibility with our
prior version-solving approach, bare versions specified without an operator
will be treated as an equality comparison requirement (prepended
with an =
) instead of being treated as a
default requirement.
We've updated the default version constraints in our starter policy file to use caret requirements, so users automatically get the latest available patch version, instead of the prior equality comparison requirement.
This change also applies for plugins specifying their own dependencies in
their plugin manifest file (plugin.kdl
). Those dependencies may now also be
set with SemVer constraints in addition to fully-specified SemVer versions.
--arch
flag for hc ready
The hc ready
command exists to let you check that your installation of
Hipcheck and the plugins specified in your policy file are ready to run. It
does this by resolving your plugins, downloading them if necessary, starting
them up, and then attempting to configure them with any configuration items
from your policy file and reporting relevant errors.
To get the right plugins, Hipcheck needs to know your host's "target triple." That's the string that explains what kind of host it is, usually including information like the Instruction Set Architecture (ISA) and host operating system, though they can have other information as well. By default, Hipcheck infers the target triple for the current host, but this inference can be wrong. In that case, Hipcheck might download plugins you're not able to run on your current platform.
The --arch
flag, which already exists for the hc check
subcommand, has been
added to hc ready
. This flag takes a target triple argument, which will be
used for plugin matching instead of being inferred by Hipcheck. In general,
we use the same target triples as those tracked by the Rust programming
language project.
hc cache plugin
Hipcheck maintains two caches today: the "target cache," which contains copies of the source repositories of targets Hipcheck analyses, and the "plugin cache" which contains copies of plugins.
Since we don't currently do anything to actively reduce the size of these
caches, they will grow over time as you analyze more targets or use more
plugins. While we're likely to add some automated cache eviction in the future,
for now we offer the hc cache
subcommand to manage these caches and remove
entries that are no longer needed.
In 3.12.0, we're introducing the hc cache plugin
subcommand, which is
specifically for managing cached plugins. It has two subcommands:
hc cache plugin list
: List cached plugins, their version, and when they
were last modified.hc cache plugin delete
: Remove plugins from the plugin cache.The arguments for hc cache plugin delete
are similar to the ones on
hc cache target delete
, and include:
-s
/--strategy
: How to select plugins to delete, and optionally how many.-N
/--name
: Plugin name to filter by.-P
/--publisher
: Publisher name to filter by.For example, to delete the three least-recently-used plugins from MITRE, you'd run:
$ hc cache plugin delete -s 'oldest 3' -P 'mitre'
Previously, the hc cache
command implicitly manages the target cache. With
the introduction of the hc cache plugin
command to manage the plugin cache,
all operations previously on hc cache
have been moved to hc cache target
.
All of the plugins MITRE ships today for Hipcheck are written in Rust and ship as pre-built binaries for our supported platforms, and they run as standalone programs except for their dependency on a sufficiently-recent version of libc from the system, or on CLI tools whose presence is checked during plugin configuration. This has worked well-enough for us, but until now we haven't had a decent answer for how to bundle and distribute plugins where you don't want to rely on the presence of dependencies on the host system.
With 3.12.0, we've introduced new documentation for how to package and ship
containerized plugins, including a new example found at
tests/test-plugins/activity-container
in the Hipcheck source repository,
and we've updated the Rust Hipcheck SDK to make it easier to define a plugin
which can run inside of a container.
The key challenge for packaging a container-based plugin is making the CLI
invocation for starting the plugin comply with Hipcheck's CLI protocol by
accepting a --port
flag to indicate what port the program should listen on.
In our new example plugin, we do this with a shell script that wraps starting
the plugin container and passess along the flag appropriately.
Within the SDK, we also now expose an API for launching a plugin by having it
listen on 0.0.0.0
instead of listening on the local loopback address
127.0.0.1
.
We plan to continue to improve the story around shipping plugins with more complex dependencies, and to further improve documentation and tooling for this setup.
So far we've only shipped a plugin SDK for Rust, because Hipcheck itself is written in Rust and so we needed an SDK to use ourselves when we split our existing analyses out into plugins last year.
However, the design of the plugin system is language-agnostic. So long as a program speaks the plugin protocol it can be used as a plugin.
We're currently working on a plugin SDK for Python. It's still unfinished
and experimental, but you can find it at sdk/python
in the Hipcheck source
repository, and we've reserved the package name hipcheck-sdk
on PyPI, which
we intend to start publishing to soon.
If you're interested in developing a plugin in Python, feel free to try out the SDK. We'd love to hear feedback from people who do try it so we can address any deficiencies or awkwardness in the API or in the experience of shipping plugins written in a language that's not ahead-of-time compiled like Rust!
Part of the design of the plugin protocol is that plugins are intended to log relevant information during their execution, which can then be collected and managed by Hipcheck. Previously, this was done on an ad-hoc basis, and the plugin protocol defined no formal method for Hipcheck to control what level of information plugins should log, no clear format for logs from plugins, and no action taken by Hipcheck to actually gather logs that plugins produce.
With 3.12.0, we've introduced three key changes:
--log-level
command
line argument for all plugins, which accepts a string detailing the
threshold log level to produce, and updated our own first-party plugins to
respect this flag.Let's cover each of these in order:
The new --log-level
flag takes one of the following levels, in order:
Off
: Do not produce logs.Error
: Log unrecoverable error state information.Warn
: Log recoverable warning information.Info
: Log general information.Debug
: Log debugging information.Trace
: Log detailed tracing information.Each log level includes entries from the levels above it.
Plugins are expected to accept and correctly handle these levels, only producing log entries consistent with the provided log level threshold.
The log format expected is a single-line JSON object with three fields:
"level"
: the log level string indicating what log level the entry is."target"
: a string indicating what module in the plugin produced the
log entry, with segments in any module path separated by ::
."fields"
: an object with one field:
"message"
: a string with the actual content of the log entry.We reserve the possibility of including more fields under the fields
object
in the future.
Finally, Hipcheck now gathers this log information and forwards it based on the
user's requested log level and any user-provided filtering. All of this is
taken from the HC_LOG
environment variable, which is used to configure
Hipcheck's logging generally, including logging collected from plugins.
Altogether, these changes should make it easier to debug issues in Hipcheck by incorporating any logging information produced by plugins.
We're always looking for new contributors! If you'd like to learn more about Hipcheck and get involved in contributing, please checkout our Roadmap and feel free to get in touch with us through our Discussions board!
As always, we want to say a big "Thank you!" to everyone who supports the project at MITRE, to CISA for sponsoring our current work on it, to our prior government sponsors who have helped advance Hipcheck, and to everyone who has contributed, given feedback, or encouraged us in building it.
The following team members contributed to this release: