require 'date' # A version 1 GLSA class GLSAv1 attr_reader :id, :title, :synopsis, :product, :date, :revised, :revision, :bugs, :access, :packages, :background, :description, :severity, :impact, :workaround, :resolution, :references def parse(xml) @id = xml.root['id'] @title = text_content xml, '/glsa/title/text()' @synopsis = text_content xml, '/glsa/synopsis/text()' @product = text_content xml, '/glsa/product/text()' @date = DateTime.parse(xml.xpath('/glsa/announced/text()').first.content) if xml.xpath('/glsa/revised').first['count'].nil? @revised, @revision = xml.xpath('/glsa/revised/text()').first.content.split(': ') else @revised = xml.xpath('/glsa/revised/text()').first.content @revision = xml.xpath('/glsa/revised').first['count'] end @revised = DateTime.parse(@revised) @bugs = xml.xpath('/glsa/bug/text()').map { |bug_node| bug_node.content.to_i } @access = xml.xpath('/glsa/access/text()').first.content @packages = {} xml.xpath('/glsa/affected/package').each do |package| @packages[package['name'] + ':' + package['arch']] = { auto: package['auto'] == 'yes', unaffected: package.xpath('./unaffected').map { |ver| [ver['range'], ver.content] }, vulnerable: package.xpath('./vulnerable').map { |ver| [ver['range'], ver.content] } } end @background = xml_content xml, '/glsa/background' @description = xml_content xml, '/glsa/description' @severity = xml.xpath('/glsa/impact').first['type'] @impact = xml_content xml, '/glsa/impact' @workaround = xml_content xml, '/glsa/workaround' @resolution = xml_content xml, '/glsa/resolution' @references = xml.xpath('/glsa/references/uri').map { |uri| [uri.content, uri['link']] } self end private def xml_content(xml, xpath) xml.xpath(xpath).first.children.to_xml.strip rescue '' end def text_content(xml, xpath) xml.xpath(xpath).first.content rescue '' end end