-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RHEL-2480: Do not create /root/.gnupg/ directory by accident #3930
Conversation
2ec8aee
to
e13ef77
Compare
e13ef77
to
8d4fb87
Compare
7c6d33e
to
99e2781
Compare
I'm not an insights committer but from past experience working with the gpgme library and, more recently, signature checking in convert2rhel, I support using I'll make some comments about the usage of gpg here but the basic questions of whether insights will do this and whether the design fits into the code base will need to be done by someone on the insights team. |
A little quick note for the steps to reproduce: Key generation fails if pinentry is not installed. $ gpg --full-generate-key
…
gpg: agent_genkey failed: No pinentry
Key generation failed: No pinentry This can be mitigated by, obviously, installing pinentry. # dnf install pinentry
$ gpg --full-generate-key
…
public and secret key created and signed.
… |
The public key that Insights Client uses to verify the egg by default, /etc/insights-client/redhattools.pub.gpg is in the binary OpenPGP format. If you use a GPG key in an armored ASCII format, GPG verification fails:
To fix this, remove the $ gpg --export $KEYID > $HOME/.gnupg/my-key.pub.gpg |
@Glutexo On which system did you get this? It worked fine for me. |
I wanted to verify that I signed the egg with my own key correctly, so I can be sure that the changes from this PR don’t interfere. There are two ways to do so that I want to share here:
The latter is easier, because it doesn’t require rebuilding the egg. Also because the absolute path is composed from a base path and a file name, it is less trivial to point the constant to your key. Because the public key is in an insights-client folder, I’d assume no other software uses it and thus nothing other than the Insights Client should break. Make sure you backup the original redhattools.pub.gpg. Note that either way of replacing the key makes the Core fail when verifying the official (downloaded and bundled) eggs signed with Red Hat’s real key. |
I’d like to note that you can omit the
In this case, it is BAF1C340B5DEA32A392D8CA8CA7F5625928C2F5D. |
@m-horky It’s a plain instalation of RHEL 9.2 with GPG (2.3.3), libcrypt (1.10.0) and Insights Client (3.1.7) from the installation DVD. See the commands below: if I export the key with $ ls -a /etc/insights-client
…
lrwxrwxrwx. 1 root root 49 Nov 7 00:26 redhattools.pub.gpg -> /home/insights/gnupg/insights-client-test.pub.gpg
…
$ gpg --list-secret-keys
…
sec rsa3072 2023-11-06 [SC]
BAF1C340B5DEA32A392D8CA8CA7F5625928C2F5D
…
$ gpg --armor --export BAF1C340B5DEA32A392D8CA8CA7F56
25928C2F5D > gnupg/insights-client-test.pub.gpg
$ sudo EGG=insights-core/insights.zip BYPASS_GPG=True insights-client --offline
WARNING: GPG verification failed. Not loading egg: insights.zip
WARNING: GPG verification failed. Not loading egg: /etc/insights-client/rpm.egg
$ gpg --export BAF1C340B5DEA32A392D8CA8CA7F56
25928C2F5D > gnupg/insights-client-test.pub.gpg
$ sudo EGG=insights-core/insights.zip BYPASS_GPG=True insights-client --offline
Starting to collect Insights data for localhost.localdomain
… |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spotted some questionable parts, that I think need to be fixed or at least defended. Because of that I chose “Request change”.
What I what to challenge, too, is that this pull request introduces quite more changes that could be reviewed and merged separately:
- the actual
--homedir
argument for gnupg; - the new
EXTRA_GPG_KEY
environment variable; - the new encapsulating crypto module;
- the new tests.
Only the first point actually fixes the original bug. Although I like the other changes, they are more of a refactoring. As I point out in one of my previous comments, it is possible to use an extra key even without adding explicit support for one.
It looks like gnupg as available in Fedora 39 and newer does not validate anymore signatures in case their key is not part of the current keyring (which is what insights-client does). Since the way both insights-core and insights-client validate GPG signatures is being reworked/improved [1][2], add a crude workaround on Fedora 39+. [1] RedHatInsights/insights-core#3930 [2] RedHatInsights#154 Signed-off-by: Pino Toscano <[email protected]>
Wow! I didn’t know that. Thank you! ❤️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking whether I like to have two separate commits for
If there was a separate pull request for the refactoring, which I would strongly prefer, the two commits are separated exaclty as they should be. Here, however, having more separate changes in a single PR, I feel slight temptation to use the commits to group changes that form a mergeable patch.
I learned how to filter changes by commits and it is possible to select a range of commits, too. The commit subjects are clear enough to do the filtering easily, so there is no need to change. Just sharing my thoughts out loud.
insights/client/crypto.py
Outdated
class CommandResult(object): | ||
"""Output of a command. | ||
|
||
Attributes: | ||
ok (bool): Result of an operation. | ||
return_code (int): Return code of the operation. | ||
stdout (str): Standard output of the command. | ||
stderr (str): Standard error of the command. | ||
_command: An optional reference to the object that created the result | ||
""" | ||
def __init__(self, ok, return_code, stdout, stderr): | ||
self.ok = ok | ||
self.return_code = return_code | ||
self.stdout = stdout | ||
self.stderr = stderr | ||
self._command = None | ||
|
||
def __str__(self): | ||
return ( | ||
"<{cls} ok={ok} return_code={code} stdout={out} stderr={err}>" | ||
).format( | ||
cls=self.__class__.__name__, | ||
ok=self.ok, code=self.return_code, | ||
out=self.stdout, err=self.stderr, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a dataclass. Dataclasses were introduced in Python 3.7 and Insights Client needs to support Python 2.6, but there are namedtuples that do exactly what this class implements.
class CommandResult(object): | |
"""Output of a command. | |
Attributes: | |
ok (bool): Result of an operation. | |
return_code (int): Return code of the operation. | |
stdout (str): Standard output of the command. | |
stderr (str): Standard error of the command. | |
_command: An optional reference to the object that created the result | |
""" | |
def __init__(self, ok, return_code, stdout, stderr): | |
self.ok = ok | |
self.return_code = return_code | |
self.stdout = stdout | |
self.stderr = stderr | |
self._command = None | |
def __str__(self): | |
return ( | |
"<{cls} ok={ok} return_code={code} stdout={out} stderr={err}>" | |
).format( | |
cls=self.__class__.__name__, | |
ok=self.ok, code=self.return_code, | |
out=self.stdout, err=self.stderr, | |
) | |
from collections import namedtuple | |
CommandResult = namedtuple("CommandResult", ["ok", "return_code", "stdout", "stderr", "command"]) |
I still doubt, however, that this abstraction is actually needed. Although the structure looks nice and clean, it increases complexity. It may be enough to just work with native Python shell command handling.
Moreover, it looks pretty low-level for something that should live in this specifict crypto module. There are other shell command calls in the codebase that may make use of this structure, if we wanted to keep it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't call this an increased complexity. It just wraps the data, instead of passing them around in an anonymous dictionary.
I've renamed it to GPGCommandResult to make its existence more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GPGCommandResult is definitely better than just plain CommandResult. Crypto ≠ GPG, so the module name is not enough and the GPG prefix is great. 👍🏻
I am not sure about the capitalization: whether to use GPGCommandResult or GpgCommandResult. I researched on the matter and there is no consensus. My personal taste would be Gpg, but lot of big projects use GPG. Let’s find out how acronyms are capitalized in the existing parts of the Client and stick to that.
This addressed only the naming. I have more thoughts on the actual code. I‘ll post them separately.
e54c6d7
to
7c72d31
Compare
|
||
result = crypto.verify_gpg_signed_file( | ||
file=path, signature=sig, | ||
keys=[constants.pub_gpg_path], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion was to remove that infrastructure from the crypto module as well. The difference is the larger amount of changes, increased complexity and support for a feature that is not being used (yet). The existing extra keys code in the crypto module can be trivially turned into a patch that would be part of a different pull request adding the feature as a whole.
keys=[constants.pub_gpg_path], | |
key=constants.pub_gpg_path, |
|
||
result = crypto.verify_gpg_signed_file( | ||
file=path, signature=sig, | ||
keys=[constants.pub_gpg_path], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned above, I was thinking whether it wouldn’t be nice to be consistent to move constants.pub_gpg_path to the function signature as a default value of a new named argument gpg_key. I concluded, however, that it’s not the way I’d prefer: it would increase the amount of changes and introduce a piece of refactoring that doesn’t belong here. Such refactoring would go in a blind direction of adding an argument that is not used anywhere, just paving the path for the future. That is exactly what I objected to in my previous comment in this thread.
self.return_code = return_code | ||
self.stdout = stdout | ||
self.stderr = stderr | ||
self._command = command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to verify: is this attribute use the private-marking underscore, because it is not a result of the command, but just an additional context? Your comment in an older conversation suggests so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's an additional context.
insights/client/crypto.py
Outdated
class CommandResult(object): | ||
"""Output of a command. | ||
|
||
Attributes: | ||
ok (bool): Result of an operation. | ||
return_code (int): Return code of the operation. | ||
stdout (str): Standard output of the command. | ||
stderr (str): Standard error of the command. | ||
_command: An optional reference to the object that created the result | ||
""" | ||
def __init__(self, ok, return_code, stdout, stderr): | ||
self.ok = ok | ||
self.return_code = return_code | ||
self.stdout = stdout | ||
self.stderr = stderr | ||
self._command = None | ||
|
||
def __str__(self): | ||
return ( | ||
"<{cls} ok={ok} return_code={code} stdout={out} stderr={err}>" | ||
).format( | ||
cls=self.__class__.__name__, | ||
ok=self.ok, code=self.return_code, | ||
out=self.stdout, err=self.stderr, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GPGCommandResult is definitely better than just plain CommandResult. Crypto ≠ GPG, so the module name is not enough and the GPG prefix is great. 👍🏻
I am not sure about the capitalization: whether to use GPGCommandResult or GpgCommandResult. I researched on the matter and there is no consensus. My personal taste would be Gpg, but lot of big projects use GPG. Let’s find out how acronyms are capitalized in the existing parts of the Client and stick to that.
This addressed only the naming. I have more thoughts on the actual code. I‘ll post them separately.
* feat: basic integration testing with tmt Introduce a minimal setup for integration tests of insights-client. The tests are written using pytest and an helper plugin for insights-client and other Red Hat client tools [1]. The tests are wrapped as single "integration" test for tmt [2], which makes it possible to run them automatically e.g. in testing-farm. There is a simple test added to show how the setup for the tests works. [1] https://github.com/ptoscano/pytest-client-tools/ [2] https://github.com/teemtee/tmt/ Signed-off-by: Pino Toscano <[email protected]> * feat: run integration tests in testing-farm Extend the packit configuration to trigger tests on testing-farm after the completion of the build jobs. The tests are split for the different distributions supported; this is due to the current limitation of testing-farm in the way additional repositories can be supplied: as the name of a Fedora Copr repository cannot be specified, each distribution needs to get the repository URL for it. Manually specify the RHEL targets/composes due to the limitations in the packit<->testing-farm mapping of RHEL composes. Signed-off-by: Pino Toscano <[email protected]> * fix: workaround newer gnupg & insights-core/insights-client It looks like gnupg as available in Fedora 39 and newer does not validate anymore signatures in case their key is not part of the current keyring (which is what insights-client does). Since the way both insights-core and insights-client validate GPG signatures is being reworked/improved [1][2], add a crude workaround on Fedora 39+. [1] RedHatInsights/insights-core#3930 [2] #154 Signed-off-by: Pino Toscano <[email protected]> --------- Signed-off-by: Pino Toscano <[email protected]>
from tempfile import NamedTemporaryFile | ||
from . import crypto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only symbol imported from crypto is verify_gpg_signed_file, whose name is pretty self-explanatory. It may not be entirely necessary to import the module just for the sake of explicitly stating the call as crypto.verify_gpg_signed_file.
from . import crypto | |
from crypto import verify_gpg_signed_file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this allows you to mock the function more easily. If we imported the function itself, Python would create a new object instead of a reference, forcing us to track down how it is implemented. This way there is only one source for the existence of the function implementation.
Plus including the module name makes it easier for the reader to understand where the function is coming from and any additional context it may have. You don't get that from a bare function.
Overall, that is subjective, we may not find an agreement on this detail.
logger.debug("Status: %s", proc.returncode) | ||
if proc.returncode: | ||
|
||
result = crypto.verify_gpg_signed_file( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only the function was imported, the call would still make perfect sense even without the module name.
result = crypto.verify_gpg_signed_file( | |
result = verify_gpg_signed_file( |
def __init__(self, ok, return_code, stdout, stderr, command): | ||
self.ok = ok | ||
self.return_code = return_code | ||
self.stdout = stdout | ||
self.stderr = stderr | ||
self._command = command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although the constructor is as straightforward as it can be, it is still a lot of code for something as simple as a data structure.
We can’t use a Data Class, because they are not supported in Python 2.6. A namedtuple would, however do the trick on a single line:
GPGCommandResult = namedtuple("GPGCommandResult", ["ok", "return_code", "stdout", "stderr", "_command"])
There is however no way to have a different argument name (command without an underscore) and attribute name (_command with an underscore).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what a namedtuple could look like:
from collections import namedtuple
GPGCommandResult = namedtuple("GPGCommandResult", ["ok", "return_code", "stdout", "stderr", "command"])
result = GPGCommandResult(True, 0, "out", "", "echo out")
You can see that a single line definition (plus one import) do exactly what the entire class does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we'd lose the documentation of the fields. The class
construct allows us to properly describe what each value means, without having to rely on the name. Sure, the names are clear and descriptive, but the docstring provides type information and potentially additional context you just won't get from a named tuple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to add the field documentation using inheritance:
class GPGCommandResult(namedtuple("GPGCommandResult", ["ok", "return_code", "stdout", "stderr", "command"]))
"""Output of a GPGCommand.
Attributes:
ok (bool): Result of an operation.
return_code (int): Return code of the operation.
stdout (str): Standard output of the command.
stderr (str): Standard error of the command.
command (str | None):
An optional reference to the GPGCommand object that created the result
"""
Unfortunately, the __doc__
attribute is not writable in Python 2, so it’s not possible to do
GPGCommandResult.__doc__ = """Output of a GPGCommand.
Attributes:
ok (bool): Result of an operation.
return_code (int): Return code of the operation.
stdout (str): Standard output of the command.
stderr (str): Standard error of the command.
command (str | None):
An optional reference to the GPGCommand object that created the result
It is rather clumsy, but still pretty straightforward and I’d say, Pythonic.
Here’s a nice article on named tuples on Real Python: https://realpython.com/python-namedtuple/
However, the Client codebase doesn’t contain many dataclass-like types and even any argument documentation for functions and methods is scarce. That’s not to say it’s a bad idea to have it (although I am not a big fan of typing), just omitting it here wouldn’t make it any worse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding missing docstrings, unifying and standardizing it format, and documenting function arguments and return values can be done as a separate effort.
def __str__(self): | ||
return ( | ||
"<{cls} ok={ok} return_code={code} stdout={out} stderr={err}>" | ||
).format( | ||
cls=self.__class__.__name__, | ||
ok=self.ok, code=self.return_code, | ||
out=self.stdout, err=self.stderr, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though this is only a data structure, there is still a lot of complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that complex, it's just a format string ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A namedtuple comes with __str__
and __repr__
providing almost exactly the same string.
>>> from collections import namedtuple
>>> GPGCommandResult = namedtuple("GPGCommandResult", ["ok", "return_code", "stdout", "stderr", "command"])
>>> result = GPGCommandResult(True, 0, "out", "", "echo out")
>>> print "Result: %s" % (result,)
Result: GPGCommandResult(True, 0, 'out', '', 'echo out')
Although the format string itself is not that complex, the complexity I was refering to is the fact that it is completely redundant. An 8-line method of a custom class inevitably increases the code complexity, even though is as simple as this one. If you encounter it, you still need to read it and understand what it does and why it is there.
7c72d31
to
fde5c4f
Compare
Today's small update: I've fixed the "type hint" of |
ba13fea
to
0a3b78b
Compare
(Nothing changed, I only rebased it over the latest master) |
def __init__(self, ok, return_code, stdout, stderr, command): | ||
self.ok = ok | ||
self.return_code = return_code | ||
self.stdout = stdout | ||
self.stderr = stderr | ||
self._command = command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding missing docstrings, unifying and standardizing it format, and documenting function arguments and return values can be done as a separate effort.
|
||
|
||
class GPGCommandResult(object): | ||
"""Output of a GPGCommand. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A description like this is not very helpful. It doesn’t seem to add any additional context. It may be still nice to have a docstring for every class, I’m just responding to your comment challenging that namedtuples can’t have (syntactically nice) docstrings.
The nomenclature doesn’t match here. The class name says “result”, but the documentation says “output”. “Output” sounds more like a string, like in “standard output”. Consistent either way is better, “result” is better than “output”.
"""Output of a GPGCommand. | |
"""Result of a GPGCommand. |
GPGCommand is a class; GPGCommandResult is a result (or an output) of its evaluate method. It is, however, its only public method, so it makes some sense. Still, it doesn’t describe what the class represents, only where its instances are constructed. “Output of a GPG command” may fit better, still it’s not clear what an output (or a result) actually is and why it needs a data structure.
"""Output of a GPGCommand. | |
"""Result of a GPG command: its return code, standard and error output and optionally the original command. Returned by GPGCommand.evaluate. |
This is just a non-perfect suggestion. It sounds redundant, but the whole docstring is, for something as simple as a dataclass. It should rather express why the class is there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fair the first line does not provide any more information over the class name. However, it is a good practice to add a one-liner describing the class, and this seems enough. Further information is available in the full docstring.
|
||
return result | ||
|
||
def evaluate(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is the only public method and it runs the command, wouldn’t it make sense to leverage the __call__
method?
class GPGCommand(object):
…
def __call__(self):
"""Run the command.
…
"""
…
gpg = GPGCommand(["--verify", signature, file], keys)
result = gpg()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not something that is common in the code. I'd rather be explicit.
An optional reference to the GPGCommand object that created the result | ||
""" | ||
def __init__(self, ok, return_code, stdout, stderr, command): | ||
self.ok = ok |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this attribute necessary? It is only filled once with return_code == 0
. I see it’s accessed a few times, so it would be redundant to repeat the comparison logic. Also the attribute is nicely semantic. ❤️ Setting it manually, however, feels misplaced.
I suggest either computing the value in the constructor, or adding a @property
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, however the evaluation may not be only done based on return code, some GPG command may require further inspection of the captured output, for example. These may not be the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only thing I was really worried about was the command that didn’t have its arguments properly escaped. This is now fixed and every other comments I have only target the code style. I give my ✅ then, so we can merge.
As could be seen from my comments, I find the code too complex in regard to how simple fix it delivers. A minimal, almost one-line, patch could do the trick. And I believe anything else is a refactoring or tech debt crushing that is a separate effort.
Yes, let's wait for QE verification before merging it. I have added the label that we used when the PR are in that status. |
37def15
to
625600c
Compare
This PR has been preverified and is ready to be merged, @xiangce. |
* feat(pgp): Add crypto.py with PGP signature verification * Card ID: CCT-131 * Card ID: RHEL-2480 * Card ID: RHEL-2482 This patch adds a self-contained and isolated GPG verification environment. It runs GPG in an isolated environment where only selected PGP keys are allowed to check the file signature matches its file. GPG creates a directory `$HOME/.gnupg/` every time it performs some operation. When run under root, but not manually (e.g. via subscription-manager Cockpit plugin), it tries to create and write to this directory, which pollutes user directories and/or causes SELinux denials. This patch utilizes the `--homedir` argument GPG supports in order to move the GPG home directory to a temporary directory for the time of the transaction. After the GPG action is performed, the directory is cleaned up. Signed-off-by: mhorky <[email protected]> * feat(pgp): Use crypto.py during Egg and Collection verification * Card ID: CCT-131 * Card ID: RHEL-2480 * Card ID: RHEL-2482 Signed-off-by: mhorky <[email protected]> * chore: Add .gitleaks.toml This configuration file ensures the dummy PGP public/private key pair is not flagged by security tools as a false positive. Signed-off-by: mhorky <[email protected]> --------- Signed-off-by: mhorky <[email protected]> (cherry picked from commit 69fbf77)
Apparently, I don’t even have the necessary rights to merge. I remember having them. |
…HatInsights#158) * feat: basic integration testing with tmt Introduce a minimal setup for integration tests of insights-client. The tests are written using pytest and an helper plugin for insights-client and other Red Hat client tools [1]. The tests are wrapped as single "integration" test for tmt [2], which makes it possible to run them automatically e.g. in testing-farm. There is a simple test added to show how the setup for the tests works. [1] https://github.com/ptoscano/pytest-client-tools/ [2] https://github.com/teemtee/tmt/ Signed-off-by: Pino Toscano <[email protected]> * feat: run integration tests in testing-farm Extend the packit configuration to trigger tests on testing-farm after the completion of the build jobs. The tests are split for the different distributions supported; this is due to the current limitation of testing-farm in the way additional repositories can be supplied: as the name of a Fedora Copr repository cannot be specified, each distribution needs to get the repository URL for it. Manually specify the RHEL targets/composes due to the limitations in the packit<->testing-farm mapping of RHEL composes. Signed-off-by: Pino Toscano <[email protected]> * fix: workaround newer gnupg & insights-core/insights-client It looks like gnupg as available in Fedora 39 and newer does not validate anymore signatures in case their key is not part of the current keyring (which is what insights-client does). Since the way both insights-core and insights-client validate GPG signatures is being reworked/improved [1][2], add a crude workaround on Fedora 39+. [1] RedHatInsights/insights-core#3930 [2] RedHatInsights#154 Signed-off-by: Pino Toscano <[email protected]> --------- Signed-off-by: Pino Toscano <[email protected]> Signed-off-by: Martin Grünwald <[email protected]>
All Pull Requests:
Check all that apply:
Complete Description of Additions/Changes:
GPG creates a directory
$HOME/.gnupg/
every time it performs some operation. When run under root, but not manually (e.g. via subscription-manager Cockpit plugin), it tries to create and write to this directory, which causes SELinux denials.This patch utilizes the
--homedir
argument GPG supports in order to move the home directory to a temporary directory for the time of the transaction. After the GPG action is performed, the directory is cleaned up.You can verify this patch by performing the following actions:
1/ Create your own GPG key pair
2/ Ensure you have created the egg zip file
3/ Sign the egg
4/ Replace the official GPG key with you own.
5/ Run insights-client without
--no-gpg
orBYPASS_GPG=True
.Support for additional GPG keys was dropped from this PR. The
crypto.py
still supports it, this way it will be easier to add possibility to load multiple GPG keys later. See #3852 for example use case.