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

HTTP selfupdate #184

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

Conversation

neverpanic
Copy link
Member

@neverpanic neverpanic commented Jun 6, 2020

Note: A few things still need to happen before this can be merged:

  • Generate and upload signatures for the current release to GitHub and distfiles
  • Possibly adjust CI to generate the new signature format
  • Adjust the releasing guide to cover the new steps required
  • Add a changelog entry
  • Test signify compilation on older macOS (help wanted!)
  • Commit _resources/port1.0/fetch/base_mirror_sites.list

I'm uploading this so you can have a look and see if you notice any issues with my approach. Note that this should be reviewed commit-by-commit – otherwise you'll get a huge patchset that's not simple to review.

Description

Refactor the selfupdate package into smaller functions and switch to a control flow of:

  1. checking for newer versions by downloading a single URL
  2. downloading the new version using HTTP when available
  3. verifying the signature using EdDSA with ed25519 elliptic curve crypto with the help of OpenBSD's signify(1)
  4. automatically re-executing selfupdate for the sync step with the new base version when base was updated

This allows us to automatically fall back to other mirrors should our main mirror not be available. We did not have this functionality available for our previous rsync-based mechanism.

Additionally, the use of our standard curl wrapper enables displaying a progress bar for the download and automatically uses any proxies that might already be configured for HTTP.

Since we currently do not have a standard mechanism to sign the source code tarballs uploaded to our distfiles server and github releases page (we only sign the tarball pushed to rsync), I've taken the liberty to introduce a new modern signature scheme for this channel – if we have to touch this anyway, we might as well use modern tools and algorithms.

Previously, we would instruct users to re-run selfupdate manually when MacPorts base was updated, because Portfiles might already require the new base version to index correctly. This step has now been automated using an idea that lives on the migration branch, where the port.tcl client automatically re-executes itself in this situation.

This patch also adds support for a list of mirrors specified in the ports tree at _resources/port1.0/fetch/base_mirror_sites.list, so that we can add and remove mirrors without releasing a new version of MacPorts base. Base itself comes preconfigured with the GitHub releases URL if this list is not available.

See: https://trac.macports.org/ticket/60608

We did define those, but in the places where they could have been used,
the @variable@ syntax was used instead, so we can just drop those.
signify(1) is a tool originally developed for OpenBSD that uses modern
EdDSA signatures on the ed25519 elliptic curve. Bundling this tool gives
us a good way forward away from our single RSA 4096 public key that has
now been in use since 2011 for all packages, all base updates and all
ports trees.

Shipping signify allows us to use (a) modern cryptography, (b) avoid
using the same key for everything and (c) eventually phase out the
RSA-RIPEMD160 signatures.

The vendor/signify-osx directory is a clone of
https://github.com/jpouellet/signify-osx/, udpated with the latest
OpenBSD upstream signify source code from CVS using the 'make up' target
of the signify-osx Makefile.
Add a new public key for use with signify(1) to verify downloaded
MacPorts base relases. Adjust the Makefile to install this key in
$prefix/share/macports/keys/base, so that we have a designated space for
additional keys (enabling future key roll-over) and separate keys, for
example for a ports tree signature.
We should not hardcode the location of the keys directory or the signify
binary in any source code files, so add a autoconf variable that can be
used instead.
This list of options was hard to read, hard to maintain, hard to keep
sorted, and hard to diff in its current form.

Move every option name to a line of its own and sort to simplify this in
the future.
Currently, all of our configuration file options hold a single value
only, and while we could space-separate them, this quickly gets messy
due to the lack of line continuation support.

Introduce a new type of configuration option than can be specified
multiple times in one configuration file and appends the new value to
a list, instead of overwriting the old value.

Note that this append functionality happens per configuration file, to
enable overwriting the defaults specified in one configuration file in
the next one, rather than only appending.
To support updating MacPorts base via HTTP and avoiding the rsync
download (which we currently do not distribute over multiple mirrors
automatically), introduce two new multi-value configuration options
release_version_url and release_url, where the former is a list of URLs
to check for the current MacPorts release version, and the latter is
a list of template URLs where to download the source code for a given
MacPorts version.

