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

tuftool: Add clone subcommand #404

Merged
merged 3 commits into from
Aug 18, 2021
Merged

Conversation

zmrow
Copy link
Contributor

@zmrow zmrow commented Aug 13, 2021

Issue #, if available:
Fixes #401

Description of changes:
This PR does a small amount of refactoring before the main event, a new clone subcommand! This subcommand gives the user the opportunity to clone a repository and it's metadata, including all, none or some of the targets. It can be considered a bit more "low-level" than tuftool download as the files end up on disk identically named as they are in the TUF repository, including the SHA256 prefix. tuftool download also does not give the user the opportunity to download metadata.

Reading through by commit is probably easiest as they're fairly small.

    tuftool: Add `download_root` module
    
    This change adds a `download_root` module, which abstracts the logic of
    downloading `root.json` out of `download` (the subcommand).  It also
    makes the HTTP request a bit more robust by handling the initial request
    error as well as a bad response.  Additionally, it avoids creating the
    file until after the request has succeeded to avoid creating cruft on
    the user's system.
    tuftool: use `download_root` module in `download`
    
    This change updates the `download` module/subcommand to make use of the
    previously added `download_root` function.
    
    It also defines a default of "1" for the `root_version` argument.
    Previously, we effectively had this default in code by using
    `1.root.json` in the event the argument wasn't passed.  It also has the
    nice side effect of not needing to deal with an `Option` for this
    argument
    tuftool: Add `clone` subcommand
    
    This adds a `clone` subcommand to `tuftool`, allowing a user to download
    a fully functioning TUF repository.  A user has the option to download a
    full repository, a subset of the targets, or just metadata

Testing:

  • All new/old unit tests pass
  • Manual testing:
    • Download just a repository's metadata (with root.json and with the flag --allow-root-download)
$ cargo run --bin tuftool clone --metadata-only --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --allow-root-download --metadata-dir ./foo/metadata

# also ran with a downloaded root.json
$ curl -O "https://cache.bottlerocket.aws/root.json
$ cargo run --bin tuftool clone --metadata-only --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --root ./root.json --metadata-dir ./foo/metadata

 $ tree ./foo/
./foo/
└── metadata
    ├── 1628878016.snapshot.json
    ├── 1628878016.targets.json
    ├── 1.root.json
    ├── 2.root.json
    └── timestamp.json


  • Download an entire repository to ./foo (with root.json and with the flag --allow-root-download)
$ cargo run --bin tuftool clone --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --targets-url "https://updates.bottlerocket.aws/targets/" --allow-root-download --metadata-dir ./foo/metadata --targets-dir ./foo/targets

# also ran with a downloaded root.json
$ curl -O "https://cache.bottlerocket.aws/root.json
$ cargo run --bin tuftool clone --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --targets-url "https://updates.bottlerocket.aws/targets/" --root ./root.json --metadata-dir ./foo/metadata --targets-dir ./foo/targets

$ tree ./foo
 ./foo/                                                                                                                                            
├── metadata                                                                                                                                      
│   ├── 1628878016.snapshot.json                                                                                                                  
│   ├── 1628878016.targets.json                                                                                                                   
│   ├── 1.root.json                                                                                                                               
│   ├── 2.root.json                                                                                                                               
│   └── timestamp.json                                                                                                                            
└── targets                                                                                                                                       
    ├── 0c8485912fd928a185f32a74705f8e5efa692177375c27eac7ee5c11219d259e.migrate_v1.1.0_kubelet-registry-qps-registry-burst.lz4
    ├── 148f1c10a790313c19e4967c0136c58cf433c20a41676bffb5f3c976a1170d4a.bottlerocket-aws-k8s-1.20-x86_64-1.1.1-28c4e013-root.verity.lz4
...
  • Download a subset of targets (just manifest.json) (with root.json and with the flag --allow-root-download)
$ cargo run --bin tuftool clone --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --targets-url "https://updates.bottlerocket.aws/targets/" --allow-root-download --metadata-dir ./foo/metadata --targets-dir ./foo/targets --target-names manifest.json

