Skip to content
Please update to the latest release 0.77.3 to address Multiple CVEs.
Linux.Debian.Packages

Linux.Debian.Packages

Queries dpkg and snapd to list installed deb and snap packages.

The installed deb package information is fetched from the DPKG status file, while the snap package list is fetched from the snap daemon through a UNIX socket HTTP call (since detailed snap package information is not easily found in files).

The following columns are parsed from the DPKG status file:

  • Package
  • _SelectionState (install, hold, deinstall, purge, unknown)
  • _Flag (ok, reinstreq)
  • State (not-installed, config-files, half-installed, unpacked, half-configured, triggers-awaited, triggers-pending, installed)
  • InstalledSize
  • Version
  • Source
  • _Description
  • Architecture

The following columns are parsed from the snap package response (/v2/snaps):

  • Name
  • _Summary
  • _Description
  • Status (available, installed, active, removed, priced)
  • InstalledSize
  • Publisher
  • InstalledAt
  • Version
  • Channel

Both package sources provide more information than this and, and the artifact can easily be modified to include more details.


name: Linux.Debian.Packages
author: Andreas Misje – @Misje
description: |
  Queries `dpkg` and `snapd` to list installed deb and snap packages.

  The installed deb package information is fetched from the DPKG
  status file, while the snap package list is fetched from the snap
  daemon through a UNIX socket HTTP call (since detailed snap package
  information is not easily found in files).

  The following columns are parsed from the DPKG status file:

  - Package
  - _SelectionState (install, hold, deinstall, purge, unknown)
  - _Flag (ok, reinstreq)
  - State (not-installed, config-files, half-installed, unpacked,
    half-configured, triggers-awaited, triggers-pending, installed)
  - InstalledSize
  - Version
  - Source
  - _Description
  - Architecture

  The following columns are parsed from the snap package response (/v2/snaps):

  - Name
  - _Summary
  - _Description
  - Status (available, installed, active, removed, priced)
  - InstalledSize
  - Publisher
  - InstalledAt
  - Version
  - Channel

  Both package sources provide more information than this and, and the artifact
  can easily be modified to include more details.

parameters:
  - name: linuxDpkgStatus
    description: The DPKG status file to read deb package information from
    default: /var/lib/dpkg/status

  - name: snapdSocket
    description: |
     The location of the snap daemon UNIX socket, used for fetching the snap
     list through a HTTP API call. If snap is not used, the failed query
     response will simply be ignored.
    default: /run/snapd.socket

implied_permissions:
  - NETWORK

precondition: |
  SELECT OS
  FROM info()
  WHERE OS = 'linux'

sources:
  - name: DebPackages
    notebook:
      - type: none

    query: |
      LET ColumnTypes <= dict(`_Description`='nobreak')


      /* First pass - split file into records starting with
         Package and ending with \n\n.
         Then parse each record using multiple regular expressions.
      */
      LET packages = SELECT
          parse_string_with_regex(
            string=Record,
            regex=['''Package:\s(?P<Package>.+)''',
                   '''Status:\s(?P<SelectionState>\S+)\s(?P<Flag>\S+)\s(?P<State>\S+)''',
                   '''Installed-Size:\s(?P<InstalledSize>.+)''',
                   '''Version:\s(?P<Version>.+)''',
                   '''Source:\s(?P<Source>.+)''',
                   '''Description:\s+(?P<Description>.+(\n\s+.+)*)''',
                   '''Architecture:\s(?P<Architecture>.+)''']) AS Record
        FROM parse_records_with_regex(
          file=linuxDpkgStatus,
          regex='''(?sm)^(?P<Record>Package:.+?)\n\n''')

      SELECT
          Record.Package AS Package,
          Record.SelectionState AS _SelectionState,
          Record.Flag AS _Flag,
          Record.State AS State,
          humanize(bytes=atoi(string=Record.InstalledSize)) AS InstalledSize,
          Record.Version AS Version,
          Record.Source AS Source,
          regex_replace(source=Record.Description, re='''^\s+\.$''') AS _Description,
          Record.Architecture AS Architecture
      FROM packages

  - name: Snaps
    query: |
      LET ColumnTypes <= dict(`_Summary`='nobreak', `_Description`='nobreak')

      LET SnapSocketCheck = SELECT parse_json(data=Content).result AS Result
        FROM http_client(url=snapdSocket + ':unix/v2/snaps')
        WHERE Response = 200 OR NOT log(message="Error fetching snap: %v",
                                        args=Content)

      // linter: symbol_mask_warn:version
      SELECT *
      FROM foreach(row=SnapSocketCheck,
                   query={
          SELECT name AS Name,
                 summary AS _Summary,
                 description AS _Description,
                 status AS Status,
                 humanize(bytes=`installed-size`) AS InstalledSize,
                 publisher.`display-name` AS Publisher,
                 timestamp(string=`install-date`) AS InstalledAt,
                 version AS Version,
                 channel AS Channel,
                 id AS PackageId
          FROM foreach(row=Result)
        })

    notebook:
      - type: vql
        template: |
          LET ColumnTypes <= dict(`_Description`='nobreak')

          /*
          # All traces of installed deb packages

          Packages that has either been

            - Removed/purged, but it has once been installed ("not-installed")
            - Removed, but with configuration files left behind ("config-files")
            - Partially installed ("half-installed", "unpacked", "half-configured",
              "triggers-awaited", "triggers-pending"))
            - Installed ("installed")

          A package that has never been installed will not have made an entry in this
          database.
          */
          SELECT
              *
          FROM source(
            source="DebPackages")

          /*
          # All traces of installed snaps

          Snaps on the system should either be

            - installed
            - active
            - removed

          Two additional statuses are possible:

            - available
            - priced
          */
          SELECT
              *
          FROM source(
            source="Snaps")

          /*
          # All installed packages (deb and snap combined)

          Only fully installed packages are included.
          */
          SELECT
              *
          FROM chain(
            debs={
              SELECT
              Package AS Name,
              'deb' AS Type,
              InstalledSize,
              Version,
              _Description,
              Architecture
              FROM source(
                source="DebPackages")
              WHERE NOT State IN ("not-installed", "config-files")
            },
            snaps={
              SELECT
              Name,
              'snap' AS Type,
              InstalledSize,
              Version,
              _Description,
              NULL AS Architecture
              FROM source(
                source="Snaps")
              WHERE Status IN ("installed", "active")
            })