├── src ├── webfaf │ ├── __init__.py │ ├── static │ │ ├── Makefile.am │ │ ├── icons │ │ │ ├── hicolor_apps_16x16_abrt.png │ │ │ ├── hicolor_apps_32x32_abrt.png │ │ │ └── Makefile.am │ │ ├── css │ │ │ ├── Makefile.am │ │ │ └── bootstrap-multiselect.css │ │ └── js │ │ │ ├── Makefile.am │ │ │ ├── jquery.flot.simplelabel.js │ │ │ └── color.js │ ├── templates │ │ ├── about.md.in │ │ ├── stats │ │ │ └── Makefile.am │ │ ├── summary │ │ │ ├── index_plot_data.html │ │ │ ├── Makefile.am │ │ │ └── index.html │ │ ├── mdpage.html │ │ ├── 404.html │ │ ├── 403.html │ │ ├── 413.html │ │ ├── problems │ │ │ ├── Makefile.am │ │ │ ├── waitforit.html │ │ │ ├── multiple_bthashes.html │ │ │ └── list_table_rows.html │ │ ├── celery_tasks │ │ │ ├── Makefile.am │ │ │ ├── results_item.html │ │ │ ├── results_list.html │ │ │ ├── action_run.html │ │ │ └── schedule_item.html │ │ ├── 500.html │ │ ├── reports │ │ │ ├── waitforit.html │ │ │ ├── Makefile.am │ │ │ ├── new.html │ │ │ ├── attach.html │ │ │ ├── list_table_rows.html │ │ │ ├── associate_bug.html │ │ │ └── diff.html │ │ └── Makefile.am │ ├── blueprints │ │ ├── Makefile.am │ │ └── __init__.py │ ├── Makefile.am │ ├── hub.wsgi │ ├── config.py │ └── login.py ├── pyfaf │ ├── storage │ │ ├── migrations │ │ │ ├── __init__.py │ │ │ ├── Makefile.am │ │ │ ├── alembic.ini │ │ │ ├── versions │ │ │ │ ├── 23bab42e7be7_initial_migration.py │ │ │ │ ├── 13557f1962e6_ureport_added_certainty.py │ │ │ │ ├── 21345f007bdf_add_privileged_user_field.py │ │ │ │ ├── acd3d9bf85d1_ignore_private_bz.py │ │ │ │ ├── 729a154b1609_index_reportpackages.py │ │ │ │ ├── 48550f308625_add_symbolsource_retrace_fail_count.py │ │ │ │ ├── 31d0249e8d4c_create_users_table.py │ │ │ │ ├── 82081a3c76b_rename_kb_to_sf_prefilter.py │ │ │ │ ├── 272e6a3deea4_link_probable_fix_to_build.py │ │ │ │ ├── bb2289ffb392_add_tz_info_to_periodictasks.py │ │ │ │ ├── 58f44afc3a3a_drop_running_package_from_reportpackages.py │ │ │ │ ├── 183a15e52a4f_report_history_unique.py │ │ │ │ ├── 50d3e87e4b2a_add_reporturl.py │ │ │ │ ├── 17d4911132f8_assigning_release_to_repo.py │ │ │ │ ├── 71905f91e7b7_add_archived_reports.py │ │ │ │ ├── 5695a1c595c3_reportreleasedesktops.py │ │ │ │ ├── 133991a89da4_build_to_opsysrelease.py │ │ │ │ ├── f43edd5b636d_enable_problem_components_reassign.py │ │ │ │ ├── fd5dc71471cc_set_pkg_name_to_256.py │ │ │ │ ├── Makefile.am │ │ │ │ └── 9596a0f03838_zero_unique_reports_to_one.py │ │ │ └── script.py.mako │ │ ├── fixtures │ │ │ ├── lob_download_location │ │ │ ├── sql │ │ │ │ ├── buildstags.sql │ │ │ │ ├── opsys.sql │ │ │ │ ├── builds.sql │ │ │ │ ├── buildarchs.sql │ │ │ │ ├── buildsys.sql │ │ │ │ ├── opsyscomponents.sql │ │ │ │ ├── opsysreleases.sql │ │ │ │ ├── Makefile.am │ │ │ │ ├── opsysreleasescomponents.sql │ │ │ │ ├── archs.sql │ │ │ │ └── packages.sql │ │ │ ├── Makefile.am │ │ │ └── randutils.py │ │ ├── Makefile.am │ │ ├── debug.py │ │ ├── jsontype.py │ │ ├── externalfaf.py │ │ ├── user.py │ │ ├── project.py │ │ ├── bugtracker.py │ │ └── events.py │ ├── opsys │ │ └── Makefile.am │ ├── celery_tasks │ │ └── Makefile.am │ ├── solutionfinders │ │ └── Makefile.am │ ├── problemtypes │ │ └── Makefile.am │ ├── repos │ │ └── Makefile.am │ ├── bugtrackers │ │ ├── Makefile.am │ │ ├── centosmantisbt.py │ │ ├── fedorabz.py │ │ └── rhelbz.py │ ├── utils │ │ ├── Makefile.am │ │ ├── __init__.py │ │ ├── contextmanager.py │ │ ├── format.py │ │ ├── web.py │ │ ├── date.py │ │ ├── hash.py │ │ └── storage.py │ ├── Makefile.am │ ├── local.py │ ├── actions │ │ ├── archlist.py │ │ ├── opsyslist.py │ │ ├── extfafshow.py │ │ ├── releaselist.py │ │ ├── pull_bug.py │ │ ├── find_report_solution.py │ │ ├── opsysadd.py │ │ ├── Makefile.am │ │ ├── archadd.py │ │ ├── cleanup_task_results.py │ │ ├── sar.py │ │ ├── bugtrackerlist.py │ │ ├── opsysdel.py │ │ ├── init.py │ │ ├── hash_paths.py │ │ ├── pull_abrt_bugs.py │ │ └── shell.py │ └── __init__.py.in ├── Makefile.am ├── schema │ ├── setup.cfg │ ├── README │ ├── Makefile.am │ └── faf_schema │ │ ├── __init__.py │ │ └── tests │ │ └── __init__.py └── bin │ ├── faf.bash_completion │ ├── faf-migrate-db.bash_completion │ └── Makefile.am ├── .tito ├── packages │ ├── faf │ └── .readme ├── releasers.conf └── tito.props ├── tests ├── sample_plugin_dir │ ├── __init__.py │ ├── base.py │ ├── Makefile.am │ ├── plugin.py │ └── _noplugin.py ├── bin │ ├── Makefile.am │ └── eu-addr2line ├── retrace_outputs │ ├── last_chance_0x0 │ ├── last_chance_0x2 │ ├── last_chance_0x3 │ ├── last_chance_0x4 │ ├── last_chance_0x5 │ ├── last_chance_0x6 │ ├── last_chance_0x7 │ ├── last_chance_0x8 │ ├── last_chance_0x9 │ ├── last_chance_0xa │ ├── last_chance_0xb │ ├── last_chance_0xc │ ├── last_chance_0xd │ ├── last_chance_0xe │ ├── last_chance_0xf │ ├── third_full_0xf │ ├── last_chance_0x10 │ ├── other_line_0xf │ ├── third_full_0xe │ ├── last_chance_0x1 │ ├── other_line_0xe │ ├── other_source_0xf │ ├── third_full_0xd │ ├── other_source_0xe │ ├── complex_0xffff │ └── Makefile.am ├── sample_repo │ ├── Makefile.am │ └── dummy_repo.repo ├── test_webfaf │ ├── webfaftests │ │ ├── Makefile.am │ │ └── __init__.py │ ├── Makefile.am │ ├── __init__.py │ └── test_summary.py ├── sample_rpms │ ├── Makefile.am │ ├── sample-1.0-1.fc18.noarch.rpm │ ├── sample2-2.0-1.fc32.noarch.rpm │ ├── sample-broken-1-1.fc22.noarch.rpm │ └── sample-provides-too-long-1-1.fc33.noarch.rpm ├── faftests │ ├── Makefile.am │ └── test_config.conf ├── sample_reports │ ├── url_attachment │ ├── bugzilla_attachment │ ├── contact_email_attachment │ ├── comment_attachment │ ├── Makefile.am │ ├── ureport_systemd2 │ └── ureport_systemd77 ├── Makefile.am ├── test_alembic.py ├── test_common.py ├── test_checker.py └── test_dnf.py ├── config ├── plugins │ ├── retrace.conf │ ├── dnf.conf │ ├── save-reports.conf │ ├── clonebz.conf │ ├── symbol-transfer.conf │ ├── pull-reports.conf │ ├── create-problems.conf │ ├── sf-prefilter.conf │ ├── celery_tasks.conf │ ├── fedmsg.conf │ ├── retrace-remote.conf │ ├── centosmantisbt.conf │ ├── java.conf │ ├── ruby.conf │ ├── coredump.conf │ ├── kerneloops.conf │ ├── rhelbz.conf │ ├── fedorabz.conf │ ├── python.conf │ ├── fedora.conf │ ├── centos.conf │ ├── Makefile.am │ └── web.conf ├── templates │ └── Makefile.am ├── faf ├── celery-worker-env.conf ├── celery-beat-env.conf ├── faf-logging.conf ├── Makefile.am ├── faf-web.conf.in └── faf.conf.in ├── container ├── files │ └── usr │ │ ├── bin │ │ ├── faf-entrypoint │ │ ├── faf-celery-worker │ │ ├── faf-celery-beat │ │ └── run_faf │ │ └── libexec │ │ └── fix-permissions ├── Dockerfile_db ├── podman-compose.yaml └── Dockerfile_local ├── autogen.sh ├── docs ├── attachment_sample ├── test_notes ├── fixture_notes └── ureport_sample ├── mypy.ini ├── AUTHORS ├── repos ├── CentOS-Base.repo ├── fedora-updates.repo ├── fedora-rawhide.repo ├── fedora-updates-testing.repo └── fedora.repo ├── requirements.txt ├── init-scripts ├── faf-celery-tmpfiles.conf ├── faf.conf ├── faf-celery-beat.service └── faf-celery-worker.service ├── .git-commit-template ├── lgtm.yml ├── Makefile.am ├── .gitignore ├── faf_setup ├── m4 └── ax_python_module.m4 └── .github └── workflows ├── test.yml └── codeql.yml /src/webfaf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tito/packages/faf: -------------------------------------------------------------------------------- 1 | 2.6.2 ./ 2 | -------------------------------------------------------------------------------- /tests/sample_plugin_dir/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = bin pyfaf webfaf schema 2 | -------------------------------------------------------------------------------- /tests/bin/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = eu-addr2line 2 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x0: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x2: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x3: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x4: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x5: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x6: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x7: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x8: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x9: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xa: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xb: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xc: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xd: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xe: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0xf: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/third_full_0xf: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /src/schema/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /src/webfaf/static/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = css js icons 2 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x10: -------------------------------------------------------------------------------- 1 | ?? 2 | ??:0 3 | -------------------------------------------------------------------------------- /config/plugins/retrace.conf: -------------------------------------------------------------------------------- 1 | [Retrace] 2 | SkipSource = yes 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/other_line_0xf: -------------------------------------------------------------------------------- 1 | ?? 2 | other_line.c:15 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/third_full_0xe: -------------------------------------------------------------------------------- 1 | ?? 2 | third_full.c:13 3 | -------------------------------------------------------------------------------- /tests/sample_plugin_dir/base.py: -------------------------------------------------------------------------------- 1 | class Base(object): 2 | pass 3 | -------------------------------------------------------------------------------- /tests/sample_repo/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = dummy_repo.repo 2 | 3 | -------------------------------------------------------------------------------- /config/plugins/dnf.conf: -------------------------------------------------------------------------------- 1 | [dnf] 2 | metadata_expire = 24h 3 | root = / 4 | -------------------------------------------------------------------------------- /config/plugins/save-reports.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | HashFrames = 16 3 | -------------------------------------------------------------------------------- /container/files/usr/bin/faf-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec "$@" 4 | -------------------------------------------------------------------------------- /src/bin/faf.bash_completion: -------------------------------------------------------------------------------- 1 | eval "$(register-python-argcomplete faf)" 2 | -------------------------------------------------------------------------------- /tests/retrace_outputs/last_chance_0x1: -------------------------------------------------------------------------------- 1 | last_chance 2 | last_chance.c:2 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/other_line_0xe: -------------------------------------------------------------------------------- 1 | other_line 2 | other_line.c:14 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/other_source_0xf: -------------------------------------------------------------------------------- 1 | ?? 2 | yet_another_source.c:14 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/third_full_0xd: -------------------------------------------------------------------------------- 1 | third_full 2 | third_full.c:13 3 | -------------------------------------------------------------------------------- /tests/test_webfaf/webfaftests/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = __init__.py 2 | -------------------------------------------------------------------------------- /config/plugins/clonebz.conf: -------------------------------------------------------------------------------- 1 | [clonebz] 2 | baseurl=http://localhost/faf 3 | -------------------------------------------------------------------------------- /tests/retrace_outputs/other_source_0xe: -------------------------------------------------------------------------------- 1 | other_source 2 | other_source.c:14 3 | -------------------------------------------------------------------------------- /tests/sample_rpms/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = sample-1.0-1.fc18.noarch.rpm 2 | 3 | -------------------------------------------------------------------------------- /config/plugins/symbol-transfer.conf: -------------------------------------------------------------------------------- 1 | [symbol_transfer] 2 | auth_key = @SECRET_KEY@ 3 | -------------------------------------------------------------------------------- /tests/faftests/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = __init__.py mockzilla.py test_config.conf 2 | -------------------------------------------------------------------------------- /src/bin/faf-migrate-db.bash_completion: -------------------------------------------------------------------------------- 1 | eval "$(register-python-argcomplete faf-migrate-db)" 2 | -------------------------------------------------------------------------------- /config/plugins/pull-reports.conf: -------------------------------------------------------------------------------- 1 | [pullreports] 2 | Master = https://retrace.fedoraproject.org/faf 3 | -------------------------------------------------------------------------------- /tests/sample_plugin_dir/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = __init__.py base.py plugin.py _noplugin.py 2 | 3 | -------------------------------------------------------------------------------- /.tito/releasers.conf: -------------------------------------------------------------------------------- 1 | [copr] 2 | releaser = tito.release.CoprReleaser 3 | project_name = @abrt/faf-el8 4 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/lob_download_location: -------------------------------------------------------------------------------- 1 | http://rmarko.fedorapeople.org/random/faf_fixtures_v2.tar.gz 2 | -------------------------------------------------------------------------------- /config/plugins/create-problems.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | CmpFrames = 16 3 | CutThreshold = 0.3 4 | Normalize = yes 5 | -------------------------------------------------------------------------------- /config/plugins/sf-prefilter.conf: -------------------------------------------------------------------------------- 1 | [sf-prefilter] 2 | # Lower number means higher priority 3 | solution_priority = 1 4 | -------------------------------------------------------------------------------- /src/webfaf/templates/about.md.in: -------------------------------------------------------------------------------- 1 | # Placeholder. This file is replaced with README.md from project root during build. 2 | -------------------------------------------------------------------------------- /tests/sample_plugin_dir/plugin.py: -------------------------------------------------------------------------------- 1 | from .base import Base 2 | 3 | 4 | class Sub(Base): 5 | name = "sub-plugin" 6 | -------------------------------------------------------------------------------- /config/plugins/celery_tasks.conf: -------------------------------------------------------------------------------- 1 | [celery_tasks] 2 | broker = redis://localhost:6379/0 3 | backend = redis://localhost:6379/0 4 | -------------------------------------------------------------------------------- /config/plugins/fedmsg.conf: -------------------------------------------------------------------------------- 1 | [fedmsg] 2 | # Realtime notifications 3 | realtime_reports = false 4 | realtime_problems = false 5 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/buildstags.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO buildstags VALUES(1,18); 2 | INSERT INTO buildstags VALUES(2,18); 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install --force 4 | if [ -z "$NOCONFIGURE" ]; then 5 | ./configure "$@" 6 | fi 7 | -------------------------------------------------------------------------------- /config/templates/Makefile.am: -------------------------------------------------------------------------------- 1 | template_DATA = 2 | templatedir = $(sysconfdir)/faf/templates 3 | 4 | EXTRA_DIST = $(template_DATA) 5 | -------------------------------------------------------------------------------- /tests/sample_plugin_dir/_noplugin.py: -------------------------------------------------------------------------------- 1 | from .base import Base 2 | 3 | 4 | class NSub(Base): 5 | name = "should-not-be-loaded" 6 | -------------------------------------------------------------------------------- /config/faf: -------------------------------------------------------------------------------- 1 | /var/log/faf/*.log { 2 | missingok 3 | notifempty 4 | rotate 5 5 | weekly 6 | su faf faf 7 | } 8 | 9 | -------------------------------------------------------------------------------- /tests/sample_rpms/sample-1.0-1.fc18.noarch.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/tests/sample_rpms/sample-1.0-1.fc18.noarch.rpm -------------------------------------------------------------------------------- /tests/sample_rpms/sample2-2.0-1.fc32.noarch.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/tests/sample_rpms/sample2-2.0-1.fc32.noarch.rpm -------------------------------------------------------------------------------- /.tito/tito.props: -------------------------------------------------------------------------------- 1 | [buildconfig] 2 | builder = tito.builder.Builder 3 | tagger = abrt.Tagger 4 | lib_dir = .tito/custom 5 | tag_format = {version} 6 | -------------------------------------------------------------------------------- /docs/attachment_sample: -------------------------------------------------------------------------------- 1 | { 2 | "type": "rhel-bugzilla", 3 | "bthash": "2dd542ba1f1e074216196b6c0bd548609bf38ebc", 4 | "data": "928318" 5 | } 6 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/opsys.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO opsys VALUES (1, 'Fedora'); 2 | INSERT INTO opsys VALUES (2, 'Red Hat Enterprise Linux'); 3 | -------------------------------------------------------------------------------- /src/schema/README: -------------------------------------------------------------------------------- 1 | A schema package for messages sent by FAF. 2 | 3 | To find out more information about FAF visit https://github.com/abrt/faf. 4 | -------------------------------------------------------------------------------- /src/webfaf/static/icons/hicolor_apps_16x16_abrt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/src/webfaf/static/icons/hicolor_apps_16x16_abrt.png -------------------------------------------------------------------------------- /src/webfaf/static/icons/hicolor_apps_32x32_abrt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/src/webfaf/static/icons/hicolor_apps_32x32_abrt.png -------------------------------------------------------------------------------- /tests/sample_rpms/sample-broken-1-1.fc22.noarch.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/tests/sample_rpms/sample-broken-1-1.fc22.noarch.rpm -------------------------------------------------------------------------------- /config/plugins/retrace-remote.conf: -------------------------------------------------------------------------------- 1 | [retrace_remote] 2 | remote_url = http://localhost/faf/symbol_transfer/get_symbol/ 3 | auth_key = @SECRET_KEY@ 4 | -------------------------------------------------------------------------------- /src/pyfaf/opsys/Makefile.am: -------------------------------------------------------------------------------- 1 | opsys_PYTHON = \ 2 | __init__.py \ 3 | centos.py \ 4 | fedora.py 5 | 6 | opsysdir = $(pythondir)/pyfaf/opsys 7 | -------------------------------------------------------------------------------- /tests/sample_reports/url_attachment: -------------------------------------------------------------------------------- 1 | { 2 | "type": "url", 3 | "bthash": "2dd542ba1f1e074216196b6c0bd548609bf38ebc", 4 | "data": "http://example.org" 5 | } 6 | -------------------------------------------------------------------------------- /src/pyfaf/celery_tasks/Makefile.am: -------------------------------------------------------------------------------- 1 | celery_tasks_PYTHON = \ 2 | __init__.py \ 3 | schedulers.py 4 | 5 | celery_tasksdir = $(pythondir)/pyfaf/celery_tasks 6 | -------------------------------------------------------------------------------- /tests/sample_reports/bugzilla_attachment: -------------------------------------------------------------------------------- 1 | { 2 | "type": "fedora-bugzilla", 3 | "bthash": "2dd542ba1f1e074216196b6c0bd548609bf38ebc", 4 | "data": "123456" 5 | } 6 | -------------------------------------------------------------------------------- /tests/sample_rpms/sample-provides-too-long-1-1.fc33.noarch.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrt/faf/HEAD/tests/sample_rpms/sample-provides-too-long-1-1.fc33.noarch.rpm -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/builds.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO builds VALUES(1,348366,NULL,2,0,'2.15','56.fc17'); 2 | INSERT INTO builds VALUES(2,344069,NULL,1,0,'0.2','1.fc17'); 3 | -------------------------------------------------------------------------------- /tests/sample_reports/contact_email_attachment: -------------------------------------------------------------------------------- 1 | { 2 | "type": "email", 3 | "bthash": "2dd542ba1f1e074216196b6c0bd548609bf38ebc", 4 | "data": "h4xx0r@1337.com" 5 | } 6 | -------------------------------------------------------------------------------- /src/webfaf/templates/stats/Makefile.am: -------------------------------------------------------------------------------- 1 | stats_templ_DATA = by_date.html 2 | 3 | stats_templdir = $(pythondir)/webfaf/templates/stats 4 | 5 | EXTRA_DIST = $(stats_templ_DATA) 6 | -------------------------------------------------------------------------------- /.tito/packages/.readme: -------------------------------------------------------------------------------- 1 | the .tito/packages directory contains metadata files 2 | named after their packages. Each file has the latest tagged 3 | version and the project's relative directory. 4 | -------------------------------------------------------------------------------- /src/webfaf/blueprints/Makefile.am: -------------------------------------------------------------------------------- 1 | blueprints_PYTHON = \ 2 | __init__.py \ 3 | celery_tasks.py \ 4 | symbol_transfer.py 5 | 6 | blueprintsdir = $(pythondir)/webfaf/blueprints 7 | -------------------------------------------------------------------------------- /src/webfaf/templates/summary/index_plot_data.html: -------------------------------------------------------------------------------- 1 |
5 | -------------------------------------------------------------------------------- /tests/sample_reports/comment_attachment: -------------------------------------------------------------------------------- 1 | { 2 | "type": "comment", 3 | "bthash": "2dd542ba1f1e074216196b6c0bd548609bf38ebc", 4 | "data": "It crashed. I don't know why. Plz help." 5 | } 6 | -------------------------------------------------------------------------------- /tests/sample_repo/dummy_repo.repo: -------------------------------------------------------------------------------- 1 | [repo1] 2 | name=Repo1 3 | baseurl=file:///some/where 4 | gpgcheck=0 5 | 6 | [repo2] 7 | name=Repo2 8 | baseurl=file:///some/other/place 9 | gpgcheck=0 10 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/buildarchs.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO buildarchs VALUES(1,1); 2 | INSERT INTO buildarchs VALUES(1,2); 3 | INSERT INTO buildarchs VALUES(2,1); 4 | INSERT INTO buildarchs VALUES(2,2); 5 | -------------------------------------------------------------------------------- /src/webfaf/templates/summary/Makefile.am: -------------------------------------------------------------------------------- 1 | summary_templ_DATA = index.html index_plot_data.html 2 | 3 | summary_templdir = $(pythondir)/webfaf/templates/summary 4 | 5 | EXTRA_DIST = $(summary_templ_DATA) 6 | -------------------------------------------------------------------------------- /config/plugins/centosmantisbt.conf: -------------------------------------------------------------------------------- 1 | [centos-mantisbt] 2 | api_url=https://bugs.centos.org/api/soap/mantisconnect.php?wsdl 3 | web_url=https://bugs.centos.org/view.php?id= 4 | user= 5 | password= 6 | abbr=CENTOS 7 | -------------------------------------------------------------------------------- /src/webfaf/static/icons/Makefile.am: -------------------------------------------------------------------------------- 1 | icon_DATA = \ 2 | hicolor_apps_16x16_abrt.png \ 3 | hicolor_apps_32x32_abrt.png 4 | 5 | 6 | icondir = $(datadir)/faf/web/static/icons/ 7 | 8 | EXTRA_DIST = $(icon_DATA) 9 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | disallow_untyped_calls = True 3 | pretty = True 4 | show_column_numbers = True 5 | show_error_codes = True 6 | show_error_context = True 7 | strict_equality = True 8 | warn_unreachable = True 9 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = versions 2 | 3 | migrations_PYTHON = \ 4 | __init__.py \ 5 | alembic.ini \ 6 | env.py 7 | 8 | migrationsdir = $(pythondir)/pyfaf/storage/migrations 9 | -------------------------------------------------------------------------------- /src/webfaf/templates/mdpage.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ mddoc.title }}{% endblock %} 4 | 5 | {% block body %} 6 |

