Skip to content

Commit

Permalink
Merge pull request #80 from dermetfan/runtime-deps
Browse files Browse the repository at this point in the history
Scan only runtime dependencies
  • Loading branch information
zimbatm authored Apr 2, 2024
2 parents 6bcc1bd + cea4e89 commit ebd8ea8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 13 deletions.
17 changes: 12 additions & 5 deletions src/vulnix/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def init_logging(verbose):
logging.basicConfig(level=logging.WARNING)


def populate_store(store, gc_roots, profiles, paths, requisites=True):
def populate_store(store, gc_roots, profiles, paths):
"""Load derivations from nix store depending on cmdline invocation."""
if gc_roots:
store.add_gc_roots()
Expand Down Expand Up @@ -96,6 +96,9 @@ def run(nvd, store):
@click.option('-r/-R', '--requisites/--no-requisites', default=True,
help='Yes: determine transitive closure. No: examine just the '
'passed derivations (default: yes).')
@click.option('-C', '--closure', is_flag=True,
help='Examine the closure of an output path '
'(runtime dependencies). Implies --no-requisites.')
@click.option('-m', '--mirror',
help='Mirror to fetch NVD archives from. Default: {}.'.format(
DEFAULT_MIRROR),
Expand All @@ -115,12 +118,16 @@ def run(nvd, store):
@click.option('-F', '--notfixed', is_flag=True,
help='(obsolete; kept for compatibility reasons)')
def main(verbose, gc_roots, system, from_file, profile, path, mirror,
cache_dir, requisites, whitelist, write_whitelist, version, json,
show_whitelisted, show_description, default_whitelist, notfixed):
cache_dir, requisites, closure, whitelist, write_whitelist,
version, json, show_whitelisted, show_description,
default_whitelist, notfixed):
if version:
print('vulnix ' + pkg_resources.get_distribution('vulnix').version)
sys.exit(0)

if (closure):
requisites = False

if not (gc_roots or system or profile or path or from_file):
howto()
sys.exit(3)
Expand All @@ -138,7 +145,7 @@ def main(verbose, gc_roots, system, from_file, profile, path, mirror,
for wl in wh_sources:
whitelist.merge(Whitelist.load(wl))
with Timer('Load derivations'):
store = Store(requisites)
store = Store(requisites, closure)
if from_file:
if from_file.name.endswith('.json'):
_log.debug("loading packages.json")
Expand All @@ -147,7 +154,7 @@ def main(verbose, gc_roots, system, from_file, profile, path, mirror,
for drv in from_file.readlines():
paths.append(drv.strip())
else:
populate_store(store, gc_roots, profile, paths, requisites)
populate_store(store, gc_roots, profile, paths)
with NVD(mirror, cache_dir) as nvd:
with Timer('Update NVD data'):
nvd.update()
Expand Down
52 changes: 44 additions & 8 deletions src/vulnix/nix.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

class Store(object):

def __init__(self, requisites=True):
def __init__(self, requisites=True, closure=False):
self.requisites = requisites
self.closure = closure
self.derivations = set()
self.experimental_flag_needed = None

Expand Down Expand Up @@ -58,11 +59,12 @@ def _call_nix(self, args):
'nix-command'] + args)
return call(['nix'] + args)

def _find_deriver(self, path):
def _find_deriver(self, path, qpi_deriver=None):
if path.endswith('.drv'):
return path
# Deriver from QueryPathInfo
qpi_deriver = call(['nix-store', '-qd', path]).strip()
if qpi_deriver is None:
qpi_deriver = call(['nix-store', '-qd', path]).strip()
_log.debug('qpi_deriver: %s', qpi_deriver)
if qpi_deriver and qpi_deriver != 'unknown-deriver' and p.exists(
qpi_deriver):
Expand All @@ -86,18 +88,52 @@ def _find_deriver(self, path):
'Cannot determine deriver. Is this really a path into the '
'nix store?', path)

def _find_outputs(self, path):
if not path.endswith('.drv'):
return [path]

result = []
for drv in json.loads(
self._call_nix(['show-derivation', path])
).values():
for output in drv.get('outputs').values():
result.append(output.get('path'))
return result

def add_path(self, path):
"""Add the closure of all derivations referenced by a store path."""
if not p.exists(path):
raise RuntimeError('path `{}` does not exist - cannot load '
'derivations referenced from it'.format(path))
_log.debug('Loading derivations referenced by "%s"', path)
deriver = self._find_deriver(path)
if self.requisites:
for candidate in call(['nix-store', '-qR', deriver]).splitlines():
self.update(candidate)

if self.closure:
for output in self._find_outputs(path):
for candidate in map(
# We cannot use the `deriver` field directly because
# like from `nix-store -qd` that path may not exist.
# However, we know that if it is not present
# the path has no deriver because it is a
# derivation input source so we can skip it.
lambda p: self._find_deriver(
p.get('path'),
qpi_deriver=p.get('deriver')
) if p.get('deriver') is not None else None,
json.loads(
self._call_nix(['path-info', '-r', '--json', output])
)
):
if candidate is not None:
self.update(candidate)
else:
self.update(deriver)
deriver = self._find_deriver(path)
if self.requisites:
for candidate in call([
'nix-store', '-qR', deriver
]).splitlines():
self.update(candidate)
else:
self.update(deriver)

def update(self, drv_path):
if not drv_path.endswith('.drv'):
Expand Down

0 comments on commit ebd8ea8

Please sign in to comment.