See: https://trac.macports.org/ticket/60608
Refactor the selfupdate package into smaller functions and switch to
a control flow of:

 1. checking for newer versions by downloading a single URL
 2. downloading the new version using HTTP when available
 3. verifying the signature using EdDSA with ed25519 elliptic curve
    crypto with the help of OpenBSD's signify(1)
 4. automatically re-executing selfupdate for the sync step with the new
    base version when base was updated

This allows us to automatically fall back to other mirrors should our
main mirror not be available. We did not have this functionality
available for our previous rsync-based mechanism.

Additionally, the use of our standard curl wrapper enables displaying
a progress bar for the download and automatically uses any proxies that
might already be configured for HTTP.

Since we currently do not have a standard mechanism to sign the source
code tarballs uploaded to our distfiles server and github releases page
(we only sign the tarball pushed to rsync), I've taken the liberty to
introduce a new modern signature scheme for this channel – if we have to
touch this anyway, we might as well use modern tools and algorithms.

Previously, we would instruct users to re-run selfupdate manually when
MacPorts base was updated, because Portfiles might already require the
new base version to index correctly. This step has now been automated
using an idea that lives on the migration branch, where the port.tcl
client automatically re-executes itself in this situation.

This patch also adds support for a list of mirrors specified in the
ports tree at _resources/port1.0/fetch/base_mirror_sites.list, so that
we can add and remove mirrors without releasing a new version of
MacPorts base. Base itself comes preconfigured with the GitHub releases
URL if this list is not available.

See: https://trac.macports.org/ticket/60608
Those options were used for rsync-based selfupdate, but this is no
longer required since MacPorts now uses HTTP to update itself.

See: https://trac.macports.org/ticket/60608
Copy link
Member

@jmroot jmroot left a comment

Choose a reason for hiding this comment

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

This all looks pretty reasonable for the most part. Two issues are:

  • The scope of this PR is quite large, covering multiple features: switching selfupdate from rsync to HTTPS, adding signify and using it for signature verification, and re-executing after updating base to continue with syncing the ports tree. Some of it can't be merged yet. It might be better to split it up so some can be merged sooner?
  • The new selfupdate method is going to be very difficult to adequately test without doing an actual release. I think it would be safer to start by adding the HTTPS method but use rsync by default for the first release, so developers and interested users can try out HTTPS selfupdate under real world conditions, but everyone else doesn't break if there are bugs. Then for the next release, make HTTPS the default, then if all goes well, remove rsync in the next release.

set macports::$option [string trim $val]
global macports::$option
} elseif {$option in $bootstrap_multivalue_options} {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not terribly happy about having two different behaviours for options in the config file. Is it just to avoid long lines?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. Do you have a better suggestion on how to achieve this?

@@ -0,0 +1 @@
D
Copy link
Member

Choose a reason for hiding this comment

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

Might want to add the CVS stuff to .gitignore.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, yes.

Copy link
Member Author

@neverpanic neverpanic left a comment

Choose a reason for hiding this comment

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

We could merge everything up to and including "macports1.0: Sort and format list of options", and merge the rest later?

I like the idea of having this available selectively first, but I fear it would not really give us good test coverage unless we make it the default and fall back to rsync if it fails. I can take a look at implementing that, if you want?

set macports::$option [string trim $val]
global macports::$option
} elseif {$option in $bootstrap_multivalue_options} {
Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. Do you have a better suggestion on how to achieve this?

@@ -0,0 +1 @@
D
Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, yes.

@jmroot
Copy link
Member

jmroot commented Oct 22, 2020

We could merge everything up to and including "macports1.0: Sort and format list of options", and merge the rest later?

Sounds good. Remember to add the .gitignore changes first.

I like the idea of having this available selectively first, but I fear it would not really give us good test coverage unless we make it the default and fall back to rsync if it fails. I can take a look at implementing that, if you want?

That would be even better I guess. Probably still have a command-line option to make it use rsync, just in case.

@herbygillot
Copy link
Member

Can we revisit this?

Would it be possible to test base + bundled signify using the buildbots?

@neverpanic
Copy link
Member Author

This needs spitting into smaller parts, and some refactoring to keep the rsync selfupdate as fallback. I haven't found the time to implement that yet, unfortunately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
3 participants