diff --git a/.dnf.metadata b/.dnf.metadata
index 2c26a84..481b8dd 100644
--- a/.dnf.metadata
+++ b/.dnf.metadata
@@ -1 +1 @@
-71cc8d130f8f7327f57e9b96a271a0f9a18e7e0e SOURCES/dnf-4.12.0.tar.gz
+0697aee277730c57446b5b87bdb12456cf245203 SOURCES/dnf-4.14.0.tar.gz
diff --git a/.gitignore b/.gitignore
index 6838c8a..7748361 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/dnf-4.12.0.tar.gz
+SOURCES/dnf-4.14.0.tar.gz
diff --git a/SOURCES/0001-Base.reset-plug-temporary-leak-of-libsolv-s-page-fil.patch b/SOURCES/0001-Base.reset-plug-temporary-leak-of-libsolv-s-page-fil.patch
deleted file mode 100644
index 2162232..0000000
--- a/SOURCES/0001-Base.reset-plug-temporary-leak-of-libsolv-s-page-fil.patch
+++ /dev/null
@@ -1,317 +0,0 @@
-From 5ce5ed1ea08ad6e198c1c1642c4d9ea2db6eab86 Mon Sep 17 00:00:00 2001
-From: Laszlo Ersek <lersek@redhat.com>
-Date: Sun, 24 Apr 2022 09:08:28 +0200
-Subject: [PATCH] Base.reset: plug (temporary) leak of libsolv's page file
- descriptors
-
-Consider the following call paths (mixed Python and C), extending from
-livecd-creator down to libsolv:
-
-  main                                                [livecd-tools/tools/livecd-creator]
-    install()                                         [livecd-tools/imgcreate/creator.py]
-      fill_sack()                                     [dnf/dnf/base.py]
-        _add_repo_to_sack()                           [dnf/dnf/base.py]
-          load_repo()                                 [libdnf/python/hawkey/sack-py.cpp]
-            dnf_sack_load_repo()                      [libdnf/libdnf/dnf-sack.cpp]
-              write_main()                            [libdnf/libdnf/dnf-sack.cpp]
-                repo_add_solv()                       [libsolv/src/repo_solv.c]
-                  repopagestore_read_or_setup_pages() [libsolv/src/repopage.c]
-                    dup()
-              write_ext()                             [libdnf/libdnf/dnf-sack.cpp]
-                repo_add_solv()                       [libsolv/src/repo_solv.c]
-                  repopagestore_read_or_setup_pages() [libsolv/src/repopage.c]
-                    dup()
-
-The dup() calls create the following file descriptors (output from
-"lsof"):
-
-> COMMAND  PID USER FD  TYPE DEVICE SIZE/OFF   NODE NAME
-> python3 6500 root  7r  REG    8,1 25320727 395438 /var/tmp/imgcreate-mytcghah/install_root/var/cache/dnf/fedora.solv (deleted)
-> python3 6500 root  8r  REG    8,1 52531426 395450 /var/tmp/imgcreate-mytcghah/install_root/var/cache/dnf/fedora-filenames.solvx
-
-These file descriptors are *owned* by the DnfSack object (which is derived
-from GObject), as follows:
-
-  sack->priv->pool->repos[1]->repodata[1]->store.pagefd = 7
-  sack->priv->pool->repos[1]->repodata[2]->store.pagefd = 8
-  ^     ^     ^     ^         ^            ^      ^
-  |     |     |     |         |            |      |
-  |     |     |     |         |            |      int
-  |     |     |     |         |            Repopagestore [libsolv/src/repopage.h]
-  |     |     |     |         Repodata                   [libsolv/src/repodata.h]
-  |     |     |     struct s_Repo                        [libsolv/src/repo.h]
-  |     |     struct s_Pool (aka Pool)                   [libsolv/src/pool.h]
-  |     DnfSackPrivate                                   [libdnf/libdnf/dnf-sack.cpp]
-  DnfSack                                                [libdnf/libdnf/dnf-sack.h]
-
-The file descriptors are *supposed* to be closed on the following call
-path:
-
-  main                                         [livecd-tools/tools/livecd-creator]
-    install()                                  [livecd-tools/imgcreate/creator.py]
-      close()                                  [livecd-tools/imgcreate/dnfinst.py]
-        close()                                [dnf/dnf/base.py]
-          reset()                              [dnf/dnf/base.py]
-            _sack = None
-            _goal = None
-            _transaction = None
-              ...
-                dnf_sack_finalize()            [libdnf/libdnf/dnf-sack.cpp]
-                  pool_free()                  [libsolv/src/pool.c]
-                    pool_freeallrepos()        [libsolv/src/pool.c]
-                      repo_freedata()          [libsolv/src/repo.c]
-                        repodata_freedata()    [libsolv/src/repodata.c]
-                          repopagestore_free() [libsolv/src/repopage.c]
-                            close()
-
-Namely, when dnf.Base.reset() [dnf/dnf/base.py] is called with (sack=True,
-goal=True), the reference counts of the objects pointed to by the "_sack",
-"_goal" and "_transaction" fields are supposed to reach zero, and then, as
-part of the DnfSack object's finalization, the libsolv file descriptors
-are supposed to be closed.
-
-Now, while this *may* happen immediately in dnf.Base.reset(), it may as
-well not. The reason is that there is a multitude of *circular references*
-between DnfSack and the packages that it contains. When dnf.Base.reset()
-is entered, we have the following picture:
-
-     _sack                   _goal
-        |                      |
-        v                      v
-   +----------------+      +-------------+
-   | DnfSack object | <--- | Goal object |
-   +----------------+      +-------------+
-     |^    |^    |^
-     ||    ||    ||
-     ||    ||    ||
-  +--||----||----||---+
-  |  v|    v|    v|   | <-- _transaction
-  | Pkg1  Pkg2  PkgN  |
-  |                   |
-  | Transaction oject |
-  +-------------------+
-
-That is, the reference count of the DnfSack object is (1 + 1 + N), where N
-is the number of packages in the transaction. Details:
-
-(a) The first reference comes from the "_sack" field, established like
-    this:
-
-      main                       [livecd-tools/tools/livecd-creator]
-        install()                [livecd-tools/imgcreate/creator.py]
-          fill_sack()            [dnf/dnf/base.py]
-            _build_sack()        [dnf/dnf/sack.py]
-              Sack()
-                sack_init()      [libdnf/python/hawkey/sack-py.cpp]
-                  dnf_sack_new() [libdnf/libdnf/dnf-sack.cpp]
-
-(b) The second reference on the DnfSack object comes from "_goal":
-
-      main                        [livecd-tools/tools/livecd-creator]
-        install()                 [livecd-tools/imgcreate/creator.py]
-          fill_sack()             [dnf/dnf/base.py]
-             _goal = Goal(_sack)
-               goal_init()        [libdnf/python/hawkey/goal-py.cpp]
-                 Py_INCREF(_sack)
-
-(c) Then there is one reference to "_sack" *per package* in the
-    transaction:
-
-      main                                  [livecd-tools/tools/livecd-creator]
-        install()                           [livecd-tools/imgcreate/creator.py]
-          runInstall()                      [livecd-tools/imgcreate/dnfinst.py]
-            resolve()                       [dnf/dnf/base.py]
-              _goal2transaction()           [dnf/dnf/base.py]
-                list_installs()             [libdnf/python/hawkey/goal-py.cpp]
-                  list_generic()            [libdnf/python/hawkey/goal-py.cpp]
-                    packagelist_to_pylist() [libdnf/python/hawkey/iutil-py.cpp]
-                      new_package()         [libdnf/python/hawkey/sack-py.cpp]
-                        Py_BuildValue()
-                ts.add_install()
-
-    list_installs() creates a list of packages that need to be installed
-    by DNF. Inside the loop in packagelist_to_pylist(), which constructs
-    the elements of that list, Py_BuildValue() is called with the "O"
-    format specifier, and that increases the reference count on "_sack".
-
-    Subsequently, in the _goal2transaction() method, we iterate over the
-    package list created by list_installs(), and add each package to the
-    transaction (ts.add_install()). After _goal2transaction() returns,
-    this transaction is assigned to "self._transaction" in resolve(). This
-    is where the last N (back-)references on the DnfSack object come from.
-
-(d) Now, to quote the defintion of the DnfSack object
-    ("libdnf/docs/hawkey/tutorial-py.rst"):
-
-> *Sack* is an abstraction for a collection of packages.
-
-    That's why the DnfSack object references all the Pkg1 through PkgN
-    packages.
-
-So, when the dnf.Base.reset() method completes, the picture changes like
-this:
-
-     _sack                     _goal
-        |                        |
-   -- [CUT] --              -- [CUT] --
-        |                        |
-        v                |       v
-   +----------------+   [C]  +-------------+
-   | DnfSack object | <-[U]- | Goal object |
-   +----------------+   [T]  +-------------+
-     |^    |^    |^      |
-     ||    ||    ||
-     ||    ||    ||         |
-  +--||----||----||---+    [C]
-  |  v|    v|    v|   | <--[U]-- _transaction
-  | Pkg1  Pkg2  PkgN  |    [T]
-  |                   |     |
-  | Transaction oject |
-  +-------------------+
-
-and we are left with N reference cycles (one between each package and the
-same DnfSack object).
-
-This set of cycles can only be cleaned up by Python's generational garbage
-collector <https://stackify.com/python-garbage-collection/>. The GC will
-collect the DnfSack object, and consequently close the libsolv page file
-descriptors via dnf_sack_finalize() -- but garbage collection will happen
-*only eventually*, unpredictably.
-
-This means that the dnf.Base.reset() method breaks its interface contract:
-
-> Make the Base object forget about various things.
-
-because the libsolv file descriptors can (and frequently do, in practice)
-survive dnf.Base.reset().
-
-In general, as long as the garbage collector only tracks process-private
-memory blocks, there's nothing wrong; however, file descriptors are
-visible to the kernel. When dnf.Base.reset() *temporarily* leaks file
-descriptors as explained above, then immediately subsequent operations
-that depend on those file descriptors having been closed, can fail.
-
-An example is livecd-creator's unmounting of:
-
-  /var/tmp/imgcreate-mytcghah/install_root/var/cache/dnf
-
-which the kernel refuses, due to libsolv's still open file descriptors
-pointing into that filesystem:
-
-> umount: /var/tmp/imgcreate-mytcghah/install_root/var/cache/dnf: target
-> is busy.
-> Unable to unmount /var/tmp/imgcreate-mytcghah/install_root/var/cache/dnf
-> normally, using lazy unmount
-
-(Unfortunately, the whole lazy umount idea is misguided in livecd-tools;
-it's a misfeature that should be removed, as it permits the corruption of
-the loop-backed filesystem. Now that the real bug is being fixed in DNF,
-lazy umount is not needed as a (broken) workaround in livecd-tools. But
-that's a separate patch for livecd-tools:
-<https://github.com/livecd-tools/livecd-tools/pull/227>.)
-
-Plug the fd leak by forcing a garbage collection in dnf.Base.reset()
-whenever we cut the "_sack", "_goal" and "_transaction" links -- that is,
-when the "sack" and "goal" parameters are True.
-
-Note that precisely due to the unpredictable behavior of the garbage
-collector, reproducing the bug may prove elusive. In order to reproduce it
-deterministically, through usage with livecd-creator, disabling automatic
-garbage collection with the following patch (for livecd-tools) is
-sufficient:
-
-> diff --git a/tools/livecd-creator b/tools/livecd-creator
-> index 291de10cbbf9..8d2c740c238b 100755
-> --- a/tools/livecd-creator
-> +++ b/tools/livecd-creator
-> @@ -31,6 +31,8 @@ from dnf.exceptions import Error as DnfBaseError
->  import imgcreate
->  from imgcreate.errors import KickstartError
->
-> +import gc
-> +
->  class Usage(Exception):
->      def __init__(self, msg = None, no_error = False):
->          Exception.__init__(self, msg, no_error)
-> @@ -261,5 +263,6 @@ def do_nss_libs_hack():
->      return hack
->
->  if __name__ == "__main__":
-> +    gc.disable()
->      hack = do_nss_libs_hack()
->      sys.exit(main())
-
-Also note that you need to use livecd-tools at git commit 4afde9352e82 or
-later, for this fix to make any difference: said commit fixes a different
-(independent) bug in livecd-tools that produces identical symptoms, but
-from a different origin. In other words, if you don't have commit
-4afde9352e82 in your livecd-tools install, then said bug in livecd-tools
-will mask this DNF fix.
-
-Signed-off-by: Laszlo Ersek <lersek@redhat.com>
----
- dnf/base.py | 41 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
-
-diff --git a/dnf/base.py b/dnf/base.py
-index caace028..520574b4 100644
---- a/dnf/base.py
-+++ b/dnf/base.py
-@@ -72,6 +72,7 @@ import dnf.transaction
- import dnf.util
- import dnf.yum.rpmtrans
- import functools
-+import gc
- import hawkey
- import itertools
- import logging
-@@ -569,6 +570,46 @@ class Base(object):
-             self._comps_trans = dnf.comps.TransactionBunch()
-             self._transaction = None
-         self._update_security_filters = []
-+        if sack and goal:
-+            # We've just done this, above:
-+            #
-+            #      _sack                     _goal
-+            #         |                        |
-+            #    -- [CUT] --              -- [CUT] --
-+            #         |                        |
-+            #         v                |       v
-+            #    +----------------+   [C]  +-------------+
-+            #    | DnfSack object | <-[U]- | Goal object |
-+            #    +----------------+   [T]  +-------------+
-+            #      |^    |^    |^      |
-+            #      ||    ||    ||
-+            #      ||    ||    ||         |
-+            #   +--||----||----||---+    [C]
-+            #   |  v|    v|    v|   | <--[U]-- _transaction
-+            #   | Pkg1  Pkg2  PkgN  |    [T]
-+            #   |                   |     |
-+            #   | Transaction oject |
-+            #   +-------------------+
-+            #
-+            # At this point, the DnfSack object would be released only
-+            # eventually, by Python's generational garbage collector, due to the
-+            # cyclic references DnfSack<->Pkg1 ... DnfSack<->PkgN.
-+            #
-+            # The delayed release is a problem: the DnfSack object may
-+            # (indirectly) own "page file" file descriptors in libsolv, via
-+            # libdnf. For example,
-+            #
-+            #   sack->priv->pool->repos[1]->repodata[1]->store.pagefd = 7
-+            #   sack->priv->pool->repos[1]->repodata[2]->store.pagefd = 8
-+            #
-+            # These file descriptors are closed when the DnfSack object is
-+            # eventually released, that is, when dnf_sack_finalize() (in libdnf)
-+            # calls pool_free() (in libsolv).
-+            #
-+            # We need that to happen right now, as callers may want to unmount
-+            # the filesystems which those file descriptors refer to immediately
-+            # after reset() returns. Therefore, force a garbage collection here.
-+            gc.collect()
- 
-     def _closeRpmDB(self):
-         """Closes down the instances of rpmdb that could be open."""
--- 
-2.35.1
-
diff --git a/SOURCES/0001-Pass-whole-URL-in-relativeUrl-to-PackageTarget-for-R.patch b/SOURCES/0001-Pass-whole-URL-in-relativeUrl-to-PackageTarget-for-R.patch
new file mode 100644
index 0000000..b8ea3b7
--- /dev/null
+++ b/SOURCES/0001-Pass-whole-URL-in-relativeUrl-to-PackageTarget-for-R.patch
@@ -0,0 +1,62 @@
+From 5e082d74b73bf1b3565cfd72a3e1ba7a45a00a8b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com>
+Date: Wed, 7 Sep 2022 14:40:32 +0200
+Subject: [PATCH 1/2] Pass whole URL in relativeUrl to PackageTarget for RPM
+ URL download
+
+The PackageTarget supports baseUrl and relativeUrl on the API, but then
+the relativeUrl is just a path fragment with no definition on whether it
+should be encoded. It's being passed unencoded paths from other places,
+and so there's a conditional encode (only if not full URL) in libdnf.
+
+But full URLs are actually supported in relativeUrl (in that case
+baseUrl should be empty) and in that case the URL is expected to be
+encoded and is not encoded for the second time.
+
+Hence, pass the full URL to relativeUrl instead of splitting it. We also
+need to decode the file name we store, as on the filesystem the RPM file
+name is also decoded.
+
+= changelog =
+msg: Don't double-encode RPM URLs passed on CLI
+type: bugfix
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2103015
+---
+ dnf/repo.py | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/dnf/repo.py b/dnf/repo.py
+index ec1a2537..86fb2bf4 100644
+--- a/dnf/repo.py
++++ b/dnf/repo.py
+@@ -47,6 +47,7 @@ import string
+ import sys
+ import time
+ import traceback
++import urllib
+ 
+ _PACKAGES_RELATIVE_DIR = "packages"
+ _MIRRORLIST_FILENAME = "mirrorlist"
+@@ -295,7 +296,7 @@ class RemoteRPMPayload(PackagePayload):
+         self.local_path = os.path.join(self.pkgdir, self.__str__().lstrip("/"))
+ 
+     def __str__(self):
+-        return os.path.basename(self.remote_location)
++        return os.path.basename(urllib.parse.unquote(self.remote_location))
+ 
+     def _progress_cb(self, cbdata, total, done):
+         self.remote_size = total
+@@ -308,8 +309,8 @@ class RemoteRPMPayload(PackagePayload):
+ 
+     def _librepo_target(self):
+         return libdnf.repo.PackageTarget(
+-            self.conf._config, os.path.basename(self.remote_location),
+-            self.pkgdir, 0, None, 0, os.path.dirname(self.remote_location),
++            self.conf._config, self.remote_location,
++            self.pkgdir, 0, None, 0, None,
+             True, 0, 0, self.callbacks)
+ 
+     @property
+-- 
+2.37.3
+
diff --git a/SOURCES/0002-Add-only-relevant-pkgs-to-upgrade-transaction-RhBug-.patch b/SOURCES/0002-Add-only-relevant-pkgs-to-upgrade-transaction-RhBug-.patch
deleted file mode 100644
index a0cdeb8..0000000
--- a/SOURCES/0002-Add-only-relevant-pkgs-to-upgrade-transaction-RhBug-.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From f32eff294aecaac0fd71cd8888a25fa7929460b9 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
-Date: Mon, 4 Jul 2022 09:43:25 +0200
-Subject: [PATCH] Add only relevant pkgs to upgrade transaction (RhBug:2097757)
-
-https://bugzilla.redhat.com/show_bug.cgi?id=2097757
-
-Without this patch dnf can create the following transaction during dnf upgrade --security when there is an advisory for B-2-2:
-
-```
-repo @System 0 testtags <inline>
-#>=Pkg: A 1 1 x86_64
-#>=Pkg: B 1 1 x86_64
-#>=Req: A = 1-1
-
-repo available 0 testtags <inline>
-#>=Pkg: A 2 2 x86_64
-#>=Pkg: B 2 2 x86_64
-#>=Req: A = 2-2
-system x86_64 rpm @System
-job update oneof A-1-1.x86_64@@System B-2-2.x86_64@available [targeted,setevr,setarch]
-result transaction,problems
-```
-
-Problem is that without forcebest nothing gets upgraded despite the available advisory and --security switch.
-
-This can also be seen in CI test case: rpm-software-management/ci-dnf-stack#1130
----
- dnf/base.py | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
-diff --git a/dnf/base.py b/dnf/base.py
-index caace028..92fb3bd0 100644
---- a/dnf/base.py
-+++ b/dnf/base.py
-@@ -2118,7 +2118,24 @@ class Base(object):
-             query.filterm(reponame=reponame)
-         query = self._merge_update_filters(query, pkg_spec=pkg_spec, upgrade=True)
-         if query:
--            query = query.union(installed_query.latest())
-+            # Given that we use libsolv's targeted transactions, we need to ensure that the transaction contains both
-+            # the new targeted version and also the current installed version (for the upgraded package). This is
-+            # because if it only contained the new version, libsolv would decide to reinstall the package even if it
-+            # had just a different buildtime or vendor but the same version
-+            # (https://github.com/openSUSE/libsolv/issues/287)
-+            #   - In general, the query already contains both the new and installed versions but not always.
-+            #     If repository-packages command is used, the installed packages are filtered out because they are from
-+            #     the @system repo. We need to add them back in.
-+            #   - However we need to add installed versions of just the packages that are being upgraded. We don't want
-+            #     to add all installed packages because it could increase the number of solutions for the transaction
-+            #     (especially without --best) and since libsolv prefers the smallest possible upgrade it could result
-+            #     in no upgrade even if there is one available. This is a problem in general but its critical with
-+            #     --security transactions (https://bugzilla.redhat.com/show_bug.cgi?id=2097757)
-+            #   - We want to add only the latest versions of installed packages, this is specifically for installonly
-+            #     packages. Otherwise if for example kernel-1 and kernel-3 were installed and present in the
-+            #     transaction libsolv could decide to install kernel-2 because it is an upgrade for kernel-1 even
-+            #     though we don't want it because there already is a newer version present.
-+            query = query.union(installed_query.latest().filter(name=[pkg.name for pkg in query]))
-             sltr = dnf.selector.Selector(self.sack)
-             sltr.set(pkg=query)
-             self._goal.upgrade(select=sltr)
--- 
-2.36.1
-
diff --git a/SOURCES/0002-Document-changes-to-offline-upgrade-command-RhBug-19.patch b/SOURCES/0002-Document-changes-to-offline-upgrade-command-RhBug-19.patch
new file mode 100644
index 0000000..9643071
--- /dev/null
+++ b/SOURCES/0002-Document-changes-to-offline-upgrade-command-RhBug-19.patch
@@ -0,0 +1,96 @@
+From a41c3aefaa4f982511363645f5608e270094cadf Mon Sep 17 00:00:00 2001
+From: Jan Kolarik <jkolarik@redhat.com>
+Date: Tue, 1 Nov 2022 09:15:08 +0000
+Subject: [PATCH 2/2] Document changes to offline-upgrade command
+ (RhBug:1939975)
+
+A support for security filters was added to the offline-upgrade command. This commit adds the documentation into the man pages.
+
+= changelog =
+type: bugfix
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1939975
+---
+ doc/command_ref.rst | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/doc/command_ref.rst b/doc/command_ref.rst
+index f39f2c71..3ee66bac 100644
+--- a/doc/command_ref.rst
++++ b/doc/command_ref.rst
+@@ -114,7 +114,7 @@ Options
+ 
+ ``--advisory=<advisory>, --advisories=<advisory>``
+     Include packages corresponding to the advisory ID, Eg. FEDORA-2201-123.
+-    Applicable for the install, repoquery, updateinfo and upgrade commands.
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``--allowerasing``
+     Allow erasing of installed packages to resolve dependencies. This option could be used as an alternative to the ``yum swap`` command where packages to remove are not explicitly defined.
+@@ -130,12 +130,12 @@ Options
+     solver may use older versions of dependencies to meet their requirements.
+ 
+ ``--bugfix``
+-    Include packages that fix a bugfix issue. Applicable for the install, repoquery, updateinfo and
+-    upgrade commands.
++    Include packages that fix a bugfix issue. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``--bz=<bugzilla>, --bzs=<bugzilla>``
+-    Include packages that fix a Bugzilla ID, Eg. 123123. Applicable for the install, repoquery,
+-    updateinfo and upgrade commands.
++    Include packages that fix a Bugzilla ID, Eg. 123123. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``-C, --cacheonly``
+     Run entirely from system cache, don't update the cache and use it even in case it is expired.
+@@ -153,8 +153,8 @@ Options
+ 
+ ``--cve=<cves>, --cves=<cves>``
+     Include packages that fix a CVE (Common Vulnerabilities and Exposures) ID
+-    (http://cve.mitre.org/about/), Eg. CVE-2201-0123. Applicable for the install, repoquery, updateinfo,
+-    and upgrade commands.
++    (http://cve.mitre.org/about/), Eg. CVE-2201-0123. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``-d <debug level>, --debuglevel=<debug level>``
+     Debugging output level. This is an integer value between 0 (no additional information strings) and 10 (shows all debugging information, even that not understandable to the user), default is 2. Deprecated, use ``-v`` instead.
+@@ -217,8 +217,8 @@ Options
+     specified multiple times.
+ 
+ ``--enhancement``
+-    Include enhancement relevant packages. Applicable for the install, repoquery, updateinfo and
+-    upgrade commands.
++    Include enhancement relevant packages. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ .. _exclude_option-label:
+ 
+@@ -289,8 +289,8 @@ Options
+      ``--setopt`` using configuration from ``/path/dnf.conf``.
+ 
+ ``--newpackage``
+-    Include newpackage relevant packages. Applicable for the install, repoquery, updateinfo and
+-    upgrade commands.
++    Include newpackage relevant packages. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``--noautoremove``
+     Disable removal of dependencies that are no longer used. It sets
+@@ -362,11 +362,11 @@ Options
+ 
+ ``--sec-severity=<severity>, --secseverity=<severity>``
+     Includes packages that provide a fix for an issue of the specified severity.
+-    Applicable for the install, repoquery, updateinfo and upgrade commands.
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ ``--security``
+-    Includes packages that provide a fix for a security issue. Applicable for the
+-    upgrade command.
++    Includes packages that provide a fix for a security issue. 
++    Applicable for the ``install``, ``repoquery``, ``updateinfo``, ``upgrade`` and ``offline-upgrade`` (dnf-plugins-core) commands.
+ 
+ .. _setopt_option-label:
+ 
+-- 
+2.38.1
+
diff --git a/SOURCES/0003-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch b/SOURCES/0003-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch
new file mode 100644
index 0000000..ea3d079
--- /dev/null
+++ b/SOURCES/0003-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch
@@ -0,0 +1,31 @@
+From e5732ab22f092bb3fc6ce6e8f94aad72f3654383 Mon Sep 17 00:00:00 2001
+From: Jan Kolarik <jkolarik@redhat.com>
+Date: Wed, 31 Aug 2022 07:49:39 +0200
+Subject: [PATCH 1/2] Move system-upgrade plugin to core (RhBug:2054235)
+
+Just doc fix.
+
+= changelog =
+type: bugfix
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2054235
+---
+ doc/command_ref.rst | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/doc/command_ref.rst b/doc/command_ref.rst
+index 996ae3b4..f39f2c71 100644
+--- a/doc/command_ref.rst
++++ b/doc/command_ref.rst
+@@ -189,8 +189,7 @@ Options
+ ``--downloaddir=<path>, --destdir=<path>``
+     Redirect downloaded packages to provided directory. The option has to be used together with the \-\
+     :ref:`-downloadonly <downloadonly-label>` command line option, with the
+-    ``download``, ``modulesync`` or ``reposync`` commands (dnf-plugins-core) or with the ``system-upgrade`` command
+-    (dnf-plugins-extras).
++    ``download``, ``modulesync``, ``reposync`` or ``system-upgrade`` commands (dnf-plugins-core).
+ 
+ .. _downloadonly-label:
+ 
+-- 
+2.38.1
+
diff --git a/SOURCES/0003-Use-installed_all-because-installed_query-is-filtere.patch b/SOURCES/0003-Use-installed_all-because-installed_query-is-filtere.patch
deleted file mode 100644
index e5de647..0000000
--- a/SOURCES/0003-Use-installed_all-because-installed_query-is-filtere.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 776241568cb10e3a671c574b25e06b63d86e7ac0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
-Date: Mon, 4 Jul 2022 09:46:29 +0200
-Subject: [PATCH] Use `installed_all` because `installed_query` is filtered
- user input
-
-`installed_query` could be missing packages. If we specify we want to
-upgrade a specific nevra that is not yet installed, then `installed_query`
-is empty because it is based on user input, but there could be other
-versions of the pkg installed.
-
-Eg: if kernel-1 and kernel-3 are installed and we specify we want to
-upgrade kernel-2, nothing should be done because we already have higher
-version, but now `installed_query` would be empty and kernel-2 would be
-installed.
-
-Therefore, we need to use `installed_all`.
----
- dnf/base.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/dnf/base.py b/dnf/base.py
-index 92fb3bd0..1b0f07ed 100644
---- a/dnf/base.py
-+++ b/dnf/base.py
-@@ -2135,7 +2135,7 @@ class Base(object):
-             #     packages. Otherwise if for example kernel-1 and kernel-3 were installed and present in the
-             #     transaction libsolv could decide to install kernel-2 because it is an upgrade for kernel-1 even
-             #     though we don't want it because there already is a newer version present.
--            query = query.union(installed_query.latest().filter(name=[pkg.name for pkg in query]))
-+            query = query.union(installed_all.latest().filter(name=[pkg.name for pkg in query]))
-             sltr = dnf.selector.Selector(self.sack)
-             sltr.set(pkg=query)
-             self._goal.upgrade(select=sltr)
--- 
-2.36.1
-
diff --git a/SOURCES/0004-Fix-plugins-unit-tests.patch b/SOURCES/0004-Fix-plugins-unit-tests.patch
new file mode 100644
index 0000000..bc88733
--- /dev/null
+++ b/SOURCES/0004-Fix-plugins-unit-tests.patch
@@ -0,0 +1,94 @@
+From 3ef5ec915ea4b5e6fe7d25542f0daccef278c01e Mon Sep 17 00:00:00 2001
+From: Jan Kolarik <jkolarik@redhat.com>
+Date: Tue, 13 Sep 2022 14:35:10 +0200
+Subject: [PATCH] Fix plugins unit tests + unload plugins upon their deletion
+
+---
+ dnf/plugin.py              |  8 ++++++--
+ tests/api/test_dnf_base.py | 24 +++++++++++++++++++-----
+ 2 files changed, 25 insertions(+), 7 deletions(-)
+
+diff --git a/dnf/plugin.py b/dnf/plugin.py
+index b083727d..d2f46ce3 100644
+--- a/dnf/plugin.py
++++ b/dnf/plugin.py
+@@ -98,6 +98,9 @@ class Plugins(object):
+         self.plugin_cls = []
+         self.plugins = []
+ 
++    def __del__(self):
++        self._unload()
++
+     def _caller(self, method):
+         for plugin in self.plugins:
+             try:
+@@ -164,8 +167,9 @@ class Plugins(object):
+         self._caller('transaction')
+ 
+     def _unload(self):
+-        logger.debug(_('Plugins were unloaded'))
+-        del sys.modules[DYNAMIC_PACKAGE]
++        if DYNAMIC_PACKAGE in sys.modules:
++            logger.log(dnf.logging.DDEBUG, 'Plugins were unloaded.')
++            del sys.modules[DYNAMIC_PACKAGE]
+ 
+     def unload_removed_plugins(self, transaction):
+         """
+diff --git a/tests/api/test_dnf_base.py b/tests/api/test_dnf_base.py
+index e84e272b..19754b07 100644
+--- a/tests/api/test_dnf_base.py
++++ b/tests/api/test_dnf_base.py
+@@ -7,10 +7,23 @@ from __future__ import unicode_literals
+ import dnf
+ import dnf.conf
+ 
++import tests.support
++
+ from .common import TestCase
+ from .common import TOUR_4_4
+ 
+ 
++def conf_with_empty_plugins():
++    """
++    Use empty configuration to avoid importing plugins from default paths
++    which would lead to crash of other tests.
++    """
++    conf = tests.support.FakeConf()
++    conf.plugins = True
++    conf.pluginpath = []
++    return conf
++
++
+ class DnfBaseApiTest(TestCase):
+     def setUp(self):
+         self.base = dnf.Base(dnf.conf.Conf())
+@@ -75,13 +88,12 @@ class DnfBaseApiTest(TestCase):
+         self.assertHasType(self.base.transaction, dnf.db.group.RPMTransaction)
+ 
+     def test_init_plugins(self):
+-        # Base.init_plugins(disabled_glob=(), enable_plugins=(), cli=None)
++        # Base.init_plugins()
+         self.assertHasAttr(self.base, "init_plugins")
+ 
+-        # disable plugins to avoid calling dnf.plugin.Plugins._load() multiple times
+-        # which causes the tests to crash
+-        self.base.conf.plugins = False
+-        self.base.init_plugins(disabled_glob=(), enable_plugins=(), cli=None)
++        self.base._conf = conf_with_empty_plugins()
++
++        self.base.init_plugins()
+ 
+     def test_pre_configure_plugins(self):
+         # Base.pre_configure_plugins()
+@@ -99,6 +111,8 @@ class DnfBaseApiTest(TestCase):
+         # Base.unload_plugins()
+         self.assertHasAttr(self.base, "unload_plugins")
+ 
++        self.base._conf = conf_with_empty_plugins()
++
+         self.base.init_plugins()
+         self.base.unload_plugins()
+ 
+-- 
+2.38.1
+
diff --git a/SOURCES/0005-Ignore-processing-variable-files-with-unsupported-en.patch b/SOURCES/0005-Ignore-processing-variable-files-with-unsupported-en.patch
new file mode 100644
index 0000000..87b2b81
--- /dev/null
+++ b/SOURCES/0005-Ignore-processing-variable-files-with-unsupported-en.patch
@@ -0,0 +1,50 @@
+From 490cf87dd27926d16fb10735b467cbc490d5c9f1 Mon Sep 17 00:00:00 2001
+From: Jan Kolarik <jkolarik@redhat.com>
+Date: Wed, 23 Nov 2022 08:44:41 +0000
+Subject: [PATCH] Ignore processing variable files with unsupported encoding
+ (RhBug:2141215)
+
+This issue could be seen for example when there are some temporary files stored by text editors in the `/etc/dnf/vars` folder. These files could be in the binary format and causes `UnicodeDecodeError` exception to be thrown during processing of the var files.
+
+= changelog =
+type: bugfix
+resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2141215
+---
+ dnf/conf/substitutions.py | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/dnf/conf/substitutions.py b/dnf/conf/substitutions.py
+index 1281bdf0..4d0f0d55 100644
+--- a/dnf/conf/substitutions.py
++++ b/dnf/conf/substitutions.py
+@@ -18,13 +18,15 @@
+ # Red Hat, Inc.
+ #
+ 
++import logging
+ import os
+ import re
+ 
+-import dnf
+-import dnf.exceptions
++from dnf.i18n import _
+ 
+ ENVIRONMENT_VARS_RE = re.compile(r'^DNF_VAR_[A-Za-z0-9_]+$')
++logger = logging.getLogger('dnf')
++
+ 
+ class Substitutions(dict):
+     # :api
+@@ -60,7 +62,8 @@ class Substitutions(dict):
+                             val = fp.readline()
+                         if val and val[-1] == '\n':
+                             val = val[:-1]
+-                    except (OSError, IOError):
++                    except (OSError, IOError, UnicodeDecodeError) as e:
++                        logger.warning(_("Error when parsing a variable from file '{0}': {1}").format(filepath, e))
+                         continue
+                 if val is not None:
+                     self[fsvar] = val
+-- 
+2.39.0
+
diff --git a/SPECS/dnf.spec b/SPECS/dnf.spec
index 71738ac..e6374d9 100644
--- a/SPECS/dnf.spec
+++ b/SPECS/dnf.spec
@@ -8,7 +8,7 @@
 %global rpm_version 4.14.0
 
 # conflicts
-%global conflicts_dnf_plugins_core_version 4.0.24-3
+%global conflicts_dnf_plugins_core_version 4.0.26
 %global conflicts_dnf_plugins_extras_version 4.0.4
 %global conflicts_dnfdaemon_version 0.3.19
 
@@ -65,19 +65,19 @@
 It supports RPMs, modules and comps groups & environments.
 
 Name:           dnf
-Version:        4.12.0
-Release:        3%{?dist}
+Version:        4.14.0
+Release:        4%{?dist}
 Summary:        %{pkg_summary}
 # For a breakdown of the licensing, see PACKAGE-LICENSING
 License:        GPLv2+
 URL:            https://github.com/rpm-software-management/dnf
 Source0:        %{url}/archive/%{version}/%{name}-%{version}.tar.gz
+Patch1:         0001-Pass-whole-URL-in-relativeUrl-to-PackageTarget-for-R.patch
+Patch2:         0002-Document-changes-to-offline-upgrade-command-RhBug-19.patch
+Patch3:         0003-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch
+Patch4:         0004-Fix-plugins-unit-tests.patch
+Patch5:         0005-Ignore-processing-variable-files-with-unsupported-en.patch
 
-# Upstream commit which fixes leak of libsolv's page file descriptors.
-# https://github.com/rpm-software-management/dnf/commit/5ce5ed1ea08ad6e198c1c1642c4d9ea2db6eab86
-Patch0001:      0001-Base.reset-plug-temporary-leak-of-libsolv-s-page-fil.patch
-Patch0002:      0002-Add-only-relevant-pkgs-to-upgrade-transaction-RhBug-.patch
-Patch0003:      0003-Use-installed_all-because-installed_query-is-filtere.patch
 BuildArch:      noarch
 BuildRequires:  cmake
 BuildRequires:  gettext
@@ -133,13 +133,12 @@ Common data and configuration files for DNF
 %package -n %{yum_subpackage_name}
 Requires:       %{name} = %{version}-%{release}
 Summary:        %{pkg_summary}
-%if 0%{?fedora}
-%if 0%{?fedora} >= 31
+
+%if 0%{?fedora} && 0%{?fedora} < 31
+Conflicts:      yum < 3.4.3-505
+%else
 Provides:       %{name}-yum = %{version}-%{release}
 Obsoletes:      %{name}-yum < 5
-%else
-Conflicts:      yum < 3.4.3-505
-%endif
 %endif
 
 %description -n %{yum_subpackage_name}
@@ -366,6 +365,33 @@ popd
 %{python3_sitelib}/%{name}/automatic/
 
 %changelog
+* Thu Jan 05 2023 Nicola Sella <nsella@redhat.com> - 4.14.0-4
+- Ignore processing variable files with unsupported encoding (RhBug:2148871)
+
+* Wed Dec 03 2022 Nicola Sella <nsella@redhat.com> - 4.14.0-3
+- Move system-upgrade plugin to core (RhBug:2131288)
+- offline-upgrade: add support for security filters (RhBug:1939975,2139326)
+- Fix plugins unit tests + unload plugins upon their deletion 
+
+* Mon Oct 31 2022 Nicola Sella <nsella@redhat.com> - 4.14.0-2
+- Pass whole URL in relativeUrl to PackageTarget for RPM URL download
+
+* Thu Sep 22 2022 Lukas Hrazky <lhrazky@redhat.com> - 4.14.0-1
+- Update to 4.14.0
+- Add doc related to --destdir and --downloadonly options (RhBug:2100811)
+- Fix broken dependencies error reporting (RhBug:2088422)
+- Add support for group upgrade rollback (RhBug:2016070)
+- Expose plugin unload method to API (RhBug:2047251)
+- Fix upgrade from file to noarch pkg (RhBug:2006018)
+- Allow passing plugin parameters with dashes in names (RhBug:1980712)
+- Don't include resolved advisories for obsoletes with sec. filters (RhBug:2101421)
+- Add only relevant pkgs to upgrade transaction (RhBug:2097757)
+- doc: Describe how gpg keys are stored for `repo_ggpcheck` (RhBug:2020678)
+- bash-completion: use sqlite cache when available
+
+* Thu Sep 15 2022 Marek Blaha <mblaha@redhat.com> - 4.12.0-4
+- Update translations
+
 * Tue Jul 19 2022 Lukas Hrazky <lhrazky@redhat.com> - 4.12.0-3
 - Add only relevant pkgs to upgrade transaction (RhBug:2097757)