Linux.Debian.Packages

List all packages installed on the system, both deb packages and “snaps”. 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 in files).

The following columns are parsed from the DPKG status file:

  • Package
  • InstalledSize
  • Version
  • Source
  • _Description
  • Architecture

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

  • Name
  • _Summary
  • _Description
  • 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
description: |
 List all packages installed on the system, both deb packages and "snaps".
 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
 in files).

 The following columns are parsed from the DPKG status file:

  - Package
  - InstalledSize
  - Version
  - Source
  - _Description
  - Architecture

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

 - Name
 - _Summary
 - _Description
 - 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 deamon 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

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 start with
        Package and end with \n\n.
        Then parse each record using multiple RegExs.
     */
     LET packages = SELECT parse_string_with_regex(
         string=Record,
         regex=['Package:\\s(?P<Package>.+)',
                '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,
            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)

     SELECT * FROM foreach(
         row=SnapSocketCheck,
         query={
           SELECT name AS Name,
                  summary AS _Summary,
                  description AS _Description,
                  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: |
          /*
          ## Combined results
          */
          LET ColumnTypes <= dict(`_Description`='nobreak')

          SELECT *
          FROM chain(
            debs={
              SELECT Package AS Name,
                     'deb' AS Type,
                     InstalledSize,
                     Version,
                     _Description,
                     Architecture
              FROM source(artifact="Linux.Debian.Packages/DebPackages")
            },
            snaps={
              SELECT Name,
                     'snap' AS Type,
                     InstalledSize,
                     Version,
                     _Description,
                     NULL AS Architecture
              FROM source(artifact="Linux.Debian.Packages/Snaps")
            })