Skip to content
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

Add support for CLI update command #311

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

aliask
Copy link

@aliask aliask commented Feb 12, 2023

As requested by Phiz in #268, I have added support for a rocketpool update cli command which will:

  • check what the latest version is via the Github API
  • compare with local version, and download it if it's newer
  • verify the PGP signature of the downloaded binary
  • replace existing client if all the above goes well

There are some assumptions regarding the filenames in the release but these appear to be reasonably widely referenced already.

Optional flags included for this command:

  • --force will attempt to update, even if Github version is same/older
  • --skip-signature-verification will prevent any checks against the PGP signature
  • --yes will automatically confirm the update

Copy link
Contributor

@angaz angaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an awesome feature! I hope it gets merged soon.

Comment on lines 169 to 176
err = os.Remove(ex)
if err != nil {
return fmt.Errorf("error while removing old rocketpool binary: %w", err)
}
err = os.Rename(fileName, ex)
if err != nil {
return fmt.Errorf("error while writing new rocketpool binary: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.Rename should replace the original file according to the docs: https://pkg.go.dev/os#Rename

So the os.Remove isn't needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @SN9NV . I based this behaviour on this Stackoverflow question, but I just tested and it does appear to work without the unlink first.

Copy link
Contributor

@angaz angaz Feb 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When replacing the binary, the key is the the inode is different to the original executable. We have a new file created during the download process. So this is pretty safe. If we were using something else like truncate/copy, then we might still have the original inode, which can be problematic for the OS to deal with.

func checkSignature(signatureUrl string, pubkeyUrl string, verification_target *os.File) error {
pubkeyResponse, err := http.Get(pubkeyUrl)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some error context.


signatureResponse, err := http.Get(signatureUrl)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some error context.

client := getHttpClientWithTimeout()
resp, err := client.Get(GithubAPIGetLatest)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some error context.

}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some error context.

}

// Update the Rocket Pool CLI
func updateCLI(c *cli.Context) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a few main sections to this function. I think it would be easier to see the main steps if they are split into their own functions. It would also help add context to the errors. I see the same error message repeated/similar to another one. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that's a fair comment. I've split out the initial version check, and the download/verify sections into their own functions, and I think updateCLI is pretty readable now :)

@angaz
Copy link
Contributor

angaz commented Feb 23, 2023

Seems great. I tested the various flags and it seems to be working as expected.

There's just these two issues from golangci-lint:

update/update.go:135:14: Error return value of `output.Seek` is not checked (errcheck)
                output.Seek(0, io.SeekStart)
                           ^
update/update.go:16:2: SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes. New applications should consider a more focused, modern alternative to OpenPGP for their specific task. If you are required to interoperate with OpenPGP systems and need a maintained package, consider a community fork. See https://golang.org/issue/44226. (staticcheck)
        "golang.org/x/crypto/openpgp"
        ^

Not critical things, but I think probably good to have a look at.

@aliask
Copy link
Author

aliask commented Feb 24, 2023

I've added a check for the Seek(), but the openpgp deprecation is a tricky one.
I couldn't find any third party libraries offering a drop-in functionality, but I'm not sure it's really that critical:

  • Despite being officially deprecated, it appears to still be being updated - the last release was only a couple of weeks ago
  • Other major projects are still depending on it, including geth

@angaz
Copy link
Contributor

angaz commented Feb 24, 2023

I've added a check for the Seek(), but the openpgp deprecation is a tricky one. I couldn't find any third party libraries offering a drop-in functionality, but I'm not sure it's really that critical:

* Despite being _officially_ deprecated, it appears to still be being updated - the last release was only a couple of weeks ago

* Other major projects are still depending on it, including [geth](https://github.com/ethereum/go-ethereum/blob/master/.golangci.yml#L53)

Looks good. Yeah I think it will be fine and we can replace the library if there's any CVEs. I'm pretty sure it will be perfectly fine.

@angaz
Copy link
Contributor

angaz commented Feb 24, 2023

I rate it's good to go. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants