def _main_with_app_context(): if 'repair-ts' in sys.argv: _repair_ts() if 'repair-csum' in sys.argv: _repair_csum() if 'fsck' in sys.argv: _fsck() if 'ensure' in sys.argv: _ensure_tests() if 'firmware' in sys.argv: _regenerate_and_sign_firmware() if 'metadata' in sys.argv: _regenerate_and_sign_metadata() if 'metadata-embargo' in sys.argv: _regenerate_and_sign_metadata(only_embargo=True) if 'purgedelete' in sys.argv: _delete_embargo_obsoleted_fw() _purge_old_deleted_firmware() if 'fwchecks' in sys.argv: _check_firmware() _yara_query_all() _user_disable_notify() _user_disable_actual() if 'stats' in sys.argv: val = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=1)) _generate_stats_for_datestr(val) _generate_stats() if 'statsmigrate' in sys.argv: for days in range(1, 720): val = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=days)) _generate_stats_for_datestr(val)
def route_year(ts=3): """ A analytics screen to show information about users """ # this is somewhat klunky data = [] now = datetime.date.today() - datetime.timedelta(days=1) for _ in range(12 * ts): datestrold = _get_datestr_from_datetime(now) now -= datetime.timedelta(days=30) datestrnew = _get_datestr_from_datetime(now) analytics = db.session.query(Analytic).\ filter(Analytic.datestr < datestrold).\ filter(Analytic.datestr > datestrnew).\ all() # sum up all the totals for each day in that month cnt = 0 for analytic in analytics: cnt += analytic.cnt data.append(int(cnt)) return render_template('analytics-year.html', category='analytics', labels_months=_get_chart_labels_months(ts)[::-1], data_months=data[::-1])
def route_vendor(timespan_days=30): """ A analytics screen to show information about users """ # get data for this time period cnt_total = {} cached_cnt = {} yesterday = datetime.date.today() - datetime.timedelta(days=1) datestr_start = _get_datestr_from_datetime(yesterday - datetime.timedelta(days=timespan_days)) datestr_end = _get_datestr_from_datetime(yesterday) for ug in db.session.query(AnalyticVendor).\ filter(and_(AnalyticVendor.datestr > datestr_start, AnalyticVendor.datestr <= datestr_end)): display_name = ug.vendor.display_name key = str(ug.datestr) + display_name if key not in cached_cnt: cached_cnt[key] = ug.cnt if not display_name in cnt_total: cnt_total[display_name] = ug.cnt continue cnt_total[display_name] += ug.cnt # find most popular user agent strings most_popular = [] for key, value in sorted(iter(cnt_total.items()), key=lambda k_v: (k_v[1], k_v[0]), reverse=True): most_popular.append(key) if len(most_popular) >= 6: break # generate enough for the template datasets = [] palette = [ 'ef4760', # red 'ffd160', # yellow '06c990', # green '2f8ba0', # teal '845f80', # purple 'ee8510', # orange ] idx = 0 for value in most_popular: dataset = {} dataset['label'] = value dataset['color'] = palette[idx % 6] idx += 1 data = [] for i in range(timespan_days): datestr = _get_datestr_from_datetime(yesterday - datetime.timedelta(days=i)) key = str(datestr) + value dataval = 'NaN' if key in cached_cnt: dataval = str(cached_cnt[key]) data.append(dataval) dataset['data'] = '[' + ', '.join(data[::-1]) + ']' datasets.append(dataset) return render_template('analytics-vendor.html', category='analytics', labels_user_agent=_get_chart_labels_days(timespan_days)[::-1], datasets=datasets)
def route_show(firmware_id): """ Show firmware information """ # get details about the firmware fw = db.session.query(Firmware).\ filter(Firmware.firmware_id == firmware_id).\ first() if not fw: flash('No firmware matched!', 'danger') return redirect(url_for('firmware.route_firmware')) # security check if not fw.check_acl('@view'): flash('Permission denied: Insufficient permissions to view firmware', 'danger') return redirect(url_for('firmware.route_firmware')) # get data for the last month or year graph_data = [] graph_labels = None if fw.check_acl('@view-analytics') and not fw.do_not_track: if fw.timestamp.replace( tzinfo=None) > datetime.datetime.today() - datetime.timedelta( days=30): datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=31)) data = db.session.query(AnalyticFirmware.cnt).\ filter(AnalyticFirmware.firmware_id == fw.firmware_id).\ filter(AnalyticFirmware.datestr > datestr).\ order_by(AnalyticFirmware.datestr.desc()).all() graph_data = [r[0] for r in data] graph_data = graph_data[::-1] graph_labels = _get_chart_labels_days(limit=len(data))[::-1] else: datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=360)) data = db.session.query(AnalyticFirmware.cnt).\ filter(AnalyticFirmware.firmware_id == fw.firmware_id).\ filter(AnalyticFirmware.datestr > datestr).\ order_by(AnalyticFirmware.datestr.desc()).all() # put in month-sized buckets for _ in range(12): graph_data.append(0) cnt = 0 for res in data: graph_data[int(cnt / 30)] += res[0] cnt += 1 graph_data = graph_data[::-1] graph_labels = _get_chart_labels_months()[::-1] return render_template('firmware-details.html', category='firmware', fw=fw, graph_data=graph_data, graph_labels=graph_labels)
def _run_test_on_shard(self, test, shard): # only Intel μcode supported at this time if shard.guid != '3f0229ad-0a00-5269-90cf-0a45d8781b72': return # get required attributes cpuid = shard.get_attr_value('cpuid') if not cpuid: return platform = shard.get_attr_value('platform') if not platform: return version = shard.get_attr_value('version') if not version: return datestr = shard.get_attr_value('yyyymmdd') if not datestr: return # don't expect vendors to include microcode that was released *after* # the file was uploaded to the LVFS datestr_upload = str(_get_datestr_from_datetime(shard.md.fw.timestamp)) # load database mcefn = self.get_setting('microcode_mcedb_path', required=True) if not os.path.exists(mcefn): test.add_fail('cannot locate database: {}'.format(mcefn)) return conn = sqlite3.connect(mcefn) c = conn.cursor() c.execute( 'SELECT version, yyyymmdd FROM Intel WHERE cpuid=? AND ' 'platform=? AND version>? AND yyyymmdd>? ORDER BY version LIMIT 1', (cpuid, platform, version, datestr_upload)) res = c.fetchone() if res: ( newest_version, newset_datestr, ) = res print('CPUID:{:#x} Platform:{:#x} version {:#x} (released on {}) may be older ' 'than latest released version {:#x} (released on {})'.\ format(int(cpuid, 16), int(platform, 16), int(version, 16), datestr, int(newest_version, 16), newset_datestr)) claim = db.session.query(Claim)\ .filter(Claim.kind == 'old-microcode')\ .first() if claim: shard.md.add_claim(claim) c.close()
def run_cron_stats(): from lvfs import app from cron import _generate_stats_for_datestr, _generate_stats from lvfs.models import _get_datestr_from_datetime with app.test_request_context(): with io.StringIO() as buf, redirect_stdout(buf): _generate_stats_for_datestr(_get_datestr_from_datetime(datetime.date.today())) _generate_stats() stdout = buf.getvalue() assert 'generated' in stdout, stdout
def _generate_stats_for_firmware(fw, datestr): # is datestr older than firmware if datestr < _get_datestr_from_datetime(fw.timestamp): return # count how many times any of the firmware files were downloaded cnt = _execute_count_star(db.session.query(Client).\ filter(Client.firmware_id == fw.firmware_id).\ filter(Client.datestr == datestr)) analytic = AnalyticFirmware(fw.firmware_id, datestr, cnt) db.session.add(analytic)
def route_day(offset=1): """ A analytics screen to show information about users """ now = datetime.date.today() - datetime.timedelta(days=offset) datestr = _get_datestr_from_datetime(now) print(datestr) data = [0] * 24 for ts, in db.session.query(Client.timestamp)\ .filter(Client.datestr == datestr): data[ts.hour] += 1 return render_template('analytics-month.html', category='analytics', labels_days=_get_chart_labels_hours(), data_days=data)
def run_cron_stats(): from lvfs import app from lvfs.main.utils import _regenerate_metrics from lvfs.reports.utils import _regenerate_reports from lvfs.analytics.utils import _generate_stats_for_datestr from lvfs.shards.utils import _regenerate_shard_infos from lvfs.models import _get_datestr_from_datetime with app.test_request_context(): with io.StringIO() as buf, redirect_stdout(buf): _generate_stats_for_datestr( _get_datestr_from_datetime(datetime.date.today())) _regenerate_metrics() _regenerate_reports() _regenerate_shard_infos() stdout = buf.getvalue() assert 'generated' in stdout, stdout
def upgrade(): if 1: op.create_table('analytics_vendor', sa.Column('analytic_id', sa.Integer(), nullable=False), sa.Column('datestr', sa.Integer(), nullable=True), sa.Column('vendor_id', sa.Integer(), nullable=False), sa.Column('cnt', sa.Integer(), nullable=True), sa.ForeignKeyConstraint( ['vendor_id'], ['vendors.vendor_id'], ), sa.PrimaryKeyConstraint('analytic_id'), sa.UniqueConstraint('analytic_id'), mysql_character_set='utf8mb4') op.create_index(op.f('ix_analytics_vendor_datestr'), 'analytics_vendor', ['datestr'], unique=False) op.create_index(op.f('ix_analytics_vendor_vendor_id'), 'analytics_vendor', ['vendor_id'], unique=False) # get all the vendor firmwares vendor_fws = {} for v in db.session.query(Vendor): fw_ids = [] for fw in v.fws: fw_ids.append(fw.firmware_id) if not fw_ids: continue vendor_fws[v.vendor_id] = fw_ids # generate the last year of data for each vendor now = datetime.date.today() - datetime.timedelta(days=1) for _ in range(365): datestr = _get_datestr_from_datetime(now) for vendor_id in vendor_fws: print('processing %s:%s' % (datestr, vendor_id)) fw_ids = vendor_fws[vendor_id] cnt = _execute_count_star(db.session.query(Client).\ filter(Client.firmware_id.in_(fw_ids)).\ filter(Client.datestr == datestr)) db.session.add(AnalyticVendor(vendor_id, datestr, cnt)) now -= datetime.timedelta(days=1) db.session.commit()
def route_dashboard(): user = db.session.query(User).filter( User.username == '*****@*****.**').first() settings = _get_settings() default_admin_password = False if user and user.verify_password('Pa$$w0rd'): default_admin_password = True # get the 10 most recent firmwares fws = db.session.query(Firmware).\ filter(Firmware.user_id == g.user.user_id).\ join(Remote).filter(Remote.name != 'deleted').\ order_by(Firmware.timestamp.desc()).limit(10).all() download_cnt = 0 devices_cnt = 0 appstream_ids = {} for fw in g.user.vendor.fws: download_cnt += fw.download_cnt for md in fw.mds: appstream_ids[md.appstream_id] = fw devices_cnt = len(appstream_ids) # this is somewhat klunky data = [] datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=31)) for cnt in db.session.query(AnalyticVendor.cnt).\ filter(AnalyticVendor.vendor_id == g.user.vendor.vendor_id).\ filter(AnalyticVendor.datestr > datestr).\ order_by(AnalyticVendor.datestr): data.append(int(cnt[0])) return render_template( 'dashboard.html', fws_recent=fws, devices_cnt=devices_cnt, download_cnt=download_cnt, labels_days=_get_chart_labels_days(limit=len(data))[::-1], data_days=data, server_warning=settings.get('server_warning', None), category='home', default_admin_password=default_admin_password)
def _generate_stats_for_vendor(v, datestr): # is datestr older than firmware if not v.ctime: return if datestr < _get_datestr_from_datetime(v.ctime - datetime.timedelta(days=1)): return # get all the firmware for a specific vendor fw_ids = [fw.firmware_id for fw in v.fws] if not fw_ids: return # count how many times any of the firmware files were downloaded cnt = _execute_count_star(db.session.query(Client).\ filter(Client.firmware_id.in_(fw_ids)).\ filter(Client.datestr == datestr)) analytic = AnalyticVendor(vendor_id=v.vendor_id, datestr=datestr, cnt=cnt) print('adding %s:%s = %i' % (datestr, v.group_id, cnt)) db.session.add(analytic)
def upgrade(): if 1: op.add_column('clients', sa.Column('datestr', sa.Integer(), nullable=True)) op.create_index(op.f('ix_clients_datestr'), 'clients', ['datestr'], unique=False) # we have to break this into chunks to avoid having 4GB+ of Client objects cnt = 0 while True: clients = db.session.query(Client).filter( Client.datestr == None).limit(10000).all() if not clients: break for c in clients: c.datestr = _get_datestr_from_datetime(c.timestamp) cnt += 1 if cnt % 1000 == 0: print(cnt) db.session.commit() db.session.commit()
def route_month(): """ A analytics screen to show information about users """ # this is somewhat klunky data = [] now = datetime.date.today() - datetime.timedelta(days=1) for _ in range(30): datestr = _get_datestr_from_datetime(now) analytic = db.session.query(Analytic).\ filter(Analytic.datestr == datestr).\ first() if analytic: data.append(int(analytic.cnt)) else: data.append(0) # back one day now -= datetime.timedelta(days=1) return render_template('analytics-month.html', category='analytics', labels_days=_get_chart_labels_days()[::-1], data_days=data[::-1])
def serveStaticResource(resource): """ Return a static image or resource """ # ban the robots that ignore robots.txt user_agent = request.headers.get('User-Agent') if user_agent: if user_agent.find('MJ12BOT') != -1: abort(403) if user_agent.find('ltx71') != -1: abort(403) if user_agent.find('Sogou') != -1: abort(403) # log certain kinds of files if resource.endswith('.cab'): # increment the firmware download counter fw = db.session.query(Firmware).\ filter(Firmware.filename == os.path.basename(resource)).\ options(joinedload('limits')).\ options(joinedload('vendor')).first() if not fw: abort(404) # check the user agent isn't in the blocklist for this firmware for md in fw.mds: req = db.session.query(Requirement).\ filter(Requirement.component_id == md.component_id).\ filter(Requirement.kind == 'id').\ filter(Requirement.value == 'org.freedesktop.fwupd').\ first() if req and user_agent and not _user_agent_safe_for_requirement( user_agent): return Response(response='detected fwupd version too old', status=412, mimetype="text/plain") # check the firmware vendor has no country block if fw.banned_country_codes: banned_country_codes = fw.banned_country_codes.split(',') geo = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) country_code = geo.country_code_by_addr(_get_client_address()) if country_code and country_code in banned_country_codes: return Response( response='firmware not available from this IP range', status=451, mimetype="text/plain") # check any firmware download limits for fl in fw.limits: if not fl.user_agent_glob or fnmatch.fnmatch( user_agent, fl.user_agent_glob): datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(1)) cnt = _execute_count_star(db.session.query(Client).\ filter(Client.firmware_id == fw.firmware_id).\ filter(Client.datestr >= datestr)) if cnt >= fl.value: response = fl.response if not response: response = 'Too Many Requests' resp = Response(response=response, status=429, mimetype='text/plain') resp.headers['Retry-After'] = '86400' return resp # this is cached for easy access on the firmware details page if not fw.do_not_track: fw.download_cnt += 1 # log the client request if not fw.do_not_track: db.session.add( Client(addr=_addr_hash(_get_client_address()), firmware_id=fw.firmware_id, user_agent=user_agent)) db.session.commit() # firmware blobs if resource.startswith('downloads/'): return send_from_directory(app.config['DOWNLOAD_DIR'], os.path.basename(resource)) if resource.startswith('deleted/'): return send_from_directory(app.config['RESTORE_DIR'], os.path.basename(resource)) if resource.startswith('uploads/'): return send_from_directory(app.config['UPLOAD_DIR'], os.path.basename(resource)) # static files served locally return send_from_directory(os.path.join(app.root_path, 'static'), resource)
if 'fwchecks' in sys.argv: try: with app.test_request_context(): _check_firmware() _yara_query_all() except NotImplementedError as e: print(str(e)) sys.exit(1) if 'stats' in sys.argv: try: with app.test_request_context(): # default to yesterday, but also allow specifying the offset days = 1 if len(sys.argv) > 2: days = int(sys.argv[2]) val = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=days)) _generate_stats_for_datestr(val) _generate_stats() except NotImplementedError as e: print(str(e)) sys.exit(1) if 'statsmigrate' in sys.argv: try: update_kinds = None if len(sys.argv) > 2: update_kinds = sys.argv[2:] with app.test_request_context(): for days in range(1, 720): val = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta( days=days))
def _async_generate_stats(): datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(days=1)) _generate_stats_for_datestr(datestr)
def route_vendor(timespan_days=30, vendor_cnt=6, smoothing=0): """ A analytics screen to show information about users """ # get data for this time period cnt_total = defaultdict(int) cached_cnt = defaultdict(int) yesterday = datetime.date.today() - datetime.timedelta(days=1) datestr_start = _get_datestr_from_datetime(yesterday - datetime.timedelta( days=timespan_days)) datestr_end = _get_datestr_from_datetime(yesterday) print('get data for', datestr_start, datestr_end) for ug in db.session.query(AnalyticVendor)\ .filter(and_(AnalyticVendor.datestr >= datestr_start, AnalyticVendor.datestr <= datestr_end)): display_name = ug.vendor.display_name key = str(ug.datestr) + display_name cached_cnt[key] += ug.cnt cnt_total[display_name] += ug.cnt # find most popular user agent strings most_popular = [] for key, value in sorted(iter(cnt_total.items()), key=lambda k_v: (k_v[1], k_v[0]), reverse=True): most_popular.append(key) if len(most_popular) >= vendor_cnt: break # optionally smooth if not smoothing: smoothing = int(timespan_days / 25) # generate enough for the template datasets = [] palette = [ 'ef4760', # red 'ffd160', # yellow '06c990', # green '2f8ba0', # teal '845f80', # purple 'ee8510', # orange ] idx = 0 for value in sorted(most_popular): dataset = {} dataset['label'] = value dataset['color'] = palette[idx % 6] idx += 1 data = [] for i in range(timespan_days, 0, -1): datestr = _get_datestr_from_datetime(yesterday - datetime.timedelta(days=i)) key = str(datestr) + value dataval = 0 if key in cached_cnt: dataval = cached_cnt[key] data.append(dataval) if smoothing > 1: data = _running_mean(data, smoothing) dataset['data'] = json.dumps(data) datasets.append(dataset) return render_template( 'analytics-vendor.html', category='analytics', labels_user_agent=_get_chart_labels_days(timespan_days)[::-1], datasets=datasets)
def route_reportattrs_kind(kind, timespan_days=90): """ A analytics screen to show information about users """ # get data for this time period cnt_total = {} yesterday = datetime.date.today() - datetime.timedelta(days=1) datestr_start = yesterday - datetime.timedelta(days=timespan_days) cnt_total = {} cached_cnt = {} for report_ts, attr_val in db.session.query(Report.timestamp, ReportAttribute.value)\ .filter(ReportAttribute.key == kind)\ .join(Report)\ .filter(and_(Report.timestamp > datestr_start, Report.timestamp <= yesterday)): key = str(_get_datestr_from_datetime(report_ts)) + attr_val if key not in cached_cnt: cached_cnt[key] = 1 else: cached_cnt[key] += 1 if not attr_val in cnt_total: cnt_total[attr_val] = 1 continue cnt_total[attr_val] += 1 # find most popular user agent strings most_popular = [] for key, value in sorted(iter(cnt_total.items()), key=lambda k_v: (k_v[1], k_v[0]), reverse=True): most_popular.append(key) if len(most_popular) >= 6: break # generate enough for the template datasets = [] palette = [ 'ef4760', # red 'ffd160', # yellow '06c990', # green '2f8ba0', # teal '845f80', # purple 'ee8510', # orange ] idx = 0 for value in most_popular: dataset = {} dataset['label'] = value dataset['color'] = palette[idx % 6] idx += 1 data = [] for i in range(timespan_days): datestr = _get_datestr_from_datetime(yesterday - datetime.timedelta(days=i)) key = str(datestr) + value dataval = 'NaN' if key in cached_cnt: dataval = str(cached_cnt[key]) data.append(dataval) dataset['data'] = '[' + ', '.join(data[::-1]) + ']' datasets.append(dataset) return render_template( 'analytics-reportattrs-kind.html', category='analytics', kind=kind, labels_user_agent=_get_chart_labels_days(timespan_days)[::-1], datasets=datasets)
def route_user_agents(kind='APP', timespan_days=30): """ A analytics screen to show information about users """ # map back to UseragentKind try: kind_enum = UseragentKind[kind] except KeyError as e: flash('Unable to view analytic type: {}'.format(str(e)), 'danger') return redirect(url_for('analytics.route_user_agents')) # get data for this time period cnt_total = {} cached_cnt = {} yesterday = datetime.date.today() - datetime.timedelta(days=1) datestr_start = _get_datestr_from_datetime(yesterday - datetime.timedelta( days=timespan_days)) datestr_end = _get_datestr_from_datetime(yesterday) for ug in db.session.query(Useragent).\ filter(Useragent.kind == kind_enum.value).\ filter(and_(Useragent.datestr > datestr_start, Useragent.datestr <= datestr_end)): user_agent_safe = _user_agent_wildcard(ug.value) if kind == 'FWUPD': splt = user_agent_safe.split('.', 3) if len(splt) == 3: user_agent_safe = '{}.{}.x'.format(splt[0], splt[1]) key = str(ug.datestr) + user_agent_safe if key not in cached_cnt: cached_cnt[key] = ug.cnt else: cached_cnt[key] += ug.cnt if not user_agent_safe in cnt_total: cnt_total[user_agent_safe] = ug.cnt continue cnt_total[user_agent_safe] += ug.cnt # find most popular user agent strings most_popular = [] for key, value in sorted(iter(cnt_total.items()), key=lambda k_v: (k_v[1], k_v[0]), reverse=True): most_popular.append(key) if len(most_popular) >= 6: break # generate enough for the template datasets = [] palette = [ 'ef4760', # red 'ffd160', # yellow '06c990', # green '2f8ba0', # teal '845f80', # purple 'ee8510', # orange ] idx = 0 for value in most_popular: dataset = {} dataset['label'] = value dataset['color'] = palette[idx % 6] idx += 1 data = [] for i in range(timespan_days): datestr = _get_datestr_from_datetime(yesterday - datetime.timedelta(days=i)) key = str(datestr) + value dataval = 'NaN' if key in cached_cnt: dataval = str(cached_cnt[key]) data.append(dataval) dataset['data'] = '[' + ', '.join(data[::-1]) + ']' datasets.append(dataset) return render_template( 'analytics-user-agent.html', category='analytics', kind=kind, labels_user_agent=_get_chart_labels_days(timespan_days)[::-1], datasets=datasets)
def _run_test_on_shard(self, test, shard): # only Intel μcode supported at this time if shard.guid != '3f0229ad-0a00-5269-90cf-0a45d8781b72': return # get required attributes cpuid = shard.get_attr_value('cpuid') if not cpuid: return platform = shard.get_attr_value('platform') if not platform: return version = shard.get_attr_value('version') if not version: return datestr = shard.get_attr_value('yyyymmdd') if not datestr: return # don't expect vendors to include microcode that was released *after* # the file was uploaded to the LVFS datestr_upload = str(_get_datestr_from_datetime(shard.md.fw.timestamp)) # find any higher microcode version larger than this one known to the LVFS stmt1 = db.session.query(ComponentShard.component_shard_id)\ .join(ComponentShardAttribute)\ .filter(ComponentShardAttribute.key == 'cpuid')\ .filter(ComponentShardAttribute.value == cpuid)\ .subquery() stmt2 = db.session.query(ComponentShard.component_shard_id)\ .join(ComponentShardAttribute)\ .filter(ComponentShardAttribute.key == 'platform')\ .filter(ComponentShardAttribute.value == platform)\ .subquery() stmt3 = db.session.query(ComponentShard.component_shard_id)\ .join(ComponentShardAttribute)\ .filter(ComponentShardAttribute.key == 'yyyymmdd')\ .filter(ComponentShardAttribute.value < datestr_upload)\ .subquery() shards = db.session.query(ComponentShard)\ .join(stmt1, ComponentShard.component_shard_id == stmt1.c.component_shard_id)\ .join(stmt2, ComponentShard.component_shard_id == stmt2.c.component_shard_id)\ .join(stmt3, ComponentShard.component_shard_id == stmt3.c.component_shard_id)\ .join(ComponentShardAttribute)\ .filter(ComponentShardAttribute.key == 'version')\ .filter(ComponentShardAttribute.value > version)\ .order_by(ComponentShardAttribute.value)\ .all() for shard_tmp in shards: if shard_tmp.md.fw.remote.is_public: # an update can be created for resolving vendor-specific or # model-specific issues, so restrict results to the AppStream ID if shard.md.appstream_id != shard_tmp.md.appstream_id: continue # only count firmware older than the correct firmware if shard.md < shard_tmp.md: continue newest_version = shard_tmp.get_attr_value('version') newset_datestr = shard_tmp.get_attr_value('yyyymmdd') test.add_fail('Downgraded Intel CPU microcode detected', 'CPUID:{:#x} Platform:{:#x} version {:#x} (released on {}) is older ' 'than latest released version {:#x} (released on {}) found in {} v{}'\ .format(int(cpuid, 16), int(platform, 16), int(version, 16), datestr, int(newest_version, 16), newset_datestr, shard_tmp.md.name_with_category, shard_tmp.md.version_display)) return