{{ mddoc.title }}

7 | {{ mddoc.body | safe }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Michal Toman 2 | Richard Marko 3 | Miroslav Lichvar 4 | Jakub Filak 5 | Martin Milata 6 | Marek Brysa 7 | Karel Klic 8 | -------------------------------------------------------------------------------- /src/pyfaf/solutionfinders/Makefile.am: -------------------------------------------------------------------------------- 1 | solutionfinders_PYTHON = \ 2 | __init__.py \ 3 | prefilter_solution_finder.py \ 4 | probable_fix_solution_finder.py 5 | 6 | solutionfindersdir = $(pythondir)/pyfaf/solutionfinders 7 | -------------------------------------------------------------------------------- /src/webfaf/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Page Not Found{% endblock %} 4 | 5 | {% block body %} 6 |

7 | Page not found. 8 |

9 |

10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /src/pyfaf/problemtypes/Makefile.am: -------------------------------------------------------------------------------- 1 | problemtypes_PYTHON = \ 2 | __init__.py \ 3 | core.py \ 4 | java.py \ 5 | kerneloops.py \ 6 | python.py \ 7 | ruby.py 8 | 9 | problemtypesdir = $(pythondir)/pyfaf/problemtypes 10 | -------------------------------------------------------------------------------- /tests/test_webfaf/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = webfaftests 2 | 3 | TESTS = test_problems.py test_reports.py test_summary.py test_user.py 4 | 5 | check_SCRIPTS = $(TESTS) 6 | 7 | check-local: check-TESTS 8 | 9 | EXTRA_DIST = $(check_SCRIPTS) 10 | -------------------------------------------------------------------------------- /src/pyfaf/repos/Makefile.am: -------------------------------------------------------------------------------- 1 | repos_PYTHON = \ 2 | __init__.py \ 3 | dnf.py \ 4 | rpm_metadata.py 5 | 6 | EXTRA_DIST = $(repos_PYTHON) 7 | 8 | am__repos_PYTHON_DIST = $(repos_PYTHON) 9 | 10 | reposdir = $(pythondir)/pyfaf/repos 11 | -------------------------------------------------------------------------------- /config/celery-worker-env.conf: -------------------------------------------------------------------------------- 1 | CELERY_APP="pyfaf.celery_tasks.celery_app" 2 | CELERYD_NODES="worker" 3 | CELERYD_OPTS="" 4 | CELERYD_PID_FILE="/run/faf-celery/faf-celery-%n.pid" 5 | CELERYD_LOG_FILE="/var/log/faf/faf-celery-%n.log" 6 | CELERYD_LOG_LEVEL="INFO" 7 | -------------------------------------------------------------------------------- /src/bin/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_SCRIPTS = faf faf-migrate-db 2 | 3 | bashcompdir = $(sysconfdir)/bash_completion.d 4 | 5 | dist_bashcomp_DATA = \ 6 | faf.bash_completion \ 7 | faf-migrate-db.bash_completion 8 | 9 | EXTRA_DIST = $(bin_SCRIPTS) 10 | -------------------------------------------------------------------------------- /src/pyfaf/bugtrackers/Makefile.am: -------------------------------------------------------------------------------- 1 | bugtrackers_PYTHON = \ 2 | __init__.py \ 3 | bugzilla.py \ 4 | fedorabz.py \ 5 | mantisbt.py \ 6 | centosmantisbt.py \ 7 | rhelbz.py 8 | 9 | bugtrackersdir = $(pythondir)/pyfaf/bugtrackers 10 | -------------------------------------------------------------------------------- /src/webfaf/templates/403.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Forbidden{% endblock %} 4 | 5 | {% block body %} 6 |

7 | This page is only accessible for authorized users. 8 |

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /config/plugins/java.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | # Uncomment whatever is necessary to override the default 3 | 4 | # JavaHashFrames = 16 5 | # JavaCmpFrames = 16 6 | # JavaCutThreshold = 0.3 7 | # JavaNormalize = yes 8 | 9 | [Retrace] 10 | # JavaSkipSource = yes 11 | -------------------------------------------------------------------------------- /config/plugins/ruby.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | # Uncomment whatever is necessary to override the default 3 | 4 | # RubyHashFrames = 16 5 | # RubyCmpFrames = 16 6 | # RubyCutThreshold = 0.3 7 | # RubyNormalize = yes 8 | 9 | [Retrace] 10 | # RubySkipSource = yes 11 | -------------------------------------------------------------------------------- /config/plugins/coredump.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | # Uncomment whatever is necessary to override the default 3 | 4 | # CoreHashFrames = 16 5 | # CoreCmpFrames = 16 6 | # CoreCutThreshold = 0.3 7 | # CoreNormalize = yes 8 | 9 | [Retrace] 10 | # CoreSkipSource = yes 11 | -------------------------------------------------------------------------------- /config/plugins/kerneloops.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | # Uncomment whatever is necessary to override the default 3 | 4 | # OopsHashFrames = 16 5 | # OopsCmpFrames = 16 6 | # OopsCutThreshold = 0.3 7 | # OopsNormalize = yes 8 | 9 | [Retrace] 10 | # OopsSkipSource = yes 11 | -------------------------------------------------------------------------------- /config/plugins/rhelbz.conf: -------------------------------------------------------------------------------- 1 | [rhel-bugzilla] 2 | api_url=https://bugzilla.redhat.com/xmlrpc.cgi 3 | web_url=https://bugzilla.redhat.com/show_bug.cgi?id= 4 | new_bug_url=https://bugzilla.redhat.com/enter_bug.cgi 5 | save_comments=false 6 | save_attachments=false 7 | api_key= 8 | -------------------------------------------------------------------------------- /config/plugins/fedorabz.conf: -------------------------------------------------------------------------------- 1 | [fedora-bugzilla] 2 | api_url=https://bugzilla.redhat.com/xmlrpc.cgi 3 | web_url=https://bugzilla.redhat.com/show_bug.cgi?id= 4 | new_bug_url=https://bugzilla.redhat.com/enter_bug.cgi 5 | save_comments=false 6 | save_attachments=false 7 | api_key= 8 | -------------------------------------------------------------------------------- /config/plugins/python.conf: -------------------------------------------------------------------------------- 1 | [Processing] 2 | # Uncomment whatever is necessary to override the default 3 | 4 | # PythonHashFrames = 16 5 | # PythonCmpFrames = 16 6 | # PythonCutThreshold = 0.3 7 | # PythonNormalize = yes 8 | 9 | [Retrace] 10 | # PythonSkipSource = yes 11 | -------------------------------------------------------------------------------- /src/webfaf/static/css/Makefile.am: -------------------------------------------------------------------------------- 1 | css_DATA = \ 2 | bootstrap-multiselect.css \ 3 | bootstrap-tagsinput.css \ 4 | daterangepicker-bs3.css \ 5 | style.css \ 6 | typeaheadjs.css 7 | 8 | cssdir = $(datadir)/faf/web/static/css/ 9 | 10 | EXTRA_DIST = $(css_DATA) 11 | -------------------------------------------------------------------------------- /config/plugins/fedora.conf: -------------------------------------------------------------------------------- 1 | [Fedora] 2 | FedoraPDC = https://pdc.fedoraproject.org/rest_api/v1/ 3 | PagureAPI = https://src.fedoraproject.org/api/0/ 4 | SupportEOL = False 5 | build-aging-days = 14 6 | koji-url = https://koji.fedoraproject.org/kojihub 7 | ignored-releases = epel*, pel*, ln, l 8 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/buildsys.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO buildsys VALUES (1, 'http://koji.fedoraproject.org/kojihub', 'http://kojipkgs.fedoraproject.org/packages'); 2 | INSERT INTO buildsys VALUES (2, 'http://brewhub.devel.redhat.com/brewhub', 'http://porkchop.devel.redhat.com/brewroot/packages'); 3 | -------------------------------------------------------------------------------- /src/webfaf/templates/413.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}File too large{% endblock %} 4 | 5 | {% block body %} 6 |

7 | File size of the uploaded file is too large and can't be processed by the server. 8 |

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /config/celery-beat-env.conf: -------------------------------------------------------------------------------- 1 | CELERY_APP="pyfaf.celery_tasks.celery_app" 2 | CELERYD_NODES="beat" 3 | CELERYD_OPTS="-S pyfaf.celery_tasks.schedulers.DBScheduler" 4 | CELERYD_PID_FILE="/run/faf-celery/faf-celery-beat.pid" 5 | CELERYD_LOG_FILE="/var/log/faf/faf-celery-beat.log" 6 | CELERYD_LOG_LEVEL="INFO" 7 | -------------------------------------------------------------------------------- /tests/retrace_outputs/complex_0xffff: -------------------------------------------------------------------------------- 1 | waitForMessageFilteredWithTimeout::waitForMessage() [with DataType = WTF::Function]::__lambda0> inlined at Source/WTF/wtf/MessageQueue.h:131 in _ZN7WebCore13StorageThread16threadEntryPointEv 2 | Source/WTF/wtf/MessageQueue.c:1234 3 | -------------------------------------------------------------------------------- /src/webfaf/templates/problems/Makefile.am: -------------------------------------------------------------------------------- 1 | problems_templ_DATA = \ 2 | item.html \ 3 | list.html \ 4 | list_table_rows.html \ 5 | multiple_bthashes.html \ 6 | waitforit.html 7 | 8 | problems_templdir = $(pythondir)/webfaf/templates/problems 9 | 10 | EXTRA_DIST = $(problems_templ_DATA) 11 | -------------------------------------------------------------------------------- /tests/test_webfaf/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # alter path so we can import from webfaftests in this directory 5 | test_webfaf_path = os.path.dirname(os.path.realpath(__file__)) 6 | sys.path.insert(0, test_webfaf_path) 7 | os.environ["PATH"] = "{0}:{1}".format(test_webfaf_path, os.environ["PATH"]) 8 | -------------------------------------------------------------------------------- /repos/CentOS-Base.repo: -------------------------------------------------------------------------------- 1 | [centos-base] 2 | name=CentOS-$releasever - Base 3 | baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ 4 | gpgcheck=0 5 | 6 | [centos-updates] 7 | name=CentOS-$releasever - Updates 8 | baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ 9 | gpgcheck=0 10 | -------------------------------------------------------------------------------- /src/pyfaf/utils/Makefile.am: -------------------------------------------------------------------------------- 1 | utils_PYTHON = \ 2 | __init__.py \ 3 | contextmanager.py \ 4 | date.py \ 5 | decorators.py \ 6 | format.py \ 7 | hash.py \ 8 | parse.py \ 9 | proc.py \ 10 | storage.py \ 11 | user.py \ 12 | web.py 13 | 14 | utilsdir = $(pythondir)/pyfaf/utils 15 | -------------------------------------------------------------------------------- /src/webfaf/templates/celery_tasks/Makefile.am: -------------------------------------------------------------------------------- 1 | celery_tasks_templ_DATA = \ 2 | action_run.html \ 3 | index.html \ 4 | results_item.html \ 5 | results_list.html \ 6 | schedule_item.html 7 | 8 | celery_tasks_templdir = $(pythondir)/webfaf/templates/celery_tasks 9 | 10 | EXTRA_DIST = $(celery_tasks_templ_DATA) 11 | -------------------------------------------------------------------------------- /src/webfaf/templates/problems/waitforit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Problem has not yet been created{% endblock %} 4 | 5 | {% block body %} 6 |

The problem has not yet been created

7 |
Problems are generated every few hours, try refreshing this site later.
8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /container/files/usr/libexec/fix-permissions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Fix permissions on the given directory to allow group read/write of 3 | # regular files and execute of directories. 4 | 5 | find ${1} -exec chown faf {} \; 6 | find ${1} -exec chgrp 0 {} \; 7 | find ${1} -exec chmod g+rw {} \; 8 | find ${1} -type d -exec chmod g+x {} \; 9 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = sql 2 | 3 | pyfaf_fixtures_PYTHON = \ 4 | __init__.py \ 5 | data.py \ 6 | randutils.py 7 | pyfaf_fixturesdir = $(pythondir)/pyfaf/storage/fixtures 8 | 9 | fixture_DATA = lob_download_location 10 | fixturedir = $(datadir)/faf/fixtures/ 11 | 12 | EXTRA_DIST = $(fixture_DATA) 13 | -------------------------------------------------------------------------------- /src/webfaf/templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Internal Server Error{% endblock %} 4 | 5 | {% block body %} 6 |

7 | Internal Server Error. 8 | This error has been logged and we will take care of it soon. 9 | Sorry. 10 |

11 |

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /src/schema/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = \ 2 | faf_schema \ 3 | README \ 4 | setup.cfg \ 5 | setup.py 6 | 7 | all: 8 | 9 | all-local: 10 | $(PYTHON) setup.py build --verbose 11 | 12 | install-exec-local: 13 | $(PYTHON) setup.py install --root $(DESTDIR) \ 14 | --single-version-externally-managed \ 15 | --verbose 16 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/waitforit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Report is still being processed{% endblock %} 4 | 5 | {% block body %} 6 |

The reports was not found or is still being processed

7 |

Reports are processed every few minutes, try refreshing this site in a while.

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/Makefile.am: -------------------------------------------------------------------------------- 1 | reports_templ_DATA = \ 2 | associate_bug.html \ 3 | attach.html \ 4 | diff.html \ 5 | item.html \ 6 | list.html \ 7 | list_table_rows.html \ 8 | new.html \ 9 | waitforit.html 10 | 11 | reports_templdir = $(pythondir)/webfaf/templates/reports 12 | 13 | EXTRA_DIST = $(reports_templ_DATA) 14 | -------------------------------------------------------------------------------- /src/webfaf/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = blueprints static templates 2 | 3 | hub_PYTHON = \ 4 | __init__.py \ 5 | config.py \ 6 | filters.py \ 7 | forms.py \ 8 | hub.wsgi \ 9 | login.py \ 10 | problems.py \ 11 | reports.py \ 12 | stats.py \ 13 | summary.py \ 14 | user.py \ 15 | utils.py \ 16 | webfaf_main.py 17 | 18 | hubdir = $(pythondir)/webfaf 19 | -------------------------------------------------------------------------------- /docs/test_notes: -------------------------------------------------------------------------------- 1 | Running tests: 2 | 3 | - to run each test: ./faf-hub test 4 | - to run test for selected component: ./faf-hub test reports 5 | - to run specific set of tests: ./faf-hub test reports.ReportsListTest 6 | - to run single test: ./faf-hub test reports.ReportsListTest.test_entries 7 | 8 | 9 | You can increase output verbosity with -v1 -v2 -v3 options (./faf-hub test -v3) 10 | -------------------------------------------------------------------------------- /repos/fedora-updates.repo: -------------------------------------------------------------------------------- 1 | [updates] 2 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/$basearch/ 3 | gpgcheck=0 4 | 5 | [updates-debuginfo] 6 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/$basearch/debug/ 7 | gpgcheck=0 8 | 9 | [updates-source] 10 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/SRPMS/ 11 | gpgcheck=0 12 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/opsyscomponents.sql: -------------------------------------------------------------------------------- 1 | -- Fedora 2 | INSERT INTO opsyscomponents VALUES (1, 'will-crash', 1); 3 | INSERT INTO opsyscomponents VALUES (2, 'glibc', 1); 4 | INSERT INTO opsyscomponents VALUES (3, 'kernel', 1); 5 | 6 | -- EL 7 | INSERT INTO opsyscomponents VALUES (4, 'will-crash', 2); 8 | INSERT INTO opsyscomponents VALUES (5, 'glibc', 2); 9 | INSERT INTO opsyscomponents VALUES (6, 'kernel', 2); 10 | -------------------------------------------------------------------------------- /repos/fedora-rawhide.repo: -------------------------------------------------------------------------------- 1 | [rawhide] 2 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/$basearch/os/ 3 | gpgcheck=0 4 | 5 | [rawhide-debuginfo] 6 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/$basearch/debug/ 7 | gpgcheck=0 8 | 9 | [rawhide-source] 10 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/source/SRPMS/ 11 | gpgcheck=0 12 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | alembic ~= 1.4.2 2 | argcomplete ~= 1.12.0 3 | cachelib ~= 0.1.1 4 | celery >= 5.2.2 5 | fedora-messaging ~= 2.1.0 6 | flask ~= 1.1.2 7 | Flask-OpenID ~= 1.2.5 8 | Flask-SQLAlchemy ~= 2.4.4 9 | koji ~= 1.24.1 10 | markdown2 ~= 2.4.0 11 | munch ~= 2.5.0 12 | python-bugzilla ~= 3.0.2 13 | python-openid-teams ~= 1.1 14 | requests ~= 2.24.0 15 | SQLAlchemy ~= 1.3.24 16 | Werkzeug ~= 1.0.1 17 | WTForms ~= 2.3.3 18 | zeep ~= 3.4.0 19 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/opsysreleases.sql: -------------------------------------------------------------------------------- 1 | -- (id, opsys_id, version, releasedate, status) 2 | 3 | INSERT INTO opsysreleases VALUES (1, 1, '15', NULL, 'EOL'); 4 | INSERT INTO opsysreleases VALUES (2, 1, '16', NULL, 'ACTIVE'); 5 | INSERT INTO opsysreleases VALUES (3, 1, '17', NULL, 'ACTIVE'); 6 | INSERT INTO opsysreleases VALUES (4, 1, 'devel', NULL, 'UNDER_DEVELOPMENT'); 7 | INSERT INTO opsysreleases VALUES (5, 2, '7.0', NULL, 'ACTIVE'); 8 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = . 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # set to 'true' to run the environment during 11 | # the 'revision' command, regardless of autogenerate 12 | # revision_environment = false 13 | 14 | sqlalchemy.url = postgresql:///faf 15 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/Makefile.am: -------------------------------------------------------------------------------- 1 | fixture_sql_DATA = \ 2 | archs.sql \ 3 | archstags.sql \ 4 | buildarchs.sql \ 5 | builds.sql \ 6 | buildstags.sql \ 7 | buildsys.sql \ 8 | opsys.sql \ 9 | opsyscomponents.sql \ 10 | opsysreleases.sql \ 11 | opsysreleasescomponents.sql \ 12 | packages.sql \ 13 | taginheritances.sql \ 14 | tags.sql 15 | 16 | fixture_sqldir = $(datadir)/faf/fixtures/sql/ 17 | 18 | EXTRA_DIST = $(fixture_sql_DATA) 19 | -------------------------------------------------------------------------------- /init-scripts/faf-celery-tmpfiles.conf: -------------------------------------------------------------------------------- 1 | # This file is part of faf. 2 | # 3 | # faf is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | 8 | # See tmpfiles.d(5) for details 9 | 10 | #Type Path Mode User Group Age 11 | d /run/faf-celery 0755 faf faf - 12 | -------------------------------------------------------------------------------- /repos/fedora-updates-testing.repo: -------------------------------------------------------------------------------- 1 | [updates-testing] 2 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/$basearch/ 3 | gpgcheck=0 4 | 5 | [updates-testing-debuginfo] 6 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/$basearch/debug/ 7 | gpgcheck=0 8 | 9 | [updates-testing-source] 10 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/SRPMS/ 11 | gpgcheck=0 12 | -------------------------------------------------------------------------------- /repos/fedora.repo: -------------------------------------------------------------------------------- 1 | [fedora] 2 | failovermethod=priority 3 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/ 4 | gpgcheck=0 5 | 6 | [fedora-debuginfo] 7 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/ 8 | gpgcheck=0 9 | 10 | [fedora-source] 11 | baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/source/SRPMS/ 12 | gpgcheck=0 13 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/opsysreleasescomponents.sql: -------------------------------------------------------------------------------- 1 | -- will-crash, glibc, kernel for F17 2 | INSERT INTO opsysreleasescomponents VALUES (1, 3, 1); 3 | INSERT INTO opsysreleasescomponents VALUES (2, 3, 2); 4 | INSERT INTO opsysreleasescomponents VALUES (3, 3, 3); 5 | 6 | -- will-crash, glibc, kernel for EL7 7 | INSERT INTO opsysreleasescomponents VALUES (4, 5, 4); 8 | INSERT INTO opsysreleasescomponents VALUES (5, 5, 5); 9 | INSERT INTO opsysreleasescomponents VALUES (6, 5, 6); 10 | -------------------------------------------------------------------------------- /.git-commit-template: -------------------------------------------------------------------------------- 1 | COMPONENT: Subject 2 | 3 | Explanation 4 | 5 | Resolves: 6 | https://github.com/abrt/faf/issues/XXXX 7 | https://bugzilla.redhat.com/show_bug.cgi?id=XXXXXX 8 | 9 | # Try to keep the subject line within 52 chars ----| 10 | # Also please try to not exceed 72 characters of length for the body --| 11 | # Avoid using exact file names as COMPONENT. Use keywords such as spec, 12 | # client, dump_dir etc. You do not need to follow this template 100%. 13 | # See git log for examples. 14 | -------------------------------------------------------------------------------- /init-scripts/faf.conf: -------------------------------------------------------------------------------- 1 | # This file is part of faf. 2 | # 3 | # faf is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | 8 | # See tmpfiles.d(5) for details 9 | 10 | #Type Path Mode User Group Age 11 | d /tmp/faf 0755 faf faf 28d 12 | d /tmp/faf/rpm 0755 faf faf 1d 13 | -------------------------------------------------------------------------------- /src/webfaf/templates/problems/multiple_bthashes.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Multiple problems found{% endblock %} 4 | 5 | {% block body %} 6 |

Multiple problems found

7 |

Multiple problem have been found for the backtrace hashes you specified.

8 |
    9 | {% for problem in problems %} 10 |
  • #{{problem.id}}
  • 11 | {% endfor %} 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | javascript: 3 | index: 4 | exclude: "*" 5 | include: "src/webfaf/static/js/custom.js" 6 | python: 7 | prepare: 8 | packages: 9 | - autoconf 10 | - automake 11 | - autopoint 12 | - intltool 13 | - libtool 14 | - make 15 | - python3-dev 16 | after_prepare: 17 | - ./autogen.sh 18 | - make 19 | python_setup: 20 | requirements_files: false 21 | setup_py: false 22 | version: 3 23 | -------------------------------------------------------------------------------- /src/webfaf/hub.wsgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | import logging 5 | 6 | logging.basicConfig(stream=sys.stderr) 7 | os.environ["WEBFAF_ENVIRON_PRODUCTION"] = "1" 8 | sys.path.insert(0, os.path.dirname(__file__)) 9 | 10 | # We can only import from webfaf once the PYTHONPATH has been set up above. 11 | # pylint: disable=wrong-import-position 12 | from webfaf.webfaf_main import app as application 13 | from webfaf.webfaf_main import import_blueprint_plugins 14 | import_blueprint_plugins(application) 15 | -------------------------------------------------------------------------------- /src/webfaf/templates/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = \ 2 | celery_tasks \ 3 | problems \ 4 | reports \ 5 | stats \ 6 | summary 7 | 8 | template_DATA = \ 9 | _helpers.html \ 10 | 403.html \ 11 | 404.html \ 12 | 413.html \ 13 | 500.html \ 14 | about.md \ 15 | base.html \ 16 | mdpage.html 17 | 18 | templatedir = $(pythondir)/webfaf/templates 19 | 20 | # Use README.md from project root 21 | about.md: about.md.in 22 | cp ../../../README.md about.md 23 | 24 | EXTRA_DIST = $(template_DATA) about.md.in 25 | -------------------------------------------------------------------------------- /init-scripts/faf-celery-beat.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=FAF Celery beat 3 | After=network.target 4 | 5 | [Service] 6 | User=faf 7 | Group=faf 8 | EnvironmentFile=/etc/faf/celery-beat-env.conf 9 | WorkingDirectory=/etc/faf 10 | ExecStart=/usr/bin/python3 -m celery -C -A $CELERY_APP beat \ 11 | --pidfile=${CELERYD_PID_FILE} \ 12 | --logfile=${CELERYD_LOG_FILE} \ 13 | --loglevel=${CELERYD_LOG_LEVEL} \ 14 | $CELERYD_OPTS 15 | PIDFile=${CELERYD_PID_FILE} 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /config/plugins/centos.conf: -------------------------------------------------------------------------------- 1 | [CentOS] 2 | repo-urls=http://vault.centos.org/centos/$releasever/os/Source/ 3 | http://vault.centos.org/centos/$releasever/updates/Source/ 4 | http://vault.centos.org/centos/$releasever/AppStream/Source/ 5 | http://vault.centos.org/centos/$releasever/BaseOS/Source/ 6 | http://vault.centos.org/centos/$releasever-stream/AppStream/Source/ 7 | http://vault.centos.org/centos/$releasever-stream/BaseOS/Source/ 8 | 9 | inactive-releases= 10 | active-releases=7 11 | -------------------------------------------------------------------------------- /src/pyfaf/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = \ 2 | actions \ 3 | bugtrackers \ 4 | celery_tasks \ 5 | opsys \ 6 | problemtypes \ 7 | repos \ 8 | solutionfinders \ 9 | storage \ 10 | utils 11 | 12 | pyfaf_PYTHON = \ 13 | __init__.py \ 14 | checker.py \ 15 | cmdline.py \ 16 | common.py \ 17 | config.py \ 18 | local.py \ 19 | retrace.py \ 20 | faf_rpm.py \ 21 | queries.py \ 22 | ureport.py \ 23 | ureport_compat.py 24 | 25 | pyfafdir = $(pythondir)/pyfaf 26 | 27 | EXTRA_DIST = $(pyfaf_PYTHON) 28 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | 4 | {% block title %}New report{% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |

Submit uReport file

10 |
11 | {{ render_field(form.file) }} 12 |

13 |
14 |
15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /src/webfaf/static/js/Makefile.am: -------------------------------------------------------------------------------- 1 | js_DATA = \ 2 | bootstrap.js \ 3 | bootstrap-multiselect.js \ 4 | bootstrap-tagsinput.js \ 5 | color.js \ 6 | custom.js \ 7 | daterangepicker.js \ 8 | jquery.flot.axislabels.js \ 9 | jquery.flot.js \ 10 | jquery.flot.pie.js \ 11 | jquery.flot.resize.js \ 12 | jquery.flot.simplelabel.js \ 13 | jquery.flot.stack.js \ 14 | jquery.flot.symbol.js \ 15 | jquery.flot.time.js \ 16 | moment.js \ 17 | typeahead.bundle.min.js 18 | 19 | jsdir = $(datadir)/faf/web/static/js/ 20 | 21 | EXTRA_DIST = $(js_DATA) 22 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/attach.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | 4 | {% block title %}New attachment{% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |

Submit attachment file

10 |
11 | {{ render_field(form.file) }} 12 |

13 |
14 |
15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /src/pyfaf/storage/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = \ 2 | fixtures \ 3 | migrations 4 | 5 | storage_PYTHON = \ 6 | __init__.py \ 7 | bugzilla.py \ 8 | bugtracker.py \ 9 | custom_types.py \ 10 | debug.py \ 11 | events.py \ 12 | events_fedmsg.py \ 13 | externalfaf.py \ 14 | generic_table.py \ 15 | jsontype.py \ 16 | llvm.py \ 17 | opsys.py \ 18 | mantisbt.py \ 19 | problem.py \ 20 | project.py \ 21 | report.py \ 22 | sf_prefilter.py \ 23 | symbol.py \ 24 | task.py \ 25 | user.py 26 | 27 | storagedir = $(pythondir)/pyfaf/storage 28 | -------------------------------------------------------------------------------- /tests/sample_reports/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = bugzilla_attachment comment_attachment contact_email_attachment \ 2 | url_attachment \ 3 | tainted_kernel ureport1 ureport2 ureport_f20 low_quality1 \ 4 | ureport_core ureport_core1 ureport_core_invalid \ 5 | ureport_java ureport_kerneloops ureport_kerneloops2 \ 6 | ureport_python ureport_ruby \ 7 | ureport_systemd2 ureport_systemd77 ureport_kerneloops_nouveau \ 8 | ureport_duplicate ureport_duplicate2 ureport_duplicate3 \ 9 | ureport_duplicate4 ureport_solution ureport_solution_99 10 | -------------------------------------------------------------------------------- /tests/faftests/test_config.conf: -------------------------------------------------------------------------------- 1 | [Storage] 2 | ConnectString = sqlite:////tmp/faf_test_data/sqlite.db 3 | LobDir = /tmp/faf_test_data/lob 4 | 5 | [Ureport] 6 | Directory = /tmp/faf_test_data/reports/ 7 | AcceptAttachments = * 8 | # allowed values for known 9 | # BUG_OS_MAJOR_VERSION BUG_OS_MINOR_VERSION EQUAL_UREPORT_EXISTS 10 | Known = 11 | 12 | [Hub] 13 | debug = True 14 | proxy_setup = False 15 | secret_key = "NO." 16 | server_name = example.org 17 | 18 | [openid] 19 | enabled=true 20 | 21 | [fakebugzilla] 22 | api_url = http://fake_test_api_url 23 | web_url = http://fake_test_web_url 24 | api_key = FAKE_API_KEY_QR43290T4V743BN 25 | -------------------------------------------------------------------------------- /tests/retrace_outputs/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST= \ 2 | last_chance_0x0 \ 3 | last_chance_0x1 \ 4 | last_chance_0x2 \ 5 | last_chance_0x3 \ 6 | last_chance_0x4 \ 7 | last_chance_0x5 \ 8 | last_chance_0x6 \ 9 | last_chance_0x7 \ 10 | last_chance_0x8 \ 11 | last_chance_0x9 \ 12 | last_chance_0xa \ 13 | last_chance_0xb \ 14 | last_chance_0xc \ 15 | last_chance_0xd \ 16 | last_chance_0xe \ 17 | last_chance_0xf \ 18 | last_chance_0x10 \ 19 | third_full_0xd \ 20 | third_full_0xe \ 21 | third_full_0xf \ 22 | other_source_0xe \ 23 | other_source_0xf \ 24 | other_line_0xe \ 25 | other_line_0xf \ 26 | complex_0xffff 27 | -------------------------------------------------------------------------------- /config/plugins/Makefile.am: -------------------------------------------------------------------------------- 1 | pluginconf_DATA = \ 2 | centos.conf \ 3 | clonebz.conf \ 4 | centosmantisbt.conf \ 5 | celery_tasks.conf \ 6 | coredump.conf \ 7 | create-problems.conf \ 8 | dnf.conf \ 9 | fedora.conf \ 10 | fedorabz.conf \ 11 | fedmsg.conf \ 12 | java.conf \ 13 | kerneloops.conf \ 14 | pull-reports.conf \ 15 | python.conf \ 16 | retrace.conf \ 17 | retrace-remote.conf \ 18 | ruby.conf \ 19 | rhelbz.conf \ 20 | save-reports.conf \ 21 | sf-prefilter.conf \ 22 | symbol-transfer.conf \ 23 | web.conf 24 | 25 | pluginconfdir = $(sysconfdir)/faf/plugins 26 | 27 | EXTRA_DIST = $(pluginconf_DATA) 28 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = faftests sample_plugin_dir sample_reports sample_rpms test_webfaf \ 2 | retrace_outputs bin sample_repo 3 | 4 | TESTS = test_actions.py \ 5 | test_alembic.py \ 6 | test_bugzilla.py \ 7 | test_common.py \ 8 | test_create_problems.py \ 9 | test_checker.py \ 10 | test_find_report_solution.py \ 11 | test_mark_probably_fixed.py \ 12 | test_queries.py \ 13 | test_rpm.py \ 14 | test_save_reports.py \ 15 | test_storage.py \ 16 | test_stats.py \ 17 | test_report.py \ 18 | test_ureport.py \ 19 | test_utils.py \ 20 | test_rpm_metadata.py \ 21 | test_retrace.py \ 22 | test_dnf.py 23 | 24 | check_SCRIPTS = $(TESTS) 25 | 26 | check-local: check-TESTS 27 | 28 | EXTRA_DIST = $(check_SCRIPTS) 29 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = config src tests 4 | 5 | EXTRA_DIST = autogen.sh faf-version faf.spec \ 6 | init-scripts/faf-celery-beat.service \ 7 | init-scripts/faf-celery-worker.service \ 8 | init-scripts/faf-celery-tmpfiles.conf \ 9 | pylintrc README.md 10 | 11 | 12 | 13 | if HAVE_SYSTEMD 14 | systemdsystemunitdir=$(prefix)/lib/systemd/system/ 15 | systemdsystemunit_DATA = init-scripts/faf-celery-beat.service \ 16 | init-scripts/faf-celery-worker.service 17 | systemdtmpfilesdir=$(prefix)/lib/tmpfiles.d/ 18 | systemdtmpfiles_DATA = init-scripts/faf.conf \ 19 | init-scripts/faf-celery-tmpfiles.conf 20 | endif 21 | -------------------------------------------------------------------------------- /container/Dockerfile_db: -------------------------------------------------------------------------------- 1 | FROM docker.io/centos/postgresql-12-centos7 2 | 3 | USER root 4 | 5 | # Adds the semver extension on top of the official image 6 | RUN yum install --assumeyes epel-release && \ 7 | yum install --assumeyes gcc make rh-postgresql12-postgresql-devel wget which && \ 8 | yum clean all 9 | 10 | ENV PG_SEMVER_VERSION=0.32.0 11 | ENV PG_CONFIG=/opt/rh/rh-postgresql12/root/usr/bin/pg_config 12 | RUN cd /tmp/ && \ 13 | wget https://github.com/theory/pg-semver/archive/refs/tags/v${PG_SEMVER_VERSION}.tar.gz && \ 14 | tar xvf v${PG_SEMVER_VERSION}.tar.gz && \ 15 | cd pg-semver-${PG_SEMVER_VERSION}/ && \ 16 | make && \ 17 | make install 18 | 19 | # Run the container as user postgres 20 | USER 26 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.pyc 3 | *.pyo 4 | *~ 5 | .deps 6 | Makefile 7 | Makefile.in 8 | /m4 9 | /missing 10 | /compile 11 | /py-compile 12 | /configure 13 | /ltmain.sh 14 | /install-sh 15 | /depcomp 16 | faf-version 17 | 18 | /*.1 19 | /*.html 20 | /*.src.rpm 21 | /*.tar.xz 22 | /*.tar.gz 23 | /aclocal.m4 24 | /autom4te.cache 25 | /config.log 26 | /config.status 27 | /config.sub 28 | /config.guess 29 | /faf-*/ 30 | /faf.conf 31 | /faf.html/ 32 | /faf.info 33 | /i686 34 | /libtool 35 | /noarch 36 | /stamp-vti 37 | /texinfo.tex 38 | /version.texi 39 | /x86_64 40 | /tests/**/*.trs 41 | /test-driver 42 | /config/faf.conf 43 | /config/faf-web.conf 44 | /config/faf-web.conf 45 | /tests/**/*.log 46 | src/webfaf/templates/about.md 47 | 48 | .mypy_cache/ 49 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/archs.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO archs VALUES (1, 'x86_64'); 2 | INSERT INTO archs VALUES (2, 'i686'); 3 | INSERT INTO archs VALUES (3, 'i586'); 4 | INSERT INTO archs VALUES (4, 'i486'); 5 | INSERT INTO archs VALUES (5, 'i386'); 6 | INSERT INTO archs VALUES (6, 'ppc'); 7 | INSERT INTO archs VALUES (7, 'ppc64'); 8 | INSERT INTO archs VALUES (8, 'noarch'); 9 | INSERT INTO archs VALUES (9, 'src'); 10 | INSERT INTO archs VALUES (10, 's390x'); 11 | INSERT INTO archs VALUES (11, 's390'); 12 | INSERT INTO archs VALUES (12, 'ia64'); 13 | INSERT INTO archs VALUES (13, 'alpha'); 14 | INSERT INTO archs VALUES (14, 'sparc'); 15 | INSERT INTO archs VALUES (15, 'sparc64'); 16 | INSERT INTO archs VALUES (16, 'x86_x65'); 17 | INSERT INTO archs VALUES (17, 'i3868'); 18 | -------------------------------------------------------------------------------- /container/podman-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | faf-db: 4 | image: quay.io/fedoraci/faf-db:latest 5 | restart: always 6 | ports: 7 | - 5432:5432 8 | volumes: 9 | - faf-volume:/var/lib/pgsql/data:Z 10 | environment: 11 | POSTGRESQL_ADMIN_PASSWORD: scrt 12 | faf-redis: 13 | image: redis:latest 14 | restart: always 15 | ports: 16 | - 6379:6379 17 | faf: 18 | image: quay.io/fedoraci/faf:latest 19 | restart: always 20 | ports: 21 | - 8080:8080 22 | depends_on: 23 | - faf-db 24 | environment: 25 | PGHOST: faf-db 26 | PGUSER: postgres 27 | PGPASSWORD: scrt 28 | PGPORT: 5432 29 | PGDATABASE: faf 30 | RDSBROKER: "redis://faf-redis:6379/0" 31 | RDSBACKEND: "redis://faf-redis:6379/0" 32 | -------------------------------------------------------------------------------- /container/files/usr/bin/faf-celery-worker: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | source /etc/faf/celery-worker-env.conf 4 | 5 | case $1 in 6 | start) 7 | /usr/bin/python3 -m celery -C -A $CELERY_APP multi start $CELERYD_NODES \ 8 | --pidfile=${CELERYD_PID_FILE} \ 9 | --logfile=${CELERYD_LOG_FILE} \ 10 | --loglevel="${CELERYD_LOG_LEVEL}" \ 11 | $CELERYD_OPTS & 12 | ;; 13 | stop) 14 | /usr/bin/python3 -m celery multi stopwait $CELERYD_NODES \ 15 | --pidfile=${CELERYD_PID_FILE} & 16 | ;; 17 | reload) 18 | /usr/bin/python3 -m celery -C -A $CELERY_APP multi restart $CELERYD_NODES \ 19 | --pidfile=${CELERYD_PID_FILE} \ 20 | --logfile=${CELERYD_LOG_FILE} \ 21 | --loglevel="${CELERYD_LOG_LEVEL}" \ 22 | $CELERYD_OPTS & 23 | ;; 24 | esac 25 | -------------------------------------------------------------------------------- /src/schema/faf_schema/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along 14 | # with this program; if not, write to the Free Software Foundation, Inc., 15 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | -------------------------------------------------------------------------------- /tests/bin/eu-addr2line: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -n "$EU_ADDR2LINE_SAMPLE_DIR" ]; then 4 | FILE="${EU_ADDR2LINE_SAMPLE_DIR%/}/" 5 | fi 6 | 7 | while [ $# -gt 0 ]; 8 | do 9 | case "$1" in 10 | "--executable") 11 | FILE="$FILE$2" 12 | shift 13 | ;; 14 | 15 | "0x"*) 16 | FILE="${FILE}_$1" 17 | ;; 18 | 19 | "--debuginfo-path") 20 | shift 21 | ;; 22 | 23 | "--functions") 24 | ;; 25 | 26 | *) 27 | cat 2>&1 <&1 < Optional[str]: 12 | if value is not None: 13 | value = json.dumps(value) 14 | return value 15 | 16 | # pylint: disable=unused-argument 17 | def process_result_value(self, value, dialect) -> Optional[dict]: 18 | if value is not None: 19 | value = json.loads(value) 20 | return value 21 | 22 | # pylint: disable=unused-argument 23 | def process_literal_param(self, value, dialect) -> Any: 24 | return value 25 | 26 | @property 27 | def python_type(self) -> type: 28 | return json 29 | -------------------------------------------------------------------------------- /src/webfaf/templates/celery_tasks/results_item.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Tasks{% endblock %} 4 | 5 | {% block js %} 6 | {% endblock %} 7 | 8 | {% block body %} 9 |
10 |
11 |

Result {{task_result.id}}

12 |
13 |
Task
14 |
{{task_result.nice_task}}
15 |
Arguments
16 |
{{task_result.nice_args}}
17 |
Finished
18 |
{{task_result.finished_time.strftime("%Y-%m-%d %H:%M:%S")}}
19 |
State
20 |
{{task_result.state}}
21 |
22 |
23 |
Output
24 |
{{task_result.retval}}

Only the last 1000 characters are saved.

25 |
26 |
27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /container/files/usr/bin/faf-celery-beat: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | source /etc/faf/celery-beat-env.conf 4 | 5 | start_beat () { 6 | /usr/bin/python3 -m celery -C -A $CELERY_APP beat \ 7 | --pidfile=${CELERYD_PID_FILE} \ 8 | --logfile=${CELERYD_LOG_FILE} \ 9 | --loglevel="${CELERYD_LOG_LEVEL}" \ 10 | $CELERYD_OPTS & 11 | } 12 | 13 | kill_beat () { 14 | if [[ -f ${CELERYD_PID_FILE} ]]; then 15 | kill $(cat ${CELERYD_PID_FILE}) 16 | else 17 | echo "ERROR: Pidfile (${CELERYD_PID_FILE}) doesn't exist." 18 | echo "celery beat not running" 19 | exit 1 20 | fi 21 | 22 | } 23 | 24 | case $1 in 25 | start) 26 | start_beat 27 | ;; 28 | stop) 29 | kill_beat 30 | ;; 31 | reload) 32 | kill_beat 33 | start_beat 34 | ;; 35 | esac 36 | -------------------------------------------------------------------------------- /init-scripts/faf-celery-worker.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=FAF Celery worker 3 | After=network.target 4 | 5 | [Service] 6 | Type=forking 7 | User=faf 8 | Group=faf 9 | EnvironmentFile=/etc/faf/celery-worker-env.conf 10 | WorkingDirectory=/etc/faf 11 | ExecStart=/usr/bin/python3 -m celery -C -A ${CELERY_APP} multi start $CELERYD_NODES \ 12 | --pidfile=${CELERYD_PID_FILE} \ 13 | --logfile=${CELERYD_LOG_FILE} \ 14 | --loglevel="${CELERYD_LOG_LEVEL}" \ 15 | $CELERYD_OPTS 16 | ExecStop=/usr/bin/python3 -m celery multi stopwait $CELERYD_NODES \ 17 | --pidfile=${CELERYD_PID_FILE} 18 | ExecReload=/usr/bin/python3 -m celery -C -A ${CELERY_APP} multi restart $CELERYD_NODES \ 19 | --pidfile=${CELERYD_PID_FILE} \ 20 | --logfile=${CELERYD_LOG_FILE} \ 21 | --loglevel="${CELERYD_LOG_LEVEL}" \ 22 | $CELERYD_OPTS 23 | 24 | [Install] 25 | WantedBy=multi-user.target 26 | -------------------------------------------------------------------------------- /config/faf-logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root,main,thread 3 | 4 | [handlers] 5 | keys=main,thread 6 | 7 | [formatters] 8 | keys=main,thread 9 | 10 | # Used only if no other loggers are specified 11 | [logger_root] 12 | level=DEBUG 13 | handlers=main 14 | 15 | [logger_main] 16 | level=INFO 17 | handlers=main 18 | qualname=faf 19 | propagate=0 20 | 21 | [logger_thread] 22 | level=INFO 23 | handlers=thread 24 | qualname=faf.thread 25 | propagate=0 26 | 27 | [handler_main] 28 | level=DEBUG 29 | formatter=main 30 | class=StreamHandler 31 | args=[] 32 | 33 | [handler_thread] 34 | level=DEBUG 35 | formatter=thread 36 | class=StreamHandler 37 | args=[] 38 | 39 | [formatter_main] 40 | format=[%(asctime)s] %(levelname)s:%(name)s: %(message)s 41 | datefmt=%Y-%m-%d %H:%M:%S 42 | 43 | [formatter_thread] 44 | format=[%(asctime)s] %(levelname)s:%(name)s(%(threadName)s): %(message)s 45 | datefmt=%Y-%m-%d %H:%M:%S 46 | -------------------------------------------------------------------------------- /src/pyfaf/local.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | __all__ = ["etc", "var"] 20 | 21 | # Invalid name "xyz" for type constant 22 | # pylint: disable-msg=C0103 23 | 24 | etc = "/etc" 25 | var = "/var" 26 | -------------------------------------------------------------------------------- /src/webfaf/static/js/jquery.flot.simplelabel.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | function init(plot) { 3 | plot.hooks.draw.push(function (plot, ctx) { 4 | $.each(plot.getAxes(), function(axisName, axis) { 5 | if(axisName.charAt(0) == 'y') { 6 | elem = plot.getPlaceholder().parent().find('#ylabel'); 7 | 8 | elem.css('top', 9 | plot.getPlaceholder().offset().top 10 | + plot.height()/2 - elem.outerHeight()/2 11 | + 'px'); 12 | 13 | elem.css('left', 14 | plot.getPlaceholder().offset().left 15 | - (elem.outerWidth()/2 + 15) 16 | + 'px'); 17 | } 18 | }); 19 | }); 20 | } 21 | 22 | $.plot.plugins.push({ 23 | init: init, 24 | name: 'simplelabel', 25 | version: '0.1' 26 | }); 27 | 28 | })(jQuery); 29 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/list_table_rows.html: -------------------------------------------------------------------------------- 1 | {% for report in reports %} 2 | 3 | {{report.id}} 4 | {{report.component}} 5 | 6 | {% if report.crashfn %} 7 |
8 |
{{ report.crashfn }}
9 | 10 |
11 | {% endif %} 12 | 13 | {% if not report.archived %} 14 | {% if report.problem_id %}processed{% else %}new{% endif %} 15 | {% else %} 16 | archived 17 | {% endif %} 18 | {{report.type}} 19 | {{report.last_occurrence.strftime("%Y-%m-%d")}} 20 | {{report.first_occurrence.strftime("%Y-%m-%d")}} 21 | {{report.count|readable_int}} 22 | 23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /tests/test_webfaf/webfaftests/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # alter path so we can import faftests 5 | faftests_path = os.path.abspath(os.path.join(__file__, "../../..")) 6 | 7 | # alter path so we can import webfaf 8 | webfaf_path = os.path.join(os.path.abspath(os.path.join(faftests_path, "..")), "src") 9 | 10 | sys.path.insert(0, faftests_path) 11 | sys.path.insert(0, webfaf_path) 12 | os.environ["PATH"] = "{0}:{1}".format(webfaf_path, os.environ["PATH"]) 13 | 14 | import faftests 15 | from webfaf.webfaf_main import app 16 | 17 | 18 | class WebfafTestCase(faftests.DatabaseCase): 19 | 20 | def setUp(self): 21 | super(WebfafTestCase, self).setUp() 22 | 23 | app.config["DATABASE"] = self.postgresql.url() 24 | app.config["SQLALCHEMY_DATABASE_URI"] = self.postgresql.url() 25 | app.config["TESTING"] = True 26 | app.config["SQLALCHEMY_ECHO"] = not True 27 | self.app = app.test_client() 28 | 29 | def tearDown(self): 30 | super(WebfafTestCase, self).tearDown() 31 | -------------------------------------------------------------------------------- /src/pyfaf/bugtrackers/centosmantisbt.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.bugtrackers import mantisbt 20 | 21 | __all__ = ["CentosMantis"] 22 | 23 | # see https://github.com/abrt/faf/issues/695 24 | # pylint: disable=abstract-method 25 | 26 | class CentosMantis(mantisbt.Mantis): 27 | name = "centos-mantisbt" 28 | -------------------------------------------------------------------------------- /config/Makefile.am: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Config 3 | #============================================================================= 4 | 5 | SUBDIRS = plugins templates 6 | 7 | config_DATA = faf.conf \ 8 | faf-logging.conf 9 | 10 | if HAVE_SYSTEMD 11 | config_DATA += celery-beat-env.conf 12 | config_DATA += celery-worker-env.conf 13 | endif 14 | 15 | configdir = $(sysconfdir)/faf 16 | 17 | faf.conf: faf.conf.in 18 | sed -e 's|@localstatedir[@]|$(localstatedir)|g' \ 19 | -e 's|@sysconfdir[@]|$(sysconfdir)|g' $< > $@ 20 | 21 | httpdconf_DATA = faf-web.conf 22 | httpdconfdir = ${sysconfdir}/httpd/conf.d 23 | 24 | faf-web.conf: faf-web.conf.in 25 | sed -e "s|@PYTHONDIR@|$(pythondir)|g" $< > $@ 26 | 27 | logrotate_DATA = faf 28 | logrotatedir = ${sysconfdir}/logrotate.d 29 | 30 | EXTRA_DIST = celery-beat-env.conf \ 31 | celery-worker-env.conf \ 32 | faf.conf.in \ 33 | faf-logging.conf \ 34 | faf-web.conf.in \ 35 | faf 36 | -------------------------------------------------------------------------------- /tests/test_webfaf/test_summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | import unittest 4 | from webfaftests import WebfafTestCase 5 | 6 | 7 | class SummaryTestCase(WebfafTestCase): 8 | """ 9 | Tests for webfaf.summary 10 | """ 11 | 12 | def setUp(self): 13 | super(SummaryTestCase, self).setUp() 14 | self.basic_fixtures() 15 | 16 | self.save_report("ureport_f20") 17 | 18 | self.db.session.commit() 19 | 20 | def test_index_redirect(self): 21 | """ 22 | Index should redirect to /summary/ 23 | """ 24 | 25 | r = self.app.get("/") 26 | self.assertEqual(r.status_code, 302) 27 | self.assertIn(b"/summary/", r.data) 28 | 29 | def test_summary(self): 30 | """ 31 | Test presence of data on the summary page 32 | """ 33 | 34 | r = self.app.get("/summary/") 35 | 36 | self.assertIn(b"Fedora 20", r.data) 37 | self.assertIn(b" 1]", r.data) # graph point 38 | 39 | if __name__ == "__main__": 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /src/pyfaf/actions/archlist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.storage.opsys import Arch 21 | 22 | 23 | class ArchList(Action): 24 | name = "archlist" 25 | 26 | 27 | def run(self, cmdline, db) -> None: 28 | for item in db.session.query(Arch): 29 | print(item) 30 | -------------------------------------------------------------------------------- /src/webfaf/static/css/bootstrap-multiselect.css: -------------------------------------------------------------------------------- 1 | .multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li>label.multiselect-group{margin:0;padding:3px 20px;height:100%;font-weight:700}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.radio,.multiselect-container>li>a>label.checkbox{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0} -------------------------------------------------------------------------------- /src/pyfaf/actions/opsyslist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.storage.opsys import OpSys 21 | 22 | 23 | class OpSysList(Action): 24 | name = "opsyslist" 25 | 26 | 27 | def run(self, cmdline, db) -> None: 28 | for opsys in db.session.query(OpSys): 29 | print(opsys) 30 | -------------------------------------------------------------------------------- /src/pyfaf/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | __all__ = ["date", "decorators", "format", "parse", "proc", "storage"] 20 | 21 | from pyfaf.utils import date 22 | from pyfaf.utils import decorators 23 | from pyfaf.utils import format # pylint: disable=redefined-builtin 24 | from pyfaf.utils import parse 25 | from pyfaf.utils import proc 26 | from pyfaf.utils import storage 27 | -------------------------------------------------------------------------------- /tests/test_alembic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | import unittest 4 | import logging 5 | 6 | import faftests 7 | 8 | import os 9 | import inspect 10 | import sys 11 | 12 | from io import StringIO 13 | 14 | from pyfaf.storage import migrations 15 | from alembic.config import Config 16 | from alembic import command 17 | 18 | 19 | class AlembicTestCase(faftests.DatabaseCase): 20 | 21 | """ 22 | Test case for migrations by alembic 23 | """ 24 | 25 | def setUp(self): 26 | super(AlembicTestCase, self).setUp() 27 | self.basic_fixtures() 28 | 29 | def test_alembic_head(self): 30 | heads_ = StringIO() 31 | alembic_cfg = Config(stdout=heads_) 32 | alembic_cfg.set_main_option("script_location", 33 | os.path.dirname(inspect.getfile(migrations))) 34 | command.heads(alembic_cfg) 35 | heads = heads_.getvalue() 36 | heads = heads[:-1] 37 | 38 | self.assertNotIn('\n', heads) 39 | 40 | if __name__ == "__main__": 41 | logging.basicConfig(level=logging.INFO) 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /src/webfaf/templates/celery_tasks/results_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import paginator %} 3 | 4 | {% block title %}Task results{% endblock %} 5 | 6 | {% block js %} 7 | {% endblock %} 8 | 9 | {% block body %} 10 |
11 |
12 |