# also ran with a downloaded root.json
$ curl -O "https://cache.bottlerocket.aws/root.json
$ cargo run --bin tuftool clone --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --targets-url "https://updates.bottlerocket.aws/targets/" --root ./root.json --metadata-dir ./foo/metadata --targets-dir ./foo/targets --target-names manifest.json

$ tree ./foo
./foo/
├── metadata
│   ├── 1628878016.snapshot.json
│   ├── 1628878016.targets.json
│   ├── 1.root.json
│   ├── 2.root.json
│   └── timestamp.json
└── targets
    └── aabc9db0c44ff6811aaf0f847c3bba6830e16bb0ecb6d2ec5eef837f68440cd2.manifest.json
  • Ensure that targets arguments collide with the --metadata-only flag
$ cargo run --bin tuftool clone --metadata-only --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --allow-root-download --metadata-dir ./foo/metadata --target-names foo
...
error: The argument '--metadata-only' cannot be used with '--target-names <target-names>...'

USAGE:
    tuftool clone --allow-root-download --metadata-url <metadata-base-url> --metadata-dir <metadata-dir> --metadata-only --root-version <root-version> --target-names <target-names>... --targets-url <targets-base-url> --targets-dir <targets-dir>
----------------------------------
$ cargo run --bin tuftool clone --metadata-only --metadata-url "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.20/x86_64/" --allow-root-download --metadata-dir ./foo/metadata --targets-dir foo
...
error: The argument '--targets-dir <targets-dir>' cannot be used with '--metadata-only'

USAGE:
    tuftool clone --allow-root-download --metadata-url <metadata-base-url> --metadata-dir <metadata-dir> --metadata-only --root-version <root-version> --targets-url <targets-base-url> --targets-dir <targets-dir>

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@zmrow
Copy link
Contributor Author

zmrow commented Aug 16, 2021

^ Fix the clippy complaint - I didn't see it when I ran the make build command locally...

Copy link
Contributor

@webern webern left a comment

Choose a reason for hiding this comment

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

Nice testing.

tuftool/src/clone.rs Outdated Show resolved Hide resolved
tuftool/src/error.rs Outdated Show resolved Hide resolved
tuftool/src/download_root.rs Show resolved Hide resolved
tuftool/src/main.rs Outdated Show resolved Hide resolved
tuftool/tests/clone_command.rs Outdated Show resolved Hide resolved
fn clone_base_command<'a>(cmd: &'a mut Command, repo_paths: &RepoPaths) -> &'a mut Command {
cmd.args(&[
"clone",
"--root",
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice tests! Should we have one for --allow-root-download as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point - I'll add one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:( Bad news everyone! We use reqwest to get the root.json, and reqwest doesn't support file:/// URLs.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think what we normally do is add a branch, where if url.scheme() is file, we just std::fs::copy it instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opened a new issue to track this: #406

tuftool/src/clone.rs Outdated Show resolved Hide resolved
tuftool/src/clone.rs Show resolved Hide resolved
tuftool/src/clone.rs Outdated Show resolved Hide resolved
tuftool/src/clone.rs Outdated Show resolved Hide resolved
tuftool/src/clone.rs Outdated Show resolved Hide resolved
tuftool/src/clone.rs Outdated Show resolved Hide resolved
This change adds a `download_root` module, which abstracts the logic of
downloading `root.json` out of `download` (the subcommand).  It also
makes the HTTP request a bit more robust by handling the initial request
error as well as a bad response.  Additionally, it avoids creating the
file until after the request has succeeded to avoid creating cruft on
the user's system.
This change updates the `download` module/subcommand to make use of the
previously added `download_root` function.

It also defines a default of "1" for the `root_version` argument.
Previously, we effectively had this default in code by using
`1.root.json` in the event the argument wasn't passed.  It also has the
nice side effect of not needing to deal with an `Option` for this
argument.
@zmrow
Copy link
Contributor Author

zmrow commented Aug 17, 2021

^ addressed all the comments

This adds a `clone` subcommand to `tuftool`, allowing a user to download
a fully functioning TUF repository.  A user has the option to download a
full repository, a subset of the targets, or just metadata.
@zmrow
Copy link
Contributor Author

zmrow commented Aug 17, 2021

^ removed a dangling println!()

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.

tuftool: provide an option to download metadata files
3 participants