fn run()

in tools/pubsys-setup/src/main.rs [74:174]


fn run() -> Result<()> {
    // Parse and store the args passed to the program
    let args = Args::from_args();

    // SimpleLogger will send errors to stderr and anything less to stdout.
    SimpleLogger::init(args.log_level, LogConfig::default()).context(error::Logger)?;

    // Make /roles and /keys directories, if they don't exist, so we can write generated files.
    let role_dir = args.root_role_path.parent().context(error::Path {
        path: &args.root_role_path,
        thing: "root role",
    })?;
    let key_dir = args.default_key_path.parent().context(error::Path {
        path: &args.default_key_path,
        thing: "key",
    })?;
    fs::create_dir_all(role_dir).context(error::Mkdir { path: role_dir })?;
    fs::create_dir_all(key_dir).context(error::Mkdir { path: key_dir })?;

    // Main branching logic for deciding whether to create role/key, use what we have, or error.
    match find_root_role_and_key(&args)? {
        (Some(_root_role_path), Some(_key_url)) => Ok(()),
        (Some(_root_role_path), None) => {
            ensure!(
                args.allow_missing_key,
                error::MissingKey { repo: args.repo }
            );
            Ok(())
        }
        // User is missing something, so we generate at least a root.json and maybe a key.
        (None, maybe_key_url) => {
            if maybe_key_url.is_some() {
                info!("Didn't find root role in Infra.toml, generating...");
            } else {
                info!("Didn't find root role or signing key in Infra.toml, generating...");
            }

            let temp_root_role =
                NamedTempFile::new_in(&role_dir).context(error::TempFileCreate {
                    purpose: "root role",
                })?;
            let temp_root_role_path = temp_root_role.path().display();

            // Make tuftool calls to create an initial root.json with basic parameters.
            tuftool!("root init '{}'", temp_root_role_path);

            tuftool!("root expire '{}' 'in 52 weeks'", temp_root_role_path);

            tuftool!("root set-threshold '{}' root 1", temp_root_role_path);
            tuftool!("root set-threshold '{}' snapshot 1", temp_root_role_path);
            tuftool!("root set-threshold '{}' targets 1", temp_root_role_path);
            tuftool!("root set-threshold '{}' timestamp 1", temp_root_role_path);

            let key_url = if let Some(key_url) = maybe_key_url {
                // If the user has a key, add it to each role.
                tuftool!("root add-key '{}' '{}' --role root --role snapshot --role targets --role timestamp",
                         temp_root_role_path, key_url);
                key_url
            } else {
                // If the user has no key, build one and add it to each role.
                tuftool!("root gen-rsa-key '{}' '{}' --role root --role snapshot --role targets --role timestamp",
                         temp_root_role_path, args.default_key_path.display());
                warn!(
                    "Created a key at {} - note that for production use, you should \
                     use a key stored in a trusted service like KMS or SSM",
                    args.default_key_path.display()
                );

                Url::from_file_path(&args.default_key_path)
                    .ok()
                    .context(error::FileToUrl {
                        path: args.default_key_path,
                    })?
            };

            // Sign the role with the given key.
            tuftool!("root sign '{}' -k '{}'", temp_root_role_path, key_url);

            temp_root_role
                .persist_noclobber(&args.root_role_path)
                .context(error::TempFilePersist {
                    path: &args.root_role_path,
                })?;

            warn!(
                "Created a root role at {} - note that for production use, you should create \
                    a role with a shorter expiration and higher thresholds",
                args.root_role_path.display()
            );

            // Root role files don't need to be secret.
            fs::set_permissions(&args.root_role_path, fs::Permissions::from_mode(0o644)).context(
                error::SetMode {
                    path: &args.root_role_path,
                },
            )?;

            Ok(())
        }
    }
}