Task results

13 | Show only unsuccessful results 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% for r in task_results %} 22 | 23 | 24 | 25 | 26 | 27 | 28 | {% endfor %} 29 | 30 |
IDTaskTimeState
{{r.id}}{{r.nice_task}}{{r.finished_time.strftime("%Y-%m-%d %H:%M:%S")}}{{r.state}}
31 | {{ paginator(pagination, task_results|length) }} 32 |
33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/23bab42e7be7_initial_migration.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | 20 | """ 21 | Initial migration 22 | 23 | Revision ID: 23bab42e7be7 24 | Revises: None 25 | Create Date: 2014-07-31 10:20:27.506558 26 | """ 27 | 28 | # revision identifiers, used by Alembic. 29 | revision = '23bab42e7be7' 30 | down_revision = None 31 | 32 | 33 | def upgrade() -> None: 34 | pass 35 | 36 | 37 | def downgrade() -> None: 38 | pass 39 | -------------------------------------------------------------------------------- /src/pyfaf/storage/externalfaf.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from sqlalchemy.sql.schema import Column 20 | from sqlalchemy.types import Integer, String 21 | 22 | from .generic_table import GenericTable 23 | 24 | 25 | class ExternalFafInstance(GenericTable): 26 | __tablename__ = "externalfafinstances" 27 | 28 | id = Column(Integer, primary_key=True) 29 | name = Column(String(256), nullable=False, index=True) 30 | baseurl = Column(String(1024), nullable=False) 31 | -------------------------------------------------------------------------------- /src/webfaf/templates/celery_tasks/action_run.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | 4 | {% block title %}Run or schedule action {{action_name}}{% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |

Run or schedule action {{action_name}}

10 |
11 |
12 |
13 |
14 |
15 | {% for field in action_form %} 16 | {{ render_field(field) }} 17 | {% else %} 18 |

This action requires no parameters.

19 | {% endfor %} 20 |

22 |
23 |
24 | {% for field in schedule_form %} 25 | {{ render_field(field) }} 26 | {% endfor %} 27 |

28 |
29 |
30 |
31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/associate_bug.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | 4 | {% block title %}Associate bug with report{% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |

Associate bug with report {{report.id}}

10 |
11 | {{ render_field(form.bug_id) }} 12 | {{ render_field(form.bugtracker) }} 13 |

14 |
15 |
16 | {% if new_bug_urls %} 17 |
18 |
19 |

By clicking the links below, you'll be taken to a pre-filled form allowing you to create a new bug for this report. After creating the bug, please copy it's ID to the form above and associate it.

20 | {% for (text, url) in new_bug_urls %} 21 |

Create new bug for {{text}}...

22 | {% endfor %} 23 | 24 |
25 | {% endif %} 26 | 27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /src/pyfaf/storage/user.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from sqlalchemy.sql.schema import Column 20 | from sqlalchemy.types import Boolean, String 21 | 22 | from .generic_table import GenericTable 23 | 24 | 25 | class User(GenericTable): 26 | __tablename__ = "users" 27 | 28 | username = Column(String(100), nullable=False, primary_key=True) 29 | mail = Column(String(150), nullable=False) 30 | admin = Column(Boolean, default=False) 31 | privileged = Column(Boolean, default=False) 32 | -------------------------------------------------------------------------------- /src/pyfaf/utils/contextmanager.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from contextlib import contextmanager 3 | from io import StringIO 4 | from typing import Generator, Tuple 5 | 6 | 7 | @contextmanager 8 | def captured_output() -> Generator[Tuple[StringIO, StringIO], None, None]: 9 | """ 10 | Capture stdout and stderr output of the executed block 11 | 12 | Example: 13 | 14 | with captured_output() as (out, err): 15 | foo() 16 | """ 17 | 18 | new_out, new_err = StringIO(), StringIO() 19 | old_out, old_err = sys.stdout, sys.stderr 20 | try: 21 | sys.stdout, sys.stderr = new_out, new_err 22 | yield sys.stdout, sys.stderr 23 | finally: 24 | sys.stdout, sys.stderr = old_out, old_err 25 | 26 | 27 | @contextmanager 28 | def captured_output_combined() -> Generator[StringIO, None, None]: 29 | """ 30 | Capture stdout and stderr combined output of the executed block 31 | 32 | Example: 33 | 34 | with captured_output_combined() as out: 35 | foo() 36 | """ 37 | 38 | new_out = StringIO() 39 | old_out, old_err = sys.stdout, sys.stderr 40 | try: 41 | sys.stdout, sys.stderr = new_out, new_out 42 | yield sys.stdout 43 | finally: 44 | sys.stdout, sys.stderr = old_out, old_err 45 | -------------------------------------------------------------------------------- /src/webfaf/templates/celery_tasks/schedule_item.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | 4 | {% block title %}Schedule item {{pt_name}}{% endblock %} 5 | 6 | {% block body %} 7 |
8 |
9 |

Schedule item {{pt_name}}

10 |
11 |
12 |
13 |
14 | {% if action_form %} 15 |
16 | {% for field in action_form %} 17 | {{ render_field(field) }} 18 | {% else %} 19 |

This action requires no parameters.

20 | {% endfor %} 21 |
22 | {% endif %} 23 |
24 | {% for field in schedule_form %} 25 | {{ render_field(field) }} 26 | {% endfor %} 27 |

28 | 29 | 30 |

31 |
32 |
33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /docs/fixture_notes: -------------------------------------------------------------------------------- 1 | faf-fixtures 2 | ------------- 3 | 4 | Generates/loads fixtures for testing purposes. 5 | 6 | Currently, there these types of fixtures are available: 7 | 1) faf-fixtures --dumb 8 | 2) faf-fixtures --realworld 9 | 10 | Dumb fixtures are only good for web UI testing, 11 | they are generated randomly and contain fake 12 | symbols, components, ... 13 | 14 | Real-world fixtures are also usable for 15 | retracing and backtrace processing, they 16 | contain real data (components, builds, rpms, tags, ..). 17 | 18 | These data are partially stored in SQL files 19 | `pyfaf/storage/fixtures/sql` directory. As we also need 20 | RPM files to test retracing and uReport handling, these 21 | are packed and stored in some other location than git. 22 | During the fixture generation process, this file 23 | is downloaded and extracted to faf lob dir. 24 | 25 | URL pointing to downloaded archive is stored in 26 | `pyfaf/storage/fixtures/lob_download_location`. 27 | 28 | To create updated version of real-world fixtures, 29 | edit and run `faf-fixtures-update-realworld` script, 30 | which downloads specified components, updates 31 | affected SQL files and packs new lob archive. 32 | 33 | When you are happy with the new version, upload the 34 | archive publicly and update `lob_download_location` 35 | respectively. 36 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 ABRT Team 2 | # Copyright (C) 2020 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | ${message} 21 | 22 | Revision ID: ${up_revision} 23 | Revises: ${down_revision} 24 | Create Date: ${create_date} 25 | """ 26 | 27 | from alembic import op 28 | import sqlalchemy as sa 29 | ${imports if imports else ""} 30 | 31 | # revision identifiers, used by Alembic. 32 | revision = ${repr(up_revision)} 33 | down_revision = ${repr(down_revision)} 34 | 35 | 36 | def upgrade(): 37 | ${upgrades if upgrades else "pass"} 38 | 39 | 40 | def downgrade(): 41 | ${downgrades if downgrades else "pass"} 42 | -------------------------------------------------------------------------------- /src/webfaf/templates/problems/list_table_rows.html: -------------------------------------------------------------------------------- 1 | {% from '_helpers.html' import external_bugs %} 2 | {%- for problem in problems %} 3 | 4 | 5 | 6 | {{ problem.id }} 7 | 8 | 9 | 10 | {%- for name in problem.unique_component_names %} 11 | {{ name }}{% if not loop.last %}, {% endif %} 12 | {%- endfor %} 13 | {%- if problem.tainted %} 14 | Tainted 15 | {%- endif %} 16 | 17 | 18 | {% if problem.crash_function %} 19 |
20 |
{{ problem.crash_function }}
21 | 22 |
23 | {% endif %} 24 | 25 | 26 | 27 | {{ problem.status }} 28 | 29 | 30 | 31 | {{ external_bugs(problem.id, problem.bugs, false) }} 32 | 33 | 34 | {%- if problem.probable_fixes %} 35 | {{ problem.probable_fixes|join(", ") }} 36 | {%- endif %} 37 | 38 | {{ problem.count|readable_int }} 39 | 40 | {%- endfor %} 41 | -------------------------------------------------------------------------------- /container/Dockerfile_local: -------------------------------------------------------------------------------- 1 | FROM abrt/faf 2 | # rhbz#1733043 workaround 3 | ENV TERM=linux 4 | 5 | USER root 6 | 7 | # install devel tools 8 | RUN dnf -y install git-core make rpm-build sudo tito vim which 9 | 10 | # Copy sources to the docker image 11 | COPY --chown=faf:faf . /faf/ 12 | 13 | # From not on work from faf directory 14 | WORKDIR '/faf' 15 | 16 | # Change owner of /faf, clean git and install dependences 17 | RUN git clean -dfx && \ 18 | dnf -y --setopt=strict=0 --setopt=tsflags=nodocs builddep faf.spec && \ 19 | dnf clean all 20 | 21 | # Build as non root 22 | USER faf 23 | 24 | ENV HOME /faf 25 | 26 | # Build faf 27 | RUN tito build --rpm --test 28 | 29 | #And continue as root 30 | USER 0 31 | 32 | # Update ABRT Analytics (FAF) 33 | RUN rpm -Uvh /tmp/tito/noarch/faf-* && \ 34 | sed -i -e"s/everyone_is_admin\s*=\s*false/everyone_is_admin = true/i" /etc/faf/plugins/web.conf && \ 35 | echo 'Defaults env_keep = "PGHOST PGUSER PGPASSWORD PGPORT PGDATABASE RDSBROKER RDSBACKEND"' >> /etc/sudoers.d/faf && \ 36 | /usr/libexec/fix-permissions /faf && \ 37 | /usr/libexec/fix-permissions /run/faf-celery && \ 38 | /usr/libexec/fix-permissions /var/log/faf && \ 39 | /usr/libexec/fix-permissions /var/spool/faf && \ 40 | /usr/libexec/fix-permissions /etc/faf/ 41 | 42 | #Switch workdir back to / 43 | WORKDIR '/' 44 | -------------------------------------------------------------------------------- /faf_setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | ARCH_LIST="src noarch x86_64 i386 i486 i586 i686 armv5tel armv7hl ppc ppc64 s390 s390x" 5 | MIRROR_URL="http://mirror.karneval.cz/pub/linux/fedora/linux" 6 | 7 | # add architectures and releases 8 | # ------------------------------ 9 | 10 | faf archadd $ARCH_LIST 11 | faf opsysadd Fedora 12 | faf pull-releases -o fedora 13 | 14 | # add fedora repositories 15 | # ----------------------- 16 | 17 | tmpdir=$( mktemp -d ) 18 | cp repos/*.repo $tmpdir 19 | 20 | # replace original URL with our selected mirror 21 | sed -i "s~http://download.fedoraproject.org/pub/fedora/linux~$MIRROR_URL~g" $tmpdir/*.repo 22 | 23 | # import repofiles 24 | for repofile in $tmpdir/*.repo; do 25 | faf repoimport dnf $repofile 26 | done 27 | 28 | # assign os/debug repositories 29 | for reponame in $( faf repolist | grep -v source ); do 30 | faf repoassign $reponame Fedora i386 x86_64 31 | done 32 | 33 | # assign source repositories 34 | for reponame in $( faf repolist | grep source ); do 35 | faf repoassign $reponame Fedora src 36 | done 37 | 38 | rm -rf $tmpdir 39 | 40 | # print result 41 | # ------------ 42 | 43 | echo -e "\nSetup complete\n" 44 | 45 | echo -e "\nAdded architectures:\n" 46 | faf archlist 47 | 48 | echo -e "\nAdded releases:\n" 49 | faf releaselist 50 | 51 | echo -e "\nAdded repositories:\n" 52 | faf repolist --detailed 53 | 54 | -------------------------------------------------------------------------------- /config/faf-web.conf.in: -------------------------------------------------------------------------------- 1 | # WSGI handler 2 | WSGIPythonOptimize 1 3 | WSGISocketPrefix /var/spool/faf/wsgi 4 | WSGIDaemonProcess faf user=faf group=faf processes=3 threads=5 5 | WSGIScriptAlias /faf @PYTHONDIR@/webfaf/hub.wsgi process-group=faf application-group=%{GLOBAL} 6 | 7 | 8 | 9 | # Apache 2.4 10 | Require all granted 11 | 12 | 13 | # Apache 2.2 14 | Order allow,deny 15 | Allow from all 16 | 17 | 18 | 19 | # project main 20 | 21 | Options Indexes 22 | IndexOptions FancyIndexing 23 | 24 | # Apache 2.4 25 | Require all granted 26 | 27 | 28 | # Apache 2.2 29 | Order allow,deny 30 | Allow from all 31 | 32 | 33 | 34 | # static 35 | Alias /faf/static "/usr/share/faf/web/static" 36 | 37 | Options Indexes 38 | IndexOptions FancyIndexing 39 | 40 | # Apache 2.4 41 | Require all granted 42 | 43 | 44 | # Apache 2.2 45 | Order allow,deny 46 | Allow from all 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/13557f1962e6_ureport_added_certainty.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Ureport add certainty 21 | 22 | Revision ID: 13557f1962e6 23 | Revises: 2573150e1470 24 | Create Date: 2016-08-09 10:01:00.818966 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = "13557f1962e6" 32 | down_revision = "89d35a57f82b" 33 | 34 | 35 | def upgrade() -> None: 36 | add_column("reports", sa.Column("max_certainty", sa.Integer, nullable=True)) 37 | 38 | 39 | def downgrade() -> None: 40 | drop_column("reports", "max_certainty") 41 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/21345f007bdf_add_privileged_user_field.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Add privileged user field 21 | 22 | Revision ID: 21345f007bdf 23 | Revises: cef2fcd69ef 24 | Create Date: 2015-08-18 14:56:02.571419 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '21345f007bdf' 32 | down_revision = 'cef2fcd69ef' 33 | 34 | 35 | def upgrade() -> None: 36 | add_column('users', sa.Column('privileged', sa.Boolean(), nullable=True)) 37 | 38 | 39 | def downgrade() -> None: 40 | drop_column('users', 'privileged') 41 | -------------------------------------------------------------------------------- /src/webfaf/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Plugins may be placed inside this directory. All modules that don't start with _ 21 | are loaded. Modules must contain `blueprint` and `url_prefix` attributes. 22 | 23 | example.py: 24 | 25 | from flask import Blueprint 26 | 27 | url_prefix = "/example" 28 | 29 | example_blueprint = Blueprint("example", __name__) 30 | 31 | 32 | @example_blueprint.route('/') 33 | def hello(): 34 | return "Hello world!" 35 | 36 | blueprint = example_blueprint 37 | 38 | blueprint_menu = [{ 39 | "title": "Example", 40 | "route": "example.hello", 41 | "admin_required": False, 42 | }, ] 43 | 44 | """ 45 | -------------------------------------------------------------------------------- /src/pyfaf/actions/extfafshow.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_external_faf_instances 21 | from pyfaf.utils.format import as_table 22 | 23 | 24 | class ExternalFafShow(Action): 25 | name = "extfafshow" 26 | 27 | 28 | def run(self, cmdline, db) -> None: 29 | header = ["ID", "Name", "Base URL"] 30 | 31 | db_instances = get_external_faf_instances(db) 32 | data = [] 33 | for db_instance in sorted(db_instances, key=lambda x: x.id): 34 | data.append((db_instance.id, db_instance.name, db_instance.baseurl)) 35 | 36 | print(as_table(header, data, margin=2)) 37 | -------------------------------------------------------------------------------- /src/pyfaf/actions/releaselist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.storage.opsys import OpSysRelease 21 | 22 | 23 | class ReleaseList(Action): 24 | name = "releaselist" 25 | 26 | 27 | def run(self, cmdline, db) -> None: 28 | for opsysrelease in db.session.query(OpSysRelease): 29 | if not cmdline.all and opsysrelease.status != "ACTIVE": 30 | continue 31 | 32 | print(opsysrelease) 33 | 34 | def tweak_cmdline_parser(self, parser) -> None: 35 | parser.add_argument("--all", action="store_true", 36 | help="list all releases (non-active)") 37 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/acd3d9bf85d1_ignore_private_bz.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 ABRT Team 2 | # Copyright (C) 2017 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Ignore private bugzilla bugz 21 | 22 | Revision ID: acd3d9bf85d1 23 | Revises: 168c63b81f85 24 | Create Date: 2017-07-25 09:03:53.335397 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = "acd3d9bf85d1" 32 | down_revision = "168c63b81f85" 33 | 34 | 35 | def upgrade() -> None: 36 | add_column("bzbugs", sa.Column("private", sa.Boolean(), nullable=False, server_default="f")) 37 | 38 | 39 | def downgrade() -> None: 40 | drop_column("bzbugs", "private") 41 | -------------------------------------------------------------------------------- /tests/sample_reports/ureport_systemd2: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": { 3 | "version": "0.13", 4 | "name": "satyr" 5 | }, 6 | "reason": "Program /usr/lib/systemd/systemd-logind was terminated by signal 6", 7 | "problem": { 8 | "stacktrace": [ 9 | { 10 | "crash_thread": true, 11 | "frames": [ 12 | { 13 | "build_id": "c15e903efc9dd21b8a81a6539d7df9401d16e6d0", 14 | "build_id_offset": 220249, 15 | "file_name": "/lib64/libc.so.6", 16 | "address": 140701620345945, 17 | "fingerprint": "f33186a4c862fb0751bca60701f553b829210477", 18 | "function_name": "raise" 19 | } 20 | ] 21 | } 22 | ], 23 | "executable": "/usr/lib/systemd/systemd-logind", 24 | "signal": 6, 25 | "component": "systemd", 26 | "user": { 27 | "local": true, 28 | "root": false 29 | }, 30 | "type": "core" 31 | }, 32 | "packages": [ 33 | { 34 | "name": "systemd", 35 | "epoch": 0, 36 | "version": "2", 37 | "architecture": "x86_64", 38 | "package_role": "affected", 39 | "release": "0", 40 | "install_time": 1398699808 41 | } 42 | ], 43 | "os": { 44 | "cpe": "cpe:/o:fedoraproject:fedora:20", 45 | "version": "20", 46 | "name": "fedora", 47 | "architecture": "x86_64" 48 | }, 49 | "ureport_version": 2 50 | } -------------------------------------------------------------------------------- /tests/sample_reports/ureport_systemd77: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": { 3 | "version": "0.13", 4 | "name": "satyr" 5 | }, 6 | "reason": "Program /usr/lib/systemd/systemd-logind was terminated by signal 6", 7 | "problem": { 8 | "stacktrace": [ 9 | { 10 | "crash_thread": true, 11 | "frames": [ 12 | { 13 | "build_id": "c15e903efc9dd21b8a81a6539d7df9401d16e6d0", 14 | "build_id_offset": 220249, 15 | "file_name": "/lib64/libc.so.6", 16 | "address": 140701620345945, 17 | "fingerprint": "f33186a4c862fb0751bca60701f553b829210477", 18 | "function_name": "raise" 19 | } 20 | ] 21 | } 22 | ], 23 | "executable": "/usr/lib/systemd/systemd-logind", 24 | "signal": 6, 25 | "component": "systemd", 26 | "user": { 27 | "local": true, 28 | "root": false 29 | }, 30 | "type": "core" 31 | }, 32 | "packages": [ 33 | { 34 | "name": "systemd", 35 | "epoch": 0, 36 | "version": "77", 37 | "architecture": "x86_64", 38 | "package_role": "affected", 39 | "release": "0", 40 | "install_time": 1398699808 41 | } 42 | ], 43 | "os": { 44 | "cpe": "cpe:/o:fedoraproject:fedora:20", 45 | "version": "20", 46 | "name": "fedora", 47 | "architecture": "x86_64" 48 | }, 49 | "ureport_version": 2 50 | } -------------------------------------------------------------------------------- /tests/test_common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | import unittest 4 | import logging 5 | 6 | import faftests 7 | 8 | from pyfaf.common import import_dir, load_plugins, load_plugin_types 9 | 10 | from sample_plugin_dir.base import Base 11 | from sample_plugin_dir.plugin import Sub 12 | 13 | 14 | class CommonsTestCase(faftests.DatabaseCase): 15 | """ 16 | Test pyfaf.common 17 | """ 18 | 19 | def test_import_dir(self): 20 | """ 21 | Test if import_dir imports correct files 22 | """ 23 | 24 | import_dir("sample_plugin_dir", "sample_plugin_dir") 25 | 26 | self.assertEqual(len(Base.__subclasses__()), 1) 27 | 28 | def test_load_plugins(self): 29 | """ 30 | Test if load_plugins returns correct results 31 | """ 32 | 33 | plugins = load_plugins(Base) 34 | self.assertIn('sub-plugin', plugins) 35 | self.assertIs(isinstance(plugins['sub-plugin'], Sub), True) 36 | self.assertIs(isinstance(plugins['sub-plugin'], Base), True) 37 | 38 | def test_load_plugin_types(self): 39 | """ 40 | Test if load_plugin_types loads correct classes 41 | """ 42 | 43 | types = load_plugin_types(Base) 44 | self.assertIn('sub', types) 45 | self.assertIs(issubclass(types['sub'], Base), True) 46 | 47 | if __name__ == "__main__": 48 | logging.basicConfig(level=logging.INFO) 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /m4/ax_python_module.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_python_module.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PYTHON_MODULE(modname[, fatal]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Checks for Python module. 12 | # 13 | # If fatal is non-empty then absence of a module will trigger an error. 14 | # 15 | # LICENSE 16 | # 17 | # Copyright (c) 2008 Andrew Collier 18 | # 19 | # Copying and distribution of this file, with or without modification, are 20 | # permitted in any medium without royalty provided the copyright notice 21 | # and this notice are preserved. This file is offered as-is, without any 22 | # warranty. 23 | 24 | #serial 5 25 | 26 | AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE]) 27 | AC_DEFUN([AX_PYTHON_MODULE],[ 28 | if test -z $PYTHON; 29 | then 30 | PYTHON="python" 31 | fi 32 | PYTHON_NAME=`basename $PYTHON` 33 | AC_MSG_CHECKING($PYTHON_NAME module: $1) 34 | $PYTHON -c "import $1" 2>/dev/null 35 | if test $? -eq 0; 36 | then 37 | AC_MSG_RESULT(yes) 38 | eval AS_TR_CPP(HAVE_PYMOD_$1)=yes 39 | else 40 | AC_MSG_RESULT(no) 41 | eval AS_TR_CPP(HAVE_PYMOD_$1)=no 42 | # 43 | if test -n "$2" 44 | then 45 | AC_MSG_ERROR(failed to find required module $1) 46 | exit 1 47 | fi 48 | fi 49 | ]) 50 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run unit tests 2 | on: 3 | pull_request: 4 | branches: [master] 5 | push: 6 | branches: [master] 7 | jobs: 8 | test: 9 | container: 10 | image: quay.io/fedora/fedora:latest 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out sources 14 | uses: actions/checkout@v3 15 | 16 | - name: Install build environment 17 | run: | 18 | dnf install --assumeyes --setopt=install_weak_deps=False \ 19 | autoconf automake dnf-plugins-core make 20 | dnf copr enable --assumeyes @abrt/faf-el8-devel 21 | 22 | - name: Install build dependencies 23 | run: dnf builddep --assumeyes --setopt=install_weak_deps=False --spec faf.spec 24 | 25 | - name: Generate build files 26 | run: | 27 | # We need an unprivileged user in order to run some Postgres-related tests. 28 | useradd --no-create-home runner 29 | # Doing this would be largely unnecessary had non-srcdir builds worked. 30 | chown -R runner: . 31 | sudo -u runner ./autogen.sh 32 | 33 | - name: Build 34 | run: sudo -u runner make -j 35 | 36 | - name: Run tests 37 | run: sudo -u runner make check 38 | 39 | - name: Upload test logs 40 | uses: actions/upload-artifact@v2 41 | with: 42 | name: testsuite.log 43 | path: tests/**/test-suite.log 44 | if: failure() 45 | -------------------------------------------------------------------------------- /container/files/usr/bin/run_faf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | USER_ID=$(id -u) 4 | GROUP_ID=$(id -g) 5 | 6 | # Openshift runs containers with user that has assigned UID >= 1000000000 7 | # Because there is no record of this user in /etc/passwd, it causes problems with some 8 | # applications. We edit the /etc/passwd so the user is assigned as faf. 9 | if [ x"$USER_ID" != x"0" -a x"$USER_ID" != x"997" ];then 10 | echo "faf:x:${USER_ID}:${GROUP_ID}::/etc/faf:/sbin/nologin" >> /etc/passwd 11 | fi 12 | 13 | # Recreate directory structure (persistent volume issue) 14 | mkdir -p /var/spool/faf/lob \ 15 | /var/spool/faf/attachments/archive \ 16 | /var/spool/faf/attachments/deferred \ 17 | /var/spool/faf/attachments/incoming \ 18 | /var/spool/faf/attachments/saved \ 19 | /var/spool/faf/reports/archive \ 20 | /var/spool/faf/reports/deferred \ 21 | /var/spool/faf/reports/incoming \ 22 | /var/spool/faf/reports/saved \ 23 | || exit 1 24 | 25 | createdb 26 | if [ $? == 0 ] 27 | then 28 | psql -c "CREATE EXTENSION semver" 29 | faf-migrate-db --create-all 30 | faf-migrate-db --stamp-only 31 | faf init 32 | faf pull-releases -o fedora 33 | else 34 | faf-migrate-db 35 | fi 36 | 37 | /usr/bin/faf-celery-worker start 38 | /usr/bin/faf-celery-beat start 39 | 40 | /usr/sbin/uwsgi --ini /etc/uwsgi.ini --logto /var/log/faf/uwsgi_logs & 41 | /usr/sbin/httpd -DFOREGROUND 42 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/729a154b1609_index_reportpackages.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 ABRT Team 2 | # Copyright (C) 2016 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Create index on reportpackages table 21 | 22 | Revision ID: 729a154b1609 23 | Revises: f43edd5b636d 24 | Create Date: 2018-06-12 14:53:06.150898 25 | """ 26 | 27 | from alembic.op import create_index, drop_index, f 28 | 29 | # revision identifiers, used by Alembic. 30 | revision = '729a154b1609' 31 | down_revision = 'f43edd5b636d' 32 | 33 | index_name = 'ix_reportpackages_report_id_installed_package_id' 34 | 35 | def upgrade() -> None: 36 | create_index(f(index_name), 'reportpackages', ['report_id', 'installed_package_id']) 37 | 38 | 39 | def downgrade() -> None: 40 | drop_index(f(index_name), table_name='reportpackages') 41 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/48550f308625_add_symbolsource_retrace_fail_count.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Add SymbolSource retrace_fail_count 21 | 22 | Revision ID: 48550f308625 23 | Revises: 1c7edfbf8941 24 | Create Date: 2015-04-27 10:26:28.975738 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = "48550f308625" 32 | down_revision = "1c7edfbf8941" 33 | 34 | 35 | def upgrade() -> None: 36 | add_column("symbolsources", sa.Column("retrace_fail_count", sa.Integer(), 37 | nullable=False, server_default="0")) 38 | 39 | 40 | def downgrade() -> None: 41 | drop_column("symbolsources", "retrace_fail_count") 42 | -------------------------------------------------------------------------------- /src/pyfaf/bugtrackers/fedorabz.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from typing import Generator 20 | 21 | from pyfaf.bugtrackers import bugzilla 22 | 23 | __all__ = ["FedoraBugzilla"] 24 | 25 | 26 | class FedoraBugzilla(bugzilla.Bugzilla): 27 | name = "fedora-bugzilla" 28 | 29 | def list_bugs(self, *args, **kwargs) -> Generator[int, None, None]: 30 | 31 | abrt_specific = dict( 32 | status_whiteboard="abrt_hash", 33 | status_whiteboard_type="allwordssubstr", 34 | product="Fedora", 35 | ) 36 | 37 | if "custom_fields" in kwargs: 38 | kwargs["custom_fields"].update(abrt_specific) 39 | else: 40 | kwargs["custom_fields"] = abrt_specific 41 | 42 | return super().list_bugs(*args, **kwargs) 43 | -------------------------------------------------------------------------------- /tests/test_checker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | import unittest 4 | import logging 5 | 6 | import faftests 7 | 8 | from pyfaf.checker import * 9 | 10 | 11 | 12 | class CheckerTestCase(faftests.TestCase): 13 | """ 14 | Test pyfaf.checker 15 | """ 16 | 17 | def test_mandatory(self): 18 | """ 19 | Test if mandatory=False is correctly handled 20 | """ 21 | 22 | chk = DictChecker({ 23 | "key1_mandatory": IntChecker(minval=0, mandatory=True), 24 | "key2_optional": IntChecker(minval=0, mandatory=False), 25 | "key3_mandatory": IntChecker(minval=0), #default mandatory=True 26 | }) 27 | 28 | valid1 = { 29 | "key1_mandatory": 1, 30 | "key2_optional": 1, 31 | "key3_mandatory": 1, 32 | } 33 | 34 | valid2 = { 35 | "key1_mandatory": 1, 36 | "key3_mandatory": 1, 37 | } 38 | 39 | invalid1 = { 40 | "key1_mandatory": 1, 41 | "key2_optional": -1, 42 | "key3_mandatory": 1, 43 | } 44 | 45 | invalid2 = { 46 | "key1_mandatory": -1, 47 | "key3_mandatory": 1, 48 | } 49 | 50 | chk.check(valid1) 51 | chk.check(valid2) 52 | self.assertRaises(CheckError, chk.check, invalid1) 53 | self.assertRaises(CheckError, chk.check, invalid2) 54 | 55 | 56 | if __name__ == "__main__": 57 | logging.basicConfig(level=logging.INFO) 58 | unittest.main() 59 | -------------------------------------------------------------------------------- /src/pyfaf/utils/format.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from functools import reduce 20 | 21 | __all__ = ["as_table"] 22 | 23 | 24 | def as_table(headers, data, margin=1, separator=" ") -> str: 25 | """ 26 | Return `headers` and `data` lists formatted as table. 27 | """ 28 | 29 | headers = list(map(str, headers)) 30 | data = [list(map(str, x)) for x in data] 31 | 32 | widths = reduce( 33 | lambda x, y: [max(a_b[0], a_b[1]) for a_b in list(zip(x, y))], 34 | [map(len, x) for x in data] + [map(len, headers)], 35 | [0 for _ in headers]) 36 | 37 | fmt = "" 38 | for num, width in enumerate(widths): 39 | fmt += "{{{0}:<{1}}}{2}".format(num, width, separator * margin) 40 | fmt += "\n" 41 | 42 | # Used * or ** magic 43 | return "".join([fmt.format(*row) for row in [headers] + data]) 44 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/31d0249e8d4c_create_users_table.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Create users table 21 | 22 | Revision ID: 31d0249e8d4c 23 | Revises: 7fa8b3134f0 24 | Create Date: 2014-09-24 14:49:20.793855 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '31d0249e8d4c' 32 | down_revision = '7fa8b3134f0' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table( 37 | 'users', 38 | sa.Column('username', sa.String(length=100), nullable=False), 39 | sa.Column('mail', sa.String(length=150), nullable=False), 40 | sa.Column('admin', sa.Boolean(), default=False), 41 | sa.PrimaryKeyConstraint('username'), 42 | ) 43 | 44 | 45 | def downgrade() -> None: 46 | drop_table('users') 47 | -------------------------------------------------------------------------------- /src/pyfaf/actions/pull_bug.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.bugtrackers import bugtrackers 21 | 22 | 23 | class PullBug(Action): 24 | name = "pull-bug" 25 | 26 | def run(self, cmdline, db) -> int: 27 | tracker = bugtrackers[cmdline.bugtracker] 28 | 29 | if not tracker.installed(db): 30 | self.log_error("Bugtracker is not installed") 31 | return 1 32 | 33 | tracker.download_bug_to_storage(db, cmdline.BUG_ID) 34 | 35 | return 0 36 | 37 | def tweak_cmdline_parser(self, parser) -> None: 38 | parser.add_bugtracker(required=True, 39 | help="pull bug from this bug tracker") 40 | 41 | parser.add_argument("BUG_ID", validators=[("InputRequired", {})], 42 | help="download bug with this ID") 43 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/sql/packages.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO packages VALUES(1,NULL,1,2,'glibc-utils','rpm'); 2 | INSERT INTO packages VALUES(2,NULL,1,2,'glibc-debuginfo-common','rpm'); 3 | INSERT INTO packages VALUES(3,NULL,1,2,'glibc-common','rpm'); 4 | INSERT INTO packages VALUES(4,NULL,1,2,'glibc-devel','rpm'); 5 | INSERT INTO packages VALUES(5,NULL,1,2,'glibc','rpm'); 6 | INSERT INTO packages VALUES(6,NULL,1,2,'glibc-debuginfo','rpm'); 7 | INSERT INTO packages VALUES(7,NULL,1,2,'nscd','rpm'); 8 | INSERT INTO packages VALUES(8,NULL,1,2,'glibc-headers','rpm'); 9 | INSERT INTO packages VALUES(9,NULL,1,2,'glibc-static','rpm'); 10 | INSERT INTO packages VALUES(10,NULL,1,1,'glibc-common','rpm'); 11 | INSERT INTO packages VALUES(11,NULL,1,1,'glibc-static','rpm'); 12 | INSERT INTO packages VALUES(12,NULL,1,1,'glibc-debuginfo-common','rpm'); 13 | INSERT INTO packages VALUES(13,NULL,1,1,'glibc-devel','rpm'); 14 | INSERT INTO packages VALUES(14,NULL,1,1,'glibc-utils','rpm'); 15 | INSERT INTO packages VALUES(15,NULL,1,1,'glibc-headers','rpm'); 16 | INSERT INTO packages VALUES(16,NULL,1,1,'glibc-debuginfo','rpm'); 17 | INSERT INTO packages VALUES(17,NULL,1,1,'glibc','rpm'); 18 | INSERT INTO packages VALUES(18,NULL,1,1,'nscd','rpm'); 19 | INSERT INTO packages VALUES(19,NULL,1,9,'glibc','rpm'); 20 | INSERT INTO packages VALUES(20,NULL,2,2,'will-crash','rpm'); 21 | INSERT INTO packages VALUES(21,NULL,2,2,'will-crash-debuginfo','rpm'); 22 | INSERT INTO packages VALUES(22,NULL,2,1,'will-crash-debuginfo','rpm'); 23 | INSERT INTO packages VALUES(23,NULL,2,1,'will-crash','rpm'); 24 | INSERT INTO packages VALUES(24,NULL,2,9,'will-crash','rpm'); 25 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/82081a3c76b_rename_kb_to_sf_prefilter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Rename Kb to SF-prefilter 21 | 22 | Revision ID: 82081a3c76b 23 | Revises: 31d0249e8d4c 24 | Create Date: 2014-10-21 12:34:28.849585 25 | """ 26 | 27 | from alembic.op import rename_table 28 | 29 | # revision identifiers, used by Alembic. 30 | revision = "82081a3c76b" 31 | down_revision = "31d0249e8d4c" 32 | 33 | 34 | def upgrade() -> None: 35 | rename_table("kbsolutions", "sfprefiltersolutions") 36 | rename_table("kbbacktracepath", "sfprefilterbacktracepaths") 37 | rename_table("kbpackagename", "sfprefilterpackagenames") 38 | 39 | 40 | def downgrade() -> None: 41 | rename_table("sfprefiltersolutions", "kbsolutions") 42 | rename_table("sfprefilterbacktracepaths", "kbbacktracepath") 43 | rename_table("sfprefilterpackagenames", "kbpackagename") 44 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL analysis 2 | on: 3 | push: 4 | branches: ["master"] 5 | pull_request: 6 | branches: ["master"] 7 | schedule: 8 | - cron: "12 17 * * 3" 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | container: 13 | image: fedora:latest 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | language: [javascript, python] 23 | steps: 24 | - name: Check out sources 25 | uses: actions/checkout@v3 26 | 27 | - name: Install dependencies (Python) 28 | if: ${{ matrix.language == 'python' }} 29 | run: | 30 | dnf --assumeyes install --setopt=install_weak_deps=False \ 31 | autoconf automake dnf-plugins-core make which 32 | dnf --assumeyes copr enable @abrt/faf-el8-devel 33 | dnf --assumeyes builddep --spec faf.spec 34 | echo CODEQL_PYTHON=/usr/bin/python3 >> $GITHUB_ENV 35 | 36 | - name: Generate build files and build 37 | if: ${{ matrix.language == 'python' }} 38 | run: ./autogen.sh && make -j 39 | 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v2 42 | with: 43 | languages: ${{ matrix.language }} 44 | queries: +security-and-quality 45 | setup-python-dependencies: false 46 | 47 | - name: Perform CodeQL Analysis 48 | uses: github/codeql-action/analyze@v2 49 | with: 50 | category: "/language:${{ matrix.language }}" 51 | -------------------------------------------------------------------------------- /config/plugins/web.conf: -------------------------------------------------------------------------------- 1 | [hub] 2 | debug = false 3 | proxy_setup = false 4 | secret_key = @SECRET_KEY@ 5 | require_https = true 6 | url = https://example.org/faf/ 7 | # server name is the bare URL without protocols and trailing slash 8 | server_name = example.org/faf 9 | brand_title = ABRT 10 | brand_subtitle = Analytics 11 | # A simple banner to notify users of scheduled downtime etc. Fill in text as needed, no text means no banner. 12 | banner = 13 | # uncomment the following two options to enable Fedmenu 14 | # fedmenu_url = https://apps.fedoraproject.org/fedmenu 15 | # fedmenu_data_url = https://apps.fedoraproject.org/js/data.js 16 | 17 | # When OpenID login is disabled, this option can be used to override permission 18 | # checks and make everyone a package maintainer. 19 | # In that case no login is necessary to access maintainer-only actions. 20 | everyone_is_maintainer = false 21 | # When OpenID login is disabled, this option can be used to override permission 22 | # checks and make everyone an admin. 23 | # In that case no login is necessary to access admin-only actions. 24 | everyone_is_admin = false 25 | 26 | [openid] 27 | enabled = true 28 | 29 | # Comma-separated list of teams provided by OpenID via 30 | # https://github.com/puiterwijk/python-openid-teams 31 | # Members of these teams will be granted maintainer privileges 32 | # privileged_teams = provenpackager,proventesters 33 | 34 | [cache] 35 | #types: 36 | # null - no caching 37 | # simple - process-local memory cache 38 | # memcached - requires pylibmc 39 | type = simple 40 | # memcached_host = localhost 41 | # memcached_port = 11211 42 | # memcached_key_prefix = webfaf 43 | -------------------------------------------------------------------------------- /src/pyfaf/storage/project.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from sqlalchemy.orm import relationship 20 | from sqlalchemy.sql.schema import Column, ForeignKey 21 | from sqlalchemy.types import DateTime, Integer, String 22 | 23 | from .generic_table import GenericTable 24 | 25 | 26 | class Project(GenericTable): 27 | __tablename__ = "projects" 28 | 29 | id = Column(Integer, primary_key=True) 30 | name = Column(String(64), nullable=False, unique=True, index=True) 31 | 32 | 33 | class ProjRelease(GenericTable): 34 | __tablename__ = "projectreleases" 35 | 36 | id = Column(Integer, primary_key=True) 37 | project_id = Column(Integer, ForeignKey("{0}.id".format(Project.__tablename__)), nullable=False, index=True) 38 | # may be git hash 39 | version = Column(String(64), nullable=False) 40 | pubdate = Column(DateTime, nullable=False) 41 | project = relationship(Project, backref="releases") 42 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/272e6a3deea4_link_probable_fix_to_build.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Link probable fix to Build 21 | 22 | Revision ID: 272e6a3deea4 23 | Revises: 82081a3c76b 24 | Create Date: 2014-12-08 14:44:00.362834 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '272e6a3deea4' 32 | down_revision = '82081a3c76b' 33 | 34 | 35 | def upgrade() -> None: 36 | add_column('problemopsysreleases', sa.Column('probable_fix_build_id', sa.Integer(), nullable=True)) 37 | drop_column('problemopsysreleases', u'probable_fix') 38 | 39 | 40 | def downgrade() -> None: 41 | add_column('problemopsysreleases', 42 | sa.Column(u'probable_fix', sa.VARCHAR(length=256), autoincrement=False, nullable=True)) 43 | drop_column('problemopsysreleases', 'probable_fix_build_id') 44 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/bb2289ffb392_add_tz_info_to_periodictasks.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 ABRT Team 2 | # Copyright (C) 2019 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | add TZ info to periodictasks 21 | 22 | Revision ID: bb2289ffb392 23 | Revises: 9596a0f03838 24 | Create Date: 2019-12-12 14:59:44.743113 25 | """ 26 | 27 | from alembic.op import alter_column 28 | import sqlalchemy as sa 29 | 30 | 31 | # revision identifiers, used by Alembic. 32 | revision = 'bb2289ffb392' 33 | down_revision = '9596a0f03838' 34 | 35 | 36 | def upgrade() -> None: 37 | alter_column('periodictasks', 'last_run_at', type_=sa.DateTime(timezone=True), nullable=True) 38 | alter_column('taskresult', 'finished_time', type_=sa.DateTime(timezone=True), nullable=True) 39 | 40 | 41 | def downgrade() -> None: 42 | alter_column('periodictasks', 'last_run_at', type_=sa.DateTime(timezone=False), nullable=True) 43 | alter_column('taskresult', 'finished_time', type_=sa.DateTime(timezone=False), nullable=True) 44 | -------------------------------------------------------------------------------- /src/pyfaf/actions/find_report_solution.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_report_opsysrelease 21 | from pyfaf.solutionfinders import find_solution 22 | from pyfaf.storage import (Report) 23 | 24 | 25 | class FindReportSolution(Action): 26 | name = "find-report-solution" 27 | 28 | 29 | def run(self, cmdline, db) -> None: 30 | db.session.autocommit = False 31 | for report in db.session.query(Report).filter(Report.max_certainty.is_(None)): 32 | osr = get_report_opsysrelease(db=db, report_id=report.id) 33 | solutions = [find_solution(report, db=db, osr=osr)] 34 | 35 | if solutions[0] is not None: 36 | report.max_certainty = max((s.certainty for s in solutions)) 37 | self.log_info("Max_certainty of report '{0}' is changed to {1}".format(report.id, report.max_certainty)) 38 | 39 | db.session.commit() 40 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/58f44afc3a3a_drop_running_package_from_reportpackages.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Drop running_package from reportpackages 21 | 22 | Revision ID: 58f44afc3a3a 23 | Revises: 1b264b21ca91 24 | Create Date: 2015-03-03 17:56:36.903726 25 | """ 26 | 27 | from alembic.op import drop_constraint, drop_column, add_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = "58f44afc3a3a" 32 | down_revision = "1b264b21ca91" 33 | 34 | 35 | def upgrade() -> None: 36 | drop_constraint("reportpackages_running_package_id_fkey", 37 | "reportpackages") 38 | 39 | drop_column("reportpackages", "running_package_id") 40 | 41 | 42 | def downgrade() -> None: 43 | add_column("reportpackages", 44 | sa.Column("running_package_id", sa.Integer(), 45 | sa.ForeignKey("packages.id"), 46 | nullable=True)) 47 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/183a15e52a4f_report_history_unique.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 ABRT Team 2 | # Copyright (C) 2016 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Unique column added into report history 21 | 22 | Revision ID: 183a15e52a4f 23 | Revises: 133991a89da4 24 | Create Date: 2016-09-26 14:35:00.567052 25 | """ 26 | 27 | from alembic.op import add_column, drop_column 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = "183a15e52a4f" 32 | down_revision = "133991a89da4" 33 | 34 | 35 | def upgrade() -> None: 36 | add_column("reporthistorydaily", sa.Column("unique", sa.Integer, nullable=True)) 37 | add_column("reporthistoryweekly", sa.Column("unique", sa.Integer, nullable=True)) 38 | add_column("reporthistorymonthly", sa.Column("unique", sa.Integer, nullable=True)) 39 | 40 | 41 | def downgrade() -> None: 42 | drop_column("reporthistorydaily", "unique") 43 | drop_column("reporthistoryweekly", "unique") 44 | drop_column("reporthistorymonthly", "unique") 45 | -------------------------------------------------------------------------------- /src/pyfaf/actions/opsysadd.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_opsys_by_name 21 | from pyfaf.storage.opsys import OpSys 22 | 23 | 24 | class OpSysAdd(Action): 25 | name = "opsysadd" 26 | 27 | 28 | def run(self, cmdline, db) -> int: 29 | opsys = get_opsys_by_name(db, cmdline.NAME) 30 | 31 | if opsys: 32 | self.log_error("Operating system '{0}' already defined" 33 | .format(cmdline.NAME)) 34 | return 1 35 | 36 | self.log_info("Adding operating system '{0}'".format(cmdline.NAME)) 37 | 38 | new = OpSys() 39 | new.name = cmdline.NAME 40 | db.session.add(new) 41 | db.session.flush() 42 | return 0 43 | 44 | def tweak_cmdline_parser(self, parser) -> None: 45 | parser.add_argument("NAME", validators=[("InputRequired", [])], 46 | help="name of new operating system") 47 | -------------------------------------------------------------------------------- /src/pyfaf/actions/Makefile.am: -------------------------------------------------------------------------------- 1 | actions_PYTHON = \ 2 | __init__.py \ 3 | addcompathashes.py \ 4 | archadd.py \ 5 | archive_reports.py \ 6 | archlist.py \ 7 | assign_release_to_builds.py \ 8 | attach_centos_bugs.py \ 9 | bugtrackerlist.py \ 10 | pull_abrt_bugs.py \ 11 | pull_bug.py \ 12 | update_bugs.py \ 13 | c2p.py \ 14 | check_repo.py \ 15 | cleanup_packages.py \ 16 | cleanup_task_results.py \ 17 | cleanup_unassigned.py \ 18 | componentadd.py \ 19 | create_problems.py \ 20 | delete_invalid_ureports.py \ 21 | extfafadd.py \ 22 | extfafclonebz.py \ 23 | extfafdelete.py \ 24 | extfaflink.py \ 25 | extfafmodify.py \ 26 | extfafshow.py \ 27 | fedmsg_notify.py \ 28 | find_components.py \ 29 | find_crash_function.py \ 30 | find_report_solution.py \ 31 | hash_paths.py \ 32 | init.py \ 33 | mark_probably_fixed.py \ 34 | pull_associates.py \ 35 | pull_components.py \ 36 | pull_releases.py \ 37 | pull_reports.py \ 38 | releaseadd.py \ 39 | releasedel.py \ 40 | releaselist.py \ 41 | releasemod.py \ 42 | repoadd.py \ 43 | repoassign.py \ 44 | repodel.py \ 45 | repoimport.py \ 46 | repoinfo.py \ 47 | repolist.py \ 48 | repomod.py \ 49 | reposync.py \ 50 | retrace.py \ 51 | retrace_remote.py \ 52 | sar.py \ 53 | save_reports.py \ 54 | sf_prefilter_soladd.py \ 55 | sf_prefilter_solshow.py \ 56 | sf_prefilter_patadd.py \ 57 | sf_prefilter_patshow.py \ 58 | shell.py \ 59 | stats.py \ 60 | opsysadd.py \ 61 | opsysdel.py \ 62 | opsyslist.py \ 63 | match_unknown_packages.py 64 | 65 | actionsdir = $(pythondir)/pyfaf/actions 66 | -------------------------------------------------------------------------------- /tests/test_dnf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- encoding: utf-8 -*- 3 | import unittest 4 | import os 5 | import shutil 6 | import logging 7 | import tempfile 8 | 9 | import faftests 10 | 11 | from pyfaf.repos.dnf import Dnf 12 | from pyfaf.utils.proc import popen 13 | 14 | 15 | class DnfTestCase(faftests.TestCase): 16 | """ 17 | Test case for dnf repository plugin. 18 | """ 19 | 20 | def test_list_packages(self): 21 | """ 22 | Test whether list_packages lists our ad-hoc 23 | repository correctly. 24 | """ 25 | 26 | rpm = "sample_rpms/sample-1.0-1.fc18.noarch.rpm" 27 | 28 | tmpdir = tempfile.mkdtemp() 29 | shutil.copyfile(rpm, os.path.join(tmpdir, os.path.basename(rpm))) 30 | 31 | proc = popen("createrepo_c", "--verbose", tmpdir) 32 | self.assertTrue(b"Workers Finished" in proc.stdout or b"Pool finished" in proc.stdout) 33 | 34 | dnf = Dnf("test_repo_name", tmpdir) 35 | pkgs = dnf.list_packages(["noarch"]) 36 | self.assertEqual(len(pkgs), 1) 37 | pkg = pkgs.pop() 38 | self.assertEqual(pkg["name"], "sample") 39 | self.assertEqual(pkg["base_package_name"], "sample") 40 | self.assertEqual(pkg["version"], "1.0") 41 | self.assertEqual(pkg["release"], "1.fc18") 42 | self.assertEqual(pkg["arch"], "noarch") 43 | 44 | self.assertEqual(pkg["filename"], os.path.basename(rpm)) 45 | self.assertEqual(pkg["url"], "file://{0}".format( 46 | os.path.join(tmpdir, os.path.basename(rpm)))) 47 | 48 | self.assertEqual(pkg["type"], "rpm") 49 | 50 | shutil.rmtree(tmpdir) 51 | 52 | if __name__ == "__main__": 53 | logging.basicConfig(level=logging.INFO) 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/50d3e87e4b2a_add_reporturl.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 ABRT Team 2 | # Copyright (C) 2015 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Add reporturl 21 | 22 | Revision ID: 50d3e87e4b2a 23 | Revises: 21345f007bdf 24 | Create Date: 2015-10-15 14:27:16.769105 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '50d3e87e4b2a' 32 | down_revision = '21345f007bdf' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table('reporturls', 37 | sa.Column('id', sa.Integer(), nullable=False), 38 | sa.Column('report_id', sa.Integer(), nullable=False), 39 | sa.Column('url', sa.String(length=1024), nullable=False), 40 | sa.Column('saved', sa.DateTime(), nullable=True), 41 | sa.ForeignKeyConstraint(['report_id'], ['reports.id'], ), 42 | sa.PrimaryKeyConstraint('id'), 43 | ) 44 | 45 | def downgrade() -> None: 46 | drop_table('reporturls') 47 | -------------------------------------------------------------------------------- /src/webfaf/templates/summary/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from "_helpers.html" import render_field %} 3 | {% from "_helpers.html" import paginator %} 4 | 5 | {% block title %}Summary{% endblock %} 6 | 7 | {% block js %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% endblock js %} 16 | 17 | {% block body %} 18 |
19 |
20 |
21 |
22 | {{ render_field(summary_form.opsysreleases, class="multiselect") }} 23 | {{ render_field(summary_form.component_names, placeholder="Components", class="component-names") }} 24 | {{ render_field(summary_form.daterange, class="form-control daterange") }} 25 | {{ render_field(summary_form.resolution) }} 26 | 27 |
28 |
29 |
30 |
31 | {% if cached_plot %} 32 | {{ cached_plot|safe }} 33 | {% else %} 34 | {% include "summary/index_plot_data.html" with context %} 35 | {% endif %} 36 |
37 |
38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /src/pyfaf/actions/archadd.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_arch_by_name 21 | from pyfaf.storage.opsys import Arch 22 | 23 | 24 | class ArchAdd(Action): 25 | name = "archadd" 26 | 27 | 28 | def run(self, cmdline, db) -> int: 29 | for archname in cmdline.NAME: 30 | arch = get_arch_by_name(db, archname) 31 | 32 | if arch: 33 | self.log_error("Architecture '{0}' already defined" 34 | .format(archname)) 35 | return 1 36 | 37 | self.log_info("Adding architecture '{0}'".format(archname)) 38 | 39 | new = Arch() 40 | new.name = archname 41 | db.session.add(new) 42 | db.session.flush() 43 | return 0 44 | 45 | def tweak_cmdline_parser(self, parser) -> None: 46 | parser.add_argument("NAME", nargs="+", validators=[("InputRequired", {})], 47 | help="name of new architecture") 48 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/17d4911132f8_assigning_release_to_repo.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Assigning release to repository 21 | 22 | Revision ID: 17d4911132f8 23 | Revises: 13557f1962e6 24 | Create Date: 2016-09-08 08:49:52.450697 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '17d4911132f8' 32 | down_revision = '13557f1962e6' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table('opsysreleaserepo', 37 | sa.Column('opsysrelease_id', sa.Integer(), nullable=False), 38 | sa.Column('repo_id', sa.Integer(), nullable=False), 39 | sa.ForeignKeyConstraint(['opsysrelease_id'], ['opsysreleases.id'], ), 40 | sa.ForeignKeyConstraint(['repo_id'], ['repo.id'], ), 41 | sa.PrimaryKeyConstraint('opsysrelease_id', 'repo_id'), 42 | ) 43 | 44 | 45 | def downgrade() -> None: 46 | drop_table('opsysreleaserepo') 47 | -------------------------------------------------------------------------------- /src/pyfaf/__init__.py.in: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | __all__ = ["checker", "cmdline", "common", "config", "local", 20 | "queries", "retrace", "faf_rpm", "ureport", "utils", "actions", 21 | "bugtrackers", "opsys", "problemtypes", "repos"] 22 | __version__ = "@PACKAGE_VERSION@" 23 | 24 | from . import checker 25 | from . import cmdline 26 | from . import common 27 | from . import config 28 | from . import local 29 | from . import queries 30 | # soft dep on retrace - it pulls elfutils 31 | # No exception type(s) specifiedo exception type(s) specified 32 | # pylint: disable-msg=W0702 33 | try: 34 | from . import retrace 35 | except: 36 | # Invalid name "retrace" for type constant 37 | # pylint: disable-msg=C0103 38 | retrace = None 39 | # pylint: enable-msg=C0103 40 | # pylint: enable-msg=W0702 41 | from . import faf_rpm 42 | from . import ureport 43 | from . import utils 44 | 45 | from . import actions 46 | from . import bugtrackers 47 | from . import opsys 48 | from . import problemtypes 49 | from . import repos 50 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/71905f91e7b7_add_archived_reports.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 ABRT Team 2 | # Copyright (C) 2017 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Add archived reports 21 | 22 | Revision ID: 71905f91e7b7 23 | Revises: 9301a426f19d 24 | Create Date: 2017-03-08 16:56:11.355916 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '71905f91e7b7' 32 | down_revision = '9301a426f19d' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table( 37 | 'reportarchive', 38 | sa.Column('id', sa.Integer, primary_key=True), 39 | sa.Column('date', sa.Date, nullable=False), 40 | sa.Column('active', sa.Boolean, nullable=False), 41 | sa.Column('report_id', sa.Integer, nullable=False), 42 | sa.Column('username', sa.String(100), nullable=False), 43 | sa.ForeignKeyConstraint(['report_id'], ['reports.id'], ), 44 | sa.ForeignKeyConstraint(['username'], ['users.username'], ), 45 | ) 46 | 47 | 48 | def downgrade() -> None: 49 | drop_table('reportarchive') 50 | -------------------------------------------------------------------------------- /src/webfaf/templates/reports/diff.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% from '_helpers.html' import backtrace_table_columns %} 3 | 4 | {% block title %}Reports diff #{{lhs.id}} #{{rhs.id}}{% endblock %} 5 | 6 | {% block body %} 7 | 8 | 9 | Differences between backtraces from report 10 | - {{lhs.id}} 11 | and backtrace from report 12 | + {{rhs.id}} 13 | 14 | 15 |
16 | 17 | 18 | 19 | 21 | 22 | {% if type != 'python' %} 23 | 24 | {% endif %} 25 | 26 | 27 | 28 | {% for l, r in diff %} 29 | {% if l and not r %} 30 | 31 | 32 | {% endif %} 33 | 34 | {% if not l and r %} 35 | 36 | 37 | {% endif %} 38 | 39 | {% if not l and not r %} 40 | 41 | 46 | 59 | 60 | {% if type != 'python' %} 61 | 62 | {% endif %} 63 | 64 | 65 | {% endif %} 66 | 67 | {% endfor %} 68 |
20 | Frame #FunctionBinarySourceLine
-
+
42 | {% endif %} 43 | 44 | {% if l and r %} 45 |
47 | {% endif %} 48 | 49 | {% if l %} 50 | {{ backtrace_table_columns(l, lhs.type) }} 51 | {% endif %} 52 | 53 | {% if not l and r %} 54 | {{ backtrace_table_columns(r, rhs.type) }} 55 | {% endif %} 56 | 57 | {% if not l and not r %} 58 |
69 | {% endblock %} 70 | -------------------------------------------------------------------------------- /src/pyfaf/actions/cleanup_task_results.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 ABRT Team 2 | # Copyright (C) 2015 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from datetime import datetime, timedelta 20 | from pyfaf.actions import Action 21 | from pyfaf.storage.task import TaskResult 22 | 23 | 24 | class CleanupTaskResults(Action): 25 | name = "cleanup-task-results" 26 | 27 | def run(self, cmdline, db) -> None: 28 | if cmdline.keep_days >= 0: 29 | q = (db.session.query(TaskResult) 30 | .filter(TaskResult.finished_time < 31 | datetime.now()-timedelta(days=cmdline.keep_days))) 32 | self.log_info("About to delete {0} task results older than {1} days." 33 | .format(q.count(), cmdline.keep_days)) 34 | q.delete() 35 | db.session.flush() 36 | self.log_info("Task results deleted") 37 | else: 38 | self.log_warn("--keep-days must be greater or equal to 0.") 39 | 40 | def tweak_cmdline_parser(self, parser) -> None: 41 | parser.add_argument("--keep-days", help="keep results for the last D days", 42 | default=14, type=int) 43 | -------------------------------------------------------------------------------- /src/pyfaf/actions/sar.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018 ABRT Team 2 | # Copyright (C) 2018 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | import os 20 | from pyfaf.actions import Action 21 | from pyfaf.storage.user import User 22 | from pyfaf.utils.user import UserDataDumper 23 | 24 | class SubjectAccessRequest(Action): 25 | name = "sar" 26 | 27 | def run(self, cmdline, db) -> int: 28 | mail = os.environ.get("SAR_EMAIL", None) 29 | username = os.environ.get("SAR_USERNAME", None) 30 | 31 | if not mail and not username: 32 | print("Environment variables SAR_USERNAME, SAR_EMAIL were not set.") 33 | return 1 34 | 35 | if mail: 36 | dumper = UserDataDumper(db, mail) 37 | print(dumper.dump(pretty=True)) 38 | return 0 39 | 40 | if username: 41 | usermail = db.session.query(User).filter(User.username == username).first() 42 | if usermail is not None: 43 | dumper = UserDataDumper(db, usermail.mail) 44 | print(dumper.dump(pretty=True)) 45 | else: 46 | print("User '{0}' was not found.".format(username)) 47 | 48 | return 0 49 | -------------------------------------------------------------------------------- /docs/ureport_sample: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": { 3 | "version": "2.0.7-2.fc16", 4 | "name": "abrt" 5 | }, 6 | "selinux": { 7 | "policy_package": { 8 | "release": "2.fc16", 9 | "epoch": 0, 10 | "version": "3.10.0", 11 | "name": "selinux-policy", 12 | "architecture": "noarch" 13 | }, 14 | "mode": "permissive", 15 | "context": "unconfined_u:unconfined_r:unconfined_t:s0" 16 | }, 17 | "uptime": 1, 18 | "installed_package": { 19 | "release": "1.fc16", 20 | "epoch": 0, 21 | "version": "0.4", 22 | "name": "faf", 23 | "architecture": "noarch" 24 | }, 25 | "user_type": "root", 26 | "reason": "TypeError", 27 | "related_packages": [ 28 | { 29 | "installed_package": { 30 | "release": "4.fc16", 31 | "epoch": 0, 32 | "version": "2.7.2", 33 | "name": "python", 34 | "architecture": "x86_64" 35 | } 36 | } 37 | ], 38 | "executable": "/usr/bin/faf-btserver-cgi", 39 | "type": "python", 40 | "architecture": "x86_64", 41 | "crash_thread": 0, 42 | "os": { 43 | "version": "16", 44 | "name": "Fedora" 45 | }, 46 | "core_backtrace": [ 47 | { 48 | "thread": 0, 49 | "buildid": "f76f656ab6e1b558fc78d0496f1960071565b0aa", 50 | "frame": 1, 51 | "funcname": "", 52 | "offset": 24, 53 | "path": "/usr/bin/faf-btserver-cgi" 54 | }, 55 | { 56 | "thread": 0, 57 | "buildid": "b07daccd370e885bf3d459984a4af09eb889360a", 58 | "frame": 2, 59 | "funcname": "compile", 60 | "offset": 190, 61 | "path": "/usr/lib64/python2.7/re.py" 62 | }, 63 | { 64 | "thread": 0, 65 | "buildid": "b07daccd370e885bf3d459984a4af09eb889360a", 66 | "frame": 3, 67 | "funcname": "_compile", 68 | "offset": 241, 69 | "path": "/usr/lib64/python2.7/re.py" 70 | } 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /src/pyfaf/storage/fixtures/randutils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from __future__ import division 20 | import os 21 | import random 22 | import hashlib 23 | 24 | from typing import Collection, Sequence, Union 25 | 26 | def pickhalf(objects) -> Union[Sequence, Collection]: 27 | ''' 28 | Randomly pick half of the objects 29 | ''' 30 | return random.sample(objects, len(objects)//2) 31 | 32 | def pickmost(objects) -> Union[Sequence, Collection]: 33 | ''' 34 | Randomly pick 9/10 of the objects 35 | ''' 36 | return random.sample(objects, len(objects)-len(objects)//10) 37 | 38 | def toss() -> bool: 39 | ''' 40 | Coin toss 41 | ''' 42 | return bool(random.randrange(2)) 43 | 44 | def tosshigh() -> bool: 45 | ''' 46 | High probability coin toss (9 of 10) 47 | ''' 48 | return bool(random.randrange(10)) 49 | 50 | def tosslow() -> bool: 51 | ''' 52 | Low probability coin toss (1 of 10) 53 | ''' 54 | return not bool(random.randrange(10)) 55 | 56 | def randhash() -> str: 57 | ''' 58 | Returns random sha1 hash 59 | ''' 60 | return hashlib.sha1(os.urandom(30).encode("utf-8")).hexdigest() 61 | -------------------------------------------------------------------------------- /src/pyfaf/storage/bugtracker.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from typing import Optional 20 | 21 | from sqlalchemy.sql.schema import Column 22 | from sqlalchemy.types import Integer, String 23 | 24 | from pyfaf.config import config 25 | 26 | from .generic_table import GenericTable 27 | 28 | 29 | class Bugtracker(GenericTable): 30 | __tablename__ = "bugtrackers" 31 | 32 | id = Column(Integer, primary_key=True) 33 | name = Column(String(64), nullable=False) 34 | 35 | def __str__(self) -> str: 36 | return str(self.name) 37 | 38 | @property 39 | def web_url(self) -> Optional[str]: 40 | cfgstr = "{0}.web_url".format(self.name) 41 | if cfgstr in config: 42 | return config[cfgstr] 43 | return None 44 | 45 | @property 46 | def api_url(self) -> Optional[str]: 47 | cfgstr = "{0}.api_url".format(self.name) 48 | if cfgstr in config: 49 | return config[cfgstr] 50 | return None 51 | 52 | @property 53 | def abbr(self) -> str: 54 | cfgstr = "{0}.abbr".format(self.name) 55 | if cfgstr in config: 56 | return config[cfgstr] 57 | return "" 58 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/5695a1c595c3_reportreleasedesktops.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Added reportreleasedesktops table 21 | 22 | Revision ID: 5695a1c595c3 23 | Revises: 23bab42e7be7 24 | Create Date: 2014-08-22 12:21:50.973673 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = '5695a1c595c3' 32 | down_revision = '23bab42e7be7' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table('reportreleasedesktops', 37 | sa.Column('report_id', sa.Integer(), nullable=False), 38 | sa.Column('release_id', sa.Integer(), nullable=False), 39 | sa.Column('desktop', sa.String(length=256), nullable=False), 40 | sa.Column('count', sa.Integer(), nullable=False), 41 | sa.ForeignKeyConstraint(['release_id'], ['opsysreleases.id'], ), 42 | sa.ForeignKeyConstraint(['report_id'], ['reports.id'], ), 43 | sa.PrimaryKeyConstraint('report_id', 'release_id', 'desktop'), 44 | ) 45 | 46 | 47 | def downgrade() -> None: 48 | drop_table('reportreleasedesktops') 49 | -------------------------------------------------------------------------------- /config/faf.conf.in: -------------------------------------------------------------------------------- 1 | # Faf site-wide configuration file 2 | # The settings are overridden by the file specified in 3 | # FAF_CONFIG_FILE environment variable. 4 | [Main] 5 | PluginsDir = @sysconfdir@/faf/plugins/ 6 | TemplatesDir = @sysconfdir@/faf/templates/ 7 | AutoEnablePlugins = True 8 | 9 | [Storage] 10 | DBUser = 11 | DBPasswd = 12 | DBHost = 13 | DBPort = 14 | DBName = faf 15 | LobDir = @localstatedir@/spool/faf/lob 16 | # Using platform-specific location by default. 17 | # Uncomment and change if needed. 18 | # TmpDir = /tmp 19 | 20 | 21 | [Mail] 22 | # where to send notification emails, comma separated list 23 | Admins = root@localhost.localdomain 24 | Server = localhost 25 | Port = 25 26 | Username = 27 | Password = 28 | From = no-reply@localhost 29 | 30 | [uReport] 31 | # The directory that holds 'reports' and 'attachments' subdirectories 32 | Directory = @localstatedir@/spool/faf 33 | CreateComponents = False 34 | # attachments accepted by this server 35 | # allowed values: fedora-bugzilla rhel-bugzilla centos-mantisb comment email url 36 | # or * to allow all attachments 37 | AcceptAttachments = fedora-bugzilla rhel-bugzilla centos-mantisbt 38 | 39 | # Allow uReports without affected package - meaning that crashing code was 40 | # not packaged 41 | allow-unpackaged = False 42 | 43 | # Determines which strategy will be used for searching known or unknown ureport's 44 | # and bugzilla bug's, if known is empty, then is used BUG_OS_MINOR_VERSION 45 | # 46 | # BUG_OS_MAJOR_VERSION - The report has attached a bug with equivalent OS Major 47 | # version name 48 | # BUG_OS_MINOR_VERSION - The report has attached a bug with equivalent OS Major 49 | # version and OS Minor version name 50 | # EQUAL_UREPORT_EXISTS - Report OS Major version match AND uReport OS Minor 51 | # version match AND uReport OS Architecture match AND Packages match name 52 | # 53 | # allowed values for the Known option 54 | # BUG_OS_MAJOR_VERSION BUG_OS_MINOR_VERSION EQUAL_UREPORT_EXISTS 55 | Known = 56 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/133991a89da4_build_to_opsysrelease.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Assign build to operating system, release and architecture 21 | 22 | Revision ID: 133991a89da4 23 | Revises: 17d4911132f8 24 | Create Date: 2016-09-08 09:08:26.035450 25 | """ 26 | 27 | from alembic.op import create_table, drop_table 28 | import sqlalchemy as sa 29 | 30 | 31 | # revision identifiers, used by Alembic. 32 | revision = '133991a89da4' 33 | down_revision = '17d4911132f8' 34 | 35 | 36 | def upgrade() -> None: 37 | create_table('buildopsysreleasearch', 38 | sa.Column('build_id', sa.Integer(), nullable=False), 39 | sa.Column('opsysrelease_id', sa.Integer(), nullable=False), 40 | sa.Column('arch_id', sa.Integer(), nullable=False), 41 | sa.ForeignKeyConstraint(['build_id'], ['builds.id'], ), 42 | sa.ForeignKeyConstraint(['opsysrelease_id'], ['opsysreleases.id'], ), 43 | sa.ForeignKeyConstraint(['arch_id'], ['archs.id'], ), 44 | sa.PrimaryKeyConstraint('build_id', 'opsysrelease_id', 'arch_id'), 45 | ) 46 | 47 | 48 | def downgrade() -> None: 49 | drop_table('buildopsysreleasearch') 50 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/f43edd5b636d_enable_problem_components_reassign.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 ABRT Team 2 | # Copyright (C) 2017 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Enable problem components reassign 21 | 22 | Revision ID: f43edd5b636d 23 | Revises: 71905f91e7b7 24 | Create Date: 2017-04-09 18:04:25.575450 25 | """ 26 | 27 | from alembic.op import create_table, create_index, drop_index, drop_table, f 28 | import sqlalchemy as sa 29 | 30 | # revision identifiers, used by Alembic. 31 | revision = 'f43edd5b636d' 32 | down_revision = '71905f91e7b7' 33 | 34 | 35 | def upgrade() -> None: 36 | create_table( 37 | 'problemreassign', 38 | sa.Column('id', sa.Integer, primary_key=True), 39 | sa.Column('date', sa.Date, nullable=False), 40 | sa.Column('problem_id', sa.Integer, nullable=False), 41 | sa.Column('username', sa.String(100), nullable=False), 42 | sa.ForeignKeyConstraint(['problem_id'], ['problems.id'], ), 43 | sa.ForeignKeyConstraint(['username'], ['users.username'], ), 44 | ) 45 | create_index('ix_problemreassign_problem_id', 'problemreassign', ['problem_id']) 46 | 47 | 48 | def downgrade() -> None: 49 | drop_index(f('ix_problemreassign_problem_id'), table_name='problemreassign') 50 | drop_table('problemreassign') 51 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/fd5dc71471cc_set_pkg_name_to_256.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 ABRT Team 2 | # Copyright (C) 2019 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | set-pkg-name-to-256 21 | 22 | Revision ID: fd5dc71471cc 23 | Revises: 8ac9b3343649 24 | Create Date: 2019-08-06 14:26:17.254047 25 | """ 26 | 27 | import sqlalchemy as sa 28 | from alembic.op import alter_column 29 | 30 | 31 | # revision identifiers, used by Alembic. 32 | revision = "fd5dc71471cc" 33 | down_revision = "8ac9b3343649" 34 | 35 | 36 | def upgrade() -> None: 37 | alter_column("packages", "name", type_=sa.String(length=256), nullable=False) 38 | alter_column("opsyscomponents", "name", type_=sa.String(length=256), nullable=False) 39 | alter_column("builds", "base_package_name", type_=sa.String(length=256), nullable=False) 40 | alter_column("reportunknownpackages", "name", type_=sa.String(length=256), nullable=False) 41 | 42 | 43 | def downgrade() -> None: 44 | alter_column("packages", "name", type_=sa.String(length=64), nullable=False) 45 | alter_column("opsyscomponents", "name", type_=sa.String(length=64), nullable=False) 46 | alter_column("builds", "base_package_name", type_=sa.String(length=64), nullable=False) 47 | alter_column("reportunknownpackages", "name", type_=sa.String(length=64), nullable=False) 48 | -------------------------------------------------------------------------------- /src/pyfaf/storage/events.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from sqlalchemy.orm import mapper 3 | from sqlalchemy.orm.session import Session 4 | 5 | from . import Build 6 | from . import ReportBacktrace 7 | from . import ReportBtFrame 8 | 9 | 10 | @event.listens_for(ReportBtFrame, "init") 11 | def init_btframe(target, *args, **kwargs) -> None: # pylint: disable=unused-argument 12 | """ 13 | Set reliable to True so it has default set correctly 14 | before it's stored in the database 15 | """ 16 | target.reliable = True 17 | 18 | 19 | @event.listens_for(Session, "before_flush") 20 | def update_backtrace_quality(session, flush_context, instances) -> None: # pylint: disable=unused-argument 21 | """ 22 | Compute and store backtrace quality information 23 | """ 24 | 25 | objects = session.new.union(session.dirty) 26 | for obj in [c for c in objects if isinstance(c, ReportBacktrace)]: 27 | if isinstance(obj, ReportBacktrace): 28 | obj.quality = obj.compute_quality() 29 | 30 | 31 | @event.listens_for(mapper, "before_delete") 32 | def before_delete(_, connection, target) -> None: # pylint: disable=unused-argument 33 | """ 34 | Remove lobs associated with target to be deleted. 35 | """ 36 | 37 | for lobname in target.__lobs__: 38 | if target.has_lob(lobname): 39 | target.del_lob(lobname) 40 | 41 | 42 | @event.listens_for(Build.version, "set") 43 | def store_semantic_version_for_build(target, value, oldvalue, initiator) -> None: # pylint: disable=unused-argument 44 | """ 45 | Store semnatic version (Build.semver) converted from text version 46 | (Build.version) 47 | """ 48 | 49 | target.semver = value 50 | 51 | 52 | @event.listens_for(Build.release, "set") 53 | def store_semantic_release_for_build(target, value, oldvalue, initiator) -> None: # pylint: disable=unused-argument 54 | """ 55 | Store semnatic release (Build.semrel) converted from text release 56 | (Build.release) 57 | """ 58 | 59 | target.semrel = value 60 | -------------------------------------------------------------------------------- /src/pyfaf/actions/bugtrackerlist.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_bugtracker_by_name 21 | from pyfaf.bugtrackers import bugtrackers 22 | from pyfaf.storage.bugtracker import Bugtracker 23 | from pyfaf.utils.format import as_table 24 | 25 | 26 | class BugtrackerList(Action): 27 | name = "bugtrackerlist" 28 | 29 | def run(self, cmdline, db) -> None: 30 | if cmdline.detailed: 31 | data = [] 32 | header = ["Name", "Installed", "API URL", "Web URL"] 33 | for tracker in bugtrackers: 34 | db_tracker = get_bugtracker_by_name(db, tracker) 35 | 36 | installed = "No" 37 | if db_tracker: 38 | installed = "Yes" 39 | tracker = db_tracker 40 | 41 | data.append((tracker, installed, tracker.api_url, 42 | tracker.web_url)) 43 | 44 | print(as_table(header, data, margin=2)) 45 | else: 46 | for tracker in db.session.query(Bugtracker): 47 | print(tracker) 48 | 49 | def tweak_cmdline_parser(self, parser) -> None: 50 | parser.add_argument("--detailed", action="store_true", 51 | help="detailed view") 52 | -------------------------------------------------------------------------------- /src/pyfaf/actions/opsysdel.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.queries import get_opsys_by_name 21 | 22 | 23 | class OpSysDel(Action): 24 | name = "opsysdel" 25 | 26 | 27 | def run(self, cmdline, db) -> int: 28 | for opsys in cmdline.OPSYS: 29 | db_opsys = get_opsys_by_name(db, opsys) 30 | 31 | if not db_opsys: 32 | self.log_warn("Operating system '{0}' not found" 33 | .format(db_opsys)) 34 | continue 35 | 36 | if db_opsys.releases: 37 | self.log_warn("Unable to delete operating system with associated" 38 | " releases. Following is the list of associated " 39 | " releases:") 40 | for release in db_opsys.releases: 41 | self.log_warn(release) 42 | 43 | continue 44 | 45 | self.log_info("Removing operating system '{0}'".format(opsys)) 46 | 47 | db.session.delete(db_opsys) 48 | db.session.flush() 49 | 50 | return 0 51 | 52 | def tweak_cmdline_parser(self, parser) -> None: 53 | parser.add_opsys(positional=True, required=True, multiple=True, helpstr="operating system to delete") 54 | -------------------------------------------------------------------------------- /src/pyfaf/actions/init.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.common import Plugin, log 21 | from pyfaf.queries import get_arch_by_name 22 | from pyfaf.storage import Arch 23 | 24 | 25 | class Init(Action): 26 | name = "init" 27 | 28 | archs = ["src", "noarch", "x86_64", "i386", "i486", "i586", "i686", 29 | "armv5tel", "armv7l", "armv7hl", "armv7hnl", "ppc", "ppc64", 30 | "ppc64le", "s390", "s390x", "sparc", "sparc64", "ia64"] 31 | 32 | 33 | def run(self, cmdline, db) -> None: 34 | for arch in Init.archs: 35 | db_arch = get_arch_by_name(db, arch) 36 | if db_arch is not None: 37 | continue 38 | 39 | self.log_info("Adding architecture '{0}'".format(arch)) 40 | new = Arch() 41 | new.name = arch 42 | db.session.add(new) 43 | 44 | db.session.flush() 45 | 46 | plugins = set() 47 | for cls in Plugin.__subclasses__(): 48 | plugins |= set(cls.__subclasses__()) 49 | 50 | for plugin in plugins: 51 | if not plugin.installed(db): 52 | plugin.install(db, logger=log.getChild(plugin.__name__)) 53 | 54 | db.session.flush() 55 | 56 | def tweak_cmdline_parser(self, parser) -> None: 57 | pass 58 | -------------------------------------------------------------------------------- /src/pyfaf/actions/hash_paths.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 ABRT Team 2 | # Copyright (C) 2015 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from sqlalchemy import or_ 20 | 21 | from pyfaf.actions import Action 22 | from pyfaf.storage.symbol import Symbol 23 | from pyfaf.utils.hash import hash_path 24 | 25 | 26 | class HashPaths(Action): 27 | name = "hash-paths" 28 | 29 | def __init__(self) -> None: 30 | super().__init__() 31 | self.prefixes = None 32 | self.load_config_to_self("prefixes", ["ureport.private_prefixes"], 33 | "/home /opt /usr/local /tmp /var/tmp") 34 | 35 | self.prefixes = self.prefixes.split() 36 | 37 | def run(self, cmdline, db) -> None: 38 | q = db.session.query(Symbol) 39 | 40 | filters = [] 41 | 42 | for p in self.prefixes: 43 | filters.append(Symbol.normalized_path.like("{}/%".format(p))) 44 | 45 | q = q.filter(or_(*filters)) 46 | 47 | total = q.count() 48 | print("Going to process {} symbols".format(total)) 49 | 50 | for c, symbol in enumerate(q.yield_per(100)): 51 | symbol.normalized_path = hash_path(symbol.normalized_path, 52 | self.prefixes) 53 | 54 | if not c % 1000: 55 | db.session.flush() 56 | 57 | db.session.flush() 58 | self.log_info("Done") 59 | -------------------------------------------------------------------------------- /src/pyfaf/utils/web.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from typing import Optional 4 | 5 | from pyfaf.config import config 6 | 7 | 8 | def webfaf_installed() -> bool: 9 | """ 10 | Return True if webfaf is installed 11 | """ 12 | 13 | try: 14 | import webfaf # pylint: disable=unused-import, unused-variable 15 | return True 16 | except: # pylint: disable=bare-except 17 | return False 18 | 19 | 20 | def server_url() -> Optional[str]: 21 | """ 22 | Return web server root URL if applicable 23 | """ 24 | 25 | if webfaf_installed(): 26 | return config.get("hub.url", None) 27 | 28 | logging.warning("Unable to get web server URL, webfaf not available") 29 | return None 30 | 31 | 32 | def server_name() -> Optional[str]: 33 | """ 34 | Return web server root URL if applicable 35 | """ 36 | 37 | if webfaf_installed(): 38 | return config.get("hub.server_name", None) 39 | 40 | logging.warning("Unable to get web server name, webfaf not available") 41 | return None 42 | 43 | 44 | def require_https() -> bool: 45 | """ 46 | Return if web server requires https (default true) 47 | """ 48 | 49 | if webfaf_installed(): 50 | from pyfaf.utils.parse import str2bool 51 | return str2bool(config.get("hub.require_https", "true")) 52 | 53 | logging.warning("Unable to get require https option, webfaf not available") 54 | return True 55 | 56 | 57 | def reverse(view, **kwargs) -> Optional[str]: 58 | """ 59 | Return full URL to pointing to `view` 60 | Wrapper around django"s own reverse. 61 | """ 62 | 63 | if webfaf_installed(): 64 | from flask import url_for 65 | from webfaf.webfaf_main import app 66 | app.config["SERVER_NAME"] = server_name() 67 | app.config["PREFERRED_URL_SCHEME"] = "https" if require_https() else "http" 68 | with app.app_context(): 69 | kwargs["_external"] = True 70 | return url_for(view, **kwargs) 71 | 72 | logging.warning("Unable to get web server URL, webfaf not available") 73 | return None 74 | -------------------------------------------------------------------------------- /src/webfaf/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from sqlalchemy.engine.url import make_url 4 | 5 | import pyfaf 6 | from pyfaf.common import get_connect_string 7 | from pyfaf.config import config, paths 8 | from pyfaf.utils.parse import str2bool 9 | 10 | dburl = make_url(get_connect_string()) 11 | 12 | WEBFAF_DIR = os.path.dirname(__file__) 13 | 14 | 15 | class Config: 16 | DEBUG = False 17 | TESTING = False 18 | SECRET_KEY = "NOT_A_RANDOM_STRING" 19 | SQLALCHEMY_DATABASE_URI = dburl 20 | SQLALCHEMY_TRACK_MODIFICATIONS = False 21 | OPENID_ENABLED = str2bool(config.get("openid.enabled", "false")) 22 | OPENID_FS_STORE = os.path.join(paths["spool"], "openid_store") 23 | OPENID_PRIVILEGED_TEAMS = [s.strip() for s in config.get("openid.privileged_teams", "").split(",")] 24 | PROXY_SETUP = False 25 | TEMPLATES_DIR = os.path.join(WEBFAF_DIR, "templates") 26 | ADMINS = config.get("mail.admins", "").split(",") 27 | BRAND_TITLE = config.get("hub.brand_title", "ABRT") 28 | BRAND_SUBTITLE = config.get("hub.brand_subtitle", "Analytics") 29 | BANNER = config.get("hub.banner", "") 30 | CACHE_TYPE = config.get("cache.type", "simple") 31 | MEMCACHED_HOST = config.get("cache.memcached_host", None) 32 | MEMCACHED_PORT = config.get("cache.memcached_port", None) 33 | MEMCACHED_KEY_PREFIX = config.get("cache.memcached_key_prefix", None) 34 | EVERYONE_IS_MAINTAINER = str2bool(config.get("hub.everyone_is_maintainer", "false")) 35 | EVERYONE_IS_ADMIN = str2bool(config.get("hub.everyone_is_admin", "false")) 36 | FEDMENU_URL = config.get("hub.fedmenu_url", None) 37 | FEDMENU_DATA_URL = config.get("hub.fedmenu_data_url", None) 38 | FAF_VERSION = pyfaf.__version__ 39 | 40 | 41 | class ProductionConfig(Config): 42 | DEBUG = str2bool(config["hub.debug"]) 43 | PROXY_SETUP = str2bool(config.get("hub.proxy_setup", "false")) 44 | SECRET_KEY = config["hub.secret_key"] 45 | 46 | 47 | class DevelopmentConfig(Config): 48 | DEBUG = True 49 | SQLALCHEMY_ECHO = True 50 | 51 | 52 | class TestingConfig(Config): 53 | TESTING = True 54 | OPENID_FS_STORE = None 55 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/Makefile.am: -------------------------------------------------------------------------------- 1 | versions_PYTHON = \ 2 | 1c4d6317721a_support_mirrors.py \ 3 | 133991a89da4_build_to_opsysrelease.py \ 4 | 168c63b81f85_report_history_default_value.py \ 5 | 17d4911132f8_assigning_release_to_repo.py \ 6 | 183a15e52a4f_report_history_unique.py \ 7 | 1b264b21ca91_add_semrel_to_build.py \ 8 | 1c7edfbf8941_drop_reportunknownpackage_running_fields.py \ 9 | 21345f007bdf_add_privileged_user_field.py \ 10 | 23bab42e7be7_initial_migration.py \ 11 | 272e6a3deea4_link_probable_fix_to_build.py \ 12 | 2dfd5aef57ca_add_eol_bz_resolution.py \ 13 | 2e5f6d8b68f5_add_contact_email_tables.py \ 14 | 31d0249e8d4c_create_users_table.py \ 15 | 43bd2d59838e_add_mantisbt.py \ 16 | 47cf82727ed1_acl_permissions.py \ 17 | 48550f308625_add_symbolsource_retrace_fail_count.py \ 18 | 4ff13674a015_add_semver_to_build.py \ 19 | 50d3e87e4b2a_add_reporturl.py \ 20 | 5695a1c595c3_reportreleasedesktops.py \ 21 | 13557f1962e6_ureport_added_certainty.py \ 22 | 58f44afc3a3a_drop_running_package_from_reportpackages.py \ 23 | 71905f91e7b7_add_archived_reports.py \ 24 | 729a154b1609_index_reportpackages.py \ 25 | 7fa8b3134f0_probable_fix_by_opsy.py \ 26 | 82081a3c76b_rename_kb_to_sf_prefilter.py \ 27 | cef2fcd69ef_celery_tasks.py \ 28 | 89d35a57f82b_add_new_value_to_repo_types_enum.py \ 29 | 9301a426f19d_associates_to_opsys.py \ 30 | acd3d9bf85d1_ignore_private_bz.py \ 31 | e5d5cefb8ca4_add_dnf_type.py \ 32 | f43edd5b636d_enable_problem_components_reassign.py \ 33 | a2b6d12819f9_drop_yum_type.py \ 34 | 093be3eab7e9_add_ondelete_cascade_to_problem_tables.py \ 35 | cb084388e232_add_ondelete_cascade_to_report_bt_tables.py \ 36 | e17dc14292b9_add_ondelete_cascade_to_report_tables.py \ 37 | cee07a513404_drop_not_used_.py \ 38 | 8ac9b3343649_add_semver_semrel_to_.py \ 39 | fd5dc71471cc_set_pkg_name_to_256.py \ 40 | 9596a0f03838_zero_unique_reports_to_one.py \ 41 | bb2289ffb392_add_tz_info_to_periodictasks.py 42 | 43 | 44 | versionsdir = $(pythondir)/pyfaf/storage/migrations/versions 45 | -------------------------------------------------------------------------------- /src/pyfaf/utils/date.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | import datetime 20 | 21 | from typing import Generator, List 22 | 23 | __all__ = ["daterange", "prev_days"] 24 | 25 | 26 | def daterange(a_date, b_date, step=1, desc=False) -> Generator[datetime.date, None, None]: 27 | """ 28 | Generator returning dates from lower to higher 29 | date if `desc` is False or from higher to lower 30 | if `desc` is True. 31 | 32 | `a_date` and `b_date` are always included in the 33 | result. 34 | """ 35 | 36 | lower = min(a_date, b_date) 37 | higher = max(a_date, b_date) 38 | 39 | if desc: 40 | for x in range(0, (higher - lower).days, step): 41 | dt = higher - datetime.timedelta(x) 42 | yield dt 43 | 44 | yield lower 45 | else: 46 | for x in range(0, (higher - lower).days, step): 47 | dt = lower + datetime.timedelta(x) 48 | yield dt 49 | 50 | yield higher 51 | 52 | 53 | def prev_days(num_days, start_from=None) -> List[datetime.date]: 54 | """ 55 | Return the list of dates preceding current day by `num_days` 56 | """ 57 | 58 | dlist = [] 59 | if not start_from: 60 | start_from = datetime.date.today() 61 | 62 | for i in range(1, num_days + 1): 63 | dlist.append(start_from - datetime.timedelta(days=i)) 64 | 65 | return list(reversed(dlist)) 66 | -------------------------------------------------------------------------------- /src/webfaf/login.py: -------------------------------------------------------------------------------- 1 | import flask 2 | from openid_teams import teams 3 | from werkzeug.wrappers import Response 4 | 5 | from pyfaf.storage.user import User 6 | from webfaf.webfaf_main import db, oid, app 7 | from webfaf.utils import fed_raw_name 8 | 9 | login = flask.Blueprint("login", __name__) 10 | 11 | 12 | @login.route("/login/", methods=["GET"]) 13 | @oid.loginhandler 14 | def do_login() -> Response: 15 | if flask.g.user is not None: 16 | return flask.redirect(oid.get_next_url()) 17 | 18 | teams_req = teams.TeamsRequest(app.config["OPENID_PRIVILEGED_TEAMS"]) 19 | return oid.try_login("https://id.fedoraproject.org/", 20 | ask_for=["email"], extensions=[teams_req]) 21 | 22 | 23 | @oid.after_login 24 | def create_or_login(resp) -> Response: 25 | flask.session["openid"] = resp.identity_url 26 | username = fed_raw_name(resp.identity_url) 27 | 28 | privileged = False 29 | # "lp" is the namespace for openid-teams 30 | if "lp" in resp.extensions and any(group in app.config["OPENID_PRIVILEGED_TEAMS"] 31 | for group in resp.extensions["lp"].teams): 32 | privileged = True 33 | 34 | user = db.session.query(User).filter(User.username == username).first() 35 | if not user: # create 36 | user = User(username=username, mail=resp.email, privileged=privileged) 37 | else: 38 | user.mail = resp.email 39 | user.privileged = privileged 40 | 41 | db.session.add(user) 42 | db.session.commit() 43 | flask.flash(u"Welcome, {0}".format(user.username)) 44 | # This is okay: https://flask.palletsprojects.com/en/2.0.x/api/#flask.g 45 | # pylint: disable=assigning-non-slot 46 | flask.g.user = user 47 | 48 | if flask.request.url_root == oid.get_next_url(): 49 | return flask.redirect(flask.url_for("summary.index")) 50 | 51 | return flask.redirect(oid.get_next_url()) 52 | 53 | 54 | @login.route("/logout/") 55 | def do_logout() -> Response: 56 | flask.session.pop("openid", None) 57 | flask.flash(u"You were signed out") 58 | return flask.redirect(oid.get_next_url()) 59 | -------------------------------------------------------------------------------- /src/pyfaf/utils/hash.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 ABRT Team 2 | # Copyright (C) 2015 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | import hashlib 20 | 21 | __all__ = ["hash_list", "hash_path"] 22 | 23 | 24 | def hash_list(inlist) -> str: 25 | """ 26 | Return hash digest from `inlist` list of strings. 27 | 28 | Strings are concatenated with newlines prior to hashing 29 | """ 30 | 31 | merged = "\n".join(inlist) 32 | return hashlib.sha1(merged.encode("utf-8")).hexdigest() 33 | 34 | 35 | def hash_path(path, prefixes) -> str: 36 | """ 37 | Returns path with part after prefixes hashed with sha256 38 | 39 | In case of paths starting with /home, ignore username. 40 | 41 | Example: 42 | hash_path("/home/user/a.out", ["/home", "/opt"]) = 43 | "/home/1816a735235f2a21efd602ff4d9b157bf060540270230597923af0aa6de780e9" 44 | 45 | hash_path("/usr/local/private/code.src", ["/usr/local"]) = 46 | "/usr/local/039580e05aa4fcec4fbb57e0532311c399453950b741041bce8e72d17698416f" 47 | """ 48 | 49 | for prefix in prefixes: 50 | if path.startswith(prefix): 51 | _, rest = path.split(prefix, 1) 52 | rest = rest[1:] # remove leading / 53 | 54 | if prefix == "/home": 55 | _, rest = rest.split("/", 1) 56 | 57 | hashed = hashlib.sha256(rest.encode("utf-8")).hexdigest() 58 | 59 | return "{0}/{1}".format(prefix, hashed) 60 | return path 61 | -------------------------------------------------------------------------------- /src/pyfaf/actions/pull_abrt_bugs.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from pyfaf.actions import Action 20 | from pyfaf.bugtrackers import bugtrackers 21 | 22 | 23 | class PullAbrtBugs(Action): 24 | name = "pull-abrt-bugs" 25 | 26 | def run(self, cmdline, db) -> int: 27 | if cmdline.bugtracker: 28 | tracker = bugtrackers[cmdline.bugtracker] 29 | if not tracker.installed(db): 30 | self.log_error("Bugtracker is not installed") 31 | return 1 32 | 33 | self.log_info("Processing bugtracker: {0}" 34 | .format(cmdline.bugtracker)) 35 | for bug_id in tracker.list_bugs(): 36 | tracker.download_bug_to_storage(db, bug_id) 37 | 38 | return 0 39 | 40 | self.log_info("Processing all bugtrackers") 41 | for name, tracker in bugtrackers.items(): 42 | self.log_info("Processing bugtracker: {0}".format(name)) 43 | if not tracker.installed(db): 44 | self.log_info("Bugtracker {0} not installed, skipping" 45 | .format(name)) 46 | continue 47 | 48 | for bug_id in tracker.list_bugs(): 49 | tracker.download_bug_to_storage(db, bug_id) 50 | 51 | return 0 52 | 53 | def tweak_cmdline_parser(self, parser) -> None: 54 | parser.add_bugtracker() 55 | -------------------------------------------------------------------------------- /src/pyfaf/utils/storage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 ABRT Team 2 | # Copyright (C) 2014 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | 20 | # Utility functions related to faf's storage 21 | 22 | from collections import defaultdict 23 | 24 | __all__ = ["format_reason", "most_common_crash_function"] 25 | 26 | 27 | def format_reason(rtype, reason, function_name) -> str: 28 | """ 29 | Return formatted `reason` of the crash according to report type `rtype` 30 | """ 31 | 32 | if rtype == "core": 33 | return "Crash in {0}".format(function_name) 34 | 35 | if rtype == "python": 36 | spl = reason.split(":") 37 | if len(spl) >= 4: 38 | fname, line, loc, exception = spl[:4] 39 | if loc == "": 40 | loc = "{0}:{1}".format(fname, line) 41 | return "{0} in {1}".format(exception, loc) 42 | 43 | return "Exception" 44 | 45 | if rtype == "kerneloops": 46 | return "Kerneloops" 47 | 48 | return "Crash" 49 | 50 | 51 | def most_common_crash_function(backtraces) -> str: 52 | """ 53 | Return the most common crash function among all backtraces of this 54 | report 55 | """ 56 | 57 | crash_functions = defaultdict(int) 58 | crash_functions["??"] = 0 59 | for bt in backtraces: 60 | if bt.crash_function: 61 | crash_functions[bt.crash_function] += 1 62 | result = max(crash_functions.items(), key=lambda x: x[1]) 63 | return result[0] 64 | -------------------------------------------------------------------------------- /src/pyfaf/storage/migrations/versions/9596a0f03838_zero_unique_reports_to_one.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 ABRT Team 2 | # Copyright (C) 2020 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | """ 20 | Make all report summaries contain at least one unique report 21 | 22 | Revision ID: 9596a0f03838 23 | Revises: fd5dc71471cc 24 | Create Date: 2020-01-09 09:23:53.053811 25 | """ 26 | 27 | from alembic.op import execute 28 | from sqlalchemy import and_, update 29 | 30 | import pyfaf.storage as st 31 | 32 | 33 | # revision identifiers, used by Alembic. 34 | revision = '9596a0f03838' 35 | down_revision = 'fd5dc71471cc' 36 | 37 | 38 | def upgrade() -> None: 39 | # Set the unique count to one for all report summaries which have no 40 | # unique reports but have _some_ reports. 41 | execute(update(st.ReportHistoryDaily) 42 | .where(and_(st.ReportHistoryDaily.unique == 0, 43 | st.ReportHistoryDaily.count > 0)) 44 | .values(unique=1)) 45 | execute(update(st.ReportHistoryMonthly) 46 | .where(and_(st.ReportHistoryMonthly.unique == 0, 47 | st.ReportHistoryMonthly.count > 0)) 48 | .values(unique=1)) 49 | execute(update(st.ReportHistoryWeekly) 50 | .where(and_(st.ReportHistoryWeekly.unique == 0, 51 | st.ReportHistoryWeekly.count > 0)) 52 | .values(unique=1)) 53 | 54 | 55 | def downgrade() -> None: 56 | # It does not make sense to reverse this migration. 57 | pass 58 | -------------------------------------------------------------------------------- /src/pyfaf/bugtrackers/rhelbz.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | from typing import Any, Dict, Generator, Optional 20 | 21 | from pyfaf.bugtrackers import bugzilla 22 | 23 | __all__ = ["RhelBugzilla"] 24 | 25 | 26 | class RhelBugzilla(bugzilla.Bugzilla): 27 | name = "rhel-bugzilla" 28 | 29 | def list_bugs(self, *args, **kwargs) -> Generator[int, None, None]: 30 | 31 | abrt_specific = dict( 32 | status_whiteboard="abrt_hash", 33 | status_whiteboard_type="allwordssubstr", 34 | product=["Red Hat Enterprise Linux 6", 35 | "Red Hat Enterprise Linux 7", 36 | "Red Hat Enterprise Linux 8"], 37 | ) 38 | 39 | if "custom_fields" in kwargs: 40 | kwargs["custom_fields"].update(abrt_specific) 41 | else: 42 | kwargs["custom_fields"] = abrt_specific 43 | 44 | return super().list_bugs(*args, **kwargs) 45 | 46 | def preprocess_bug(self, bug) -> Optional[Dict[str, Any]]: 47 | bug_dict = super().preprocess_bug(bug) 48 | 49 | # handle "Red Hat Enterprise Linux \d" product naming 50 | # by stripping the number which is redundant for our purposes 51 | # as we also have bug_dict["version"] from bugzilla 52 | 53 | if "Red Hat Enterprise Linux" in bug_dict["product"]: 54 | bug_dict["product"] = " ".join(bug_dict["product"].split()[:-1]) 55 | 56 | return bug_dict 57 | -------------------------------------------------------------------------------- /src/webfaf/static/js/color.js: -------------------------------------------------------------------------------- 1 | function getColors(neededColors){ 2 | if (typeof neededColors === 'undefined'){ 3 | neededColors = 1; 4 | } 5 | 6 | var colorPool = ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"]; 7 | var c, colors = [], 8 | colorPoolSize = colorPool.length, variation = 0; 9 | 10 | for (i = 0; i < neededColors; i++) { 11 | 12 | c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); 13 | 14 | // Each time we exhaust the colors in the pool we adjust 15 | // a scaling factor used to produce more variations on 16 | // those colors. The factor alternates negative/positive 17 | // to produce lighter/darker colors. 18 | 19 | // Reset the variation after every few cycles, or else 20 | // it will end up producing only white or black colors. 21 | 22 | if (i % colorPoolSize == 0 && i) { 23 | if (variation >= 0) { 24 | if (variation < 0.5) { 25 | variation = -variation - 0.2; 26 | } else variation = 0; 27 | } else variation = -variation; 28 | } 29 | 30 | colors[i] = c.scale('rgb', 1 + variation); 31 | } 32 | return colors; 33 | } 34 | 35 | function LightenDarkenColor(col, amt) { 36 | 37 | var usePound = false; 38 | 39 | if (col[0] == "#") { 40 | col = col.slice(1); 41 | usePound = true; 42 | } 43 | 44 | var num = parseInt(col,16); 45 | 46 | var r = (num >> 16) + amt; 47 | 48 | if (r > 255) r = 255; 49 | else if (r < 0) r = 0; 50 | 51 | var b = ((num >> 8) & 0x00FF) + amt; 52 | 53 | if (b > 255) b = 255; 54 | else if (b < 0) b = 0; 55 | 56 | var g = (num & 0x0000FF) + amt; 57 | 58 | if (g > 255) g = 255; 59 | else if (g < 0) g = 0; 60 | 61 | return (usePound?"#":"") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6); 62 | 63 | } 64 | 65 | function componentToHex(c) { 66 | var hex = c.toString(16); 67 | return hex.length == 1 ? "0" + hex : hex; 68 | } 69 | 70 | function rgbToHex(r, g, b) { 71 | return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); 72 | } 73 | -------------------------------------------------------------------------------- /src/pyfaf/actions/shell.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 ABRT Team 2 | # Copyright (C) 2013 Red Hat, Inc. 3 | # 4 | # This file is part of faf. 5 | # 6 | # faf is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # faf is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with faf. If not, see . 18 | 19 | # Unused variable 20 | # pylint: disable-msg=W0612 21 | 22 | # Unused import 23 | # pylint: disable-msg=W0611 24 | # pylint: disable-msg=W0614 25 | 26 | # Wildcard import 27 | # pylint: disable-msg=W0401 28 | 29 | from typing import Optional 30 | 31 | from collections.abc import Iterable 32 | from sqlalchemy.sql.expression import func 33 | 34 | import pyfaf 35 | from pyfaf.storage import * # pylint: disable=redefined-builtin 36 | from pyfaf.actions import Action 37 | 38 | 39 | class Shell(Action): 40 | name = "shell" 41 | cmdline_only = True 42 | 43 | 44 | def run(self, cmdline, db) -> Optional[int]: 45 | session = db.session 46 | 47 | def first(obj): 48 | return session.query(obj).first() 49 | 50 | # Redefining built-in 'any' 51 | # pylint: disable-msg=W0622 52 | def any(obj): 53 | if isinstance(obj, Iterable): 54 | return __builtins__["any"](obj) 55 | 56 | return session.query(obj).order_by(func.random()).first() 57 | 58 | try: 59 | import IPython 60 | except ImportError: 61 | print("IPython required") 62 | return 1 63 | 64 | # Module 'IPython' has no 'Shell' member 65 | # pylint: disable-msg=E1101 66 | if hasattr(IPython, "embed"): 67 | IPython.embed() 68 | else: 69 | IPython.Shell.IPShellEmbed()() 70 | --------------------------------------------------------------------------------