diff --git a/src/3rd_party_repos.c b/src/3rd_party_repos.c index cdd70d95..fab290d5 100644 --- a/src/3rd_party_repos.c +++ b/src/3rd_party_repos.c @@ -27,14 +27,6 @@ #ifdef THIRDPARTY -#define SCRIPT_TEMPLATE "#!/bin/bash\n\n" \ - "export PATH=%s:$PATH\n" \ - "export LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH\n" \ - "export XDG_DATA_DIRS=%s:$XDG_DATA_DIRS\n" \ - "export XDG_CONF_DIRS=%s:$XDG_CONF_DIRS\n" \ - "\n" \ - "%s \"$@\"\n" - char *third_party_get_bin_dir(void) { return sys_path_join("%s/%s", globals_bkp.path_prefix, SWUPD_3RD_PARTY_BIN_DIR); @@ -294,7 +286,7 @@ enum swupd_code third_party_set_repo(struct repo *repo, bool sigcheck) /* set up swupd to use the certificate from the 3rd-party repository, * unless the user is specifying a path for the certificate to use */ - string_or_die(&repo_cert_path, "%s%s/%s%s", globals_bkp.path_prefix, SWUPD_3RD_PARTY_BUNDLES_DIR, repo->name, CERT_PATH); + repo_cert_path = sys_path_join("%s/%s/%s/%s", globals_bkp.path_prefix, SWUPD_3RD_PARTY_BUNDLES_DIR, repo->name, CERT_PATH); if (!globals.user_defined_cert_path) { /* the user did not specify a cert, use repo's default */ set_cert_path(repo_cert_path); @@ -615,9 +607,33 @@ enum swupd_code third_party_remove_binary(struct file *file) return ret_code; } +static enum swupd_code third_party_bin_directory_exist(void) +{ + enum swupd_code ret_code = SWUPD_OK; + char *bin_directory = NULL; + + bin_directory = third_party_get_bin_dir(); + + /* if the SWUPD_3RD_PARTY_BIN_DIR does not exist, attempt to create it */ + if (mkdir_p(bin_directory)) { + error("The directory %s for 3rd-party content failed to be created\n", bin_directory); + ret_code = SWUPD_COULDNT_CREATE_DIR; + goto exit; + } + + if (!sys_filelink_is_dir(bin_directory)) { + error("The path %s for 3rd-party content exists but is not a directory\n", bin_directory); + ret_code = SWUPD_COULDNT_CREATE_DIR; + } + +exit: + free_and_clear_pointer(&bin_directory); + return ret_code; +} + enum swupd_code third_party_create_wrapper_script(struct file *file) { - enum swupd_code ret_code = 0; + enum swupd_code ret_code = SWUPD_OK; int fd; FILE *fp = NULL; char *bin_directory = NULL; @@ -652,15 +668,9 @@ enum swupd_code third_party_create_wrapper_script(struct file *file) goto close_and_exit; } - /* if the SWUPD_3RD_PARTY_BIN_DIR does not exist, attempt to create it */ - if (mkdir_p(bin_directory)) { - ret_code = SWUPD_COULDNT_CREATE_DIR; - goto close_and_exit; - } - - if (!sys_filelink_is_dir(bin_directory)) { - error("The path %s for 3rd-party content exists but is not a directory\n", bin_directory); - ret_code = SWUPD_COULDNT_CREATE_DIR; + /* make sure the SWUPD_3RD_PARTY_BIN_DIR exist */ + ret_code = third_party_bin_directory_exist(); + if (ret_code) { goto close_and_exit; } diff --git a/src/3rd_party_repos.h b/src/3rd_party_repos.h index f110de1d..ec639450 100644 --- a/src/3rd_party_repos.h +++ b/src/3rd_party_repos.h @@ -14,6 +14,15 @@ extern "C" { #ifdef THIRDPARTY +/** Template used to generate wrapper scripts for 3rd-party binaries */ +#define SCRIPT_TEMPLATE "#!/bin/bash\n\n" \ + "export PATH=%s:$PATH\n" \ + "export LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH\n" \ + "export XDG_DATA_DIRS=%s:$XDG_DATA_DIRS\n" \ + "export XDG_CONF_DIRS=%s:$XDG_CONF_DIRS\n" \ + "\n" \ + "%s \"$@\"\n" + /** @brief Name of the directory where 3rd-party content and state should be stored */ #define SWUPD_3RD_PARTY_DIRNAME "3rd-party" @@ -26,6 +35,9 @@ extern "C" { /** @brief Full path to the directory where 3rd-party binaries are going to be installed */ #define SWUPD_3RD_PARTY_BIN_DIR SWUPD_3RD_PARTY_DIR "/bin" +/** @brief Name of the file that holds the copy of the current script template */ +#define SWUPD_3RD_PARTY_TEMPLATE_FILE "script.template" + /** @brief Store information of a repository. */ struct repo { /** @brief repo's name */ diff --git a/src/3rd_party_update.c b/src/3rd_party_update.c index 1597747d..b93c79f9 100644 --- a/src/3rd_party_update.c +++ b/src/3rd_party_update.c @@ -195,6 +195,43 @@ static enum swupd_code validate_file_permissions(struct list *files_to_be_update return ret_code; } +static enum swupd_code regenerate_all_wrapper_scripts(UNUSED_PARAM char *unused) +{ + enum swupd_code ret_code; + struct list *current_subs = NULL; + struct manifest *current_mom = NULL; + int version; + + /* get currently installed 3rd-party bundles */ + read_subscriptions(¤t_subs); + + /* load the MoM */ + version = get_current_version(globals.path_prefix); + current_mom = load_mom(version, NULL); + if (!current_mom) { + ret_code = SWUPD_COULDNT_LOAD_MOM; + goto exit; + } + + /* get a list of all 3rd-party files installed */ + current_mom->submanifests = recurse_manifest(current_mom, current_subs, NULL, false, NULL); + if (!current_mom->submanifests) { + ret_code = SWUPD_RECURSE_MANIFEST; + goto exit; + } + current_mom->files = consolidate_files_from_bundles(current_mom->submanifests); + + ret_code = third_party_process_files(current_mom->files, "Regenerating scripts...\n", "update_binaries", third_party_update_wrapper_script); + if (ret_code == SWUPD_OK) { + info("Scripts regenerated successfully\n"); + } + +exit: + manifest_free(current_mom); + free_subscriptions(¤t_subs); + return ret_code; +} + static enum swupd_code update_exported_binaries(struct list *updated_files) { return third_party_process_files(updated_files, "\nUpdating 3rd-party bundle binaries...\n", "update_binaries", third_party_update_wrapper_script); @@ -217,7 +254,11 @@ static enum swupd_code update_repos(UNUSED_PARAM char *unused) enum swupd_code third_party_update_main(int argc, char **argv) { enum swupd_code ret_code = SWUPD_OK; + char *template_file = NULL; + char *template = NULL; int steps_in_update; + int ret; + size_t template_len; if (!parse_options(argc, argv)) { print("\n"); @@ -260,7 +301,32 @@ enum swupd_code third_party_update_main(int argc, char **argv) /* update 3rd-party bundles */ ret_code = third_party_run_operation_multirepo(cmdline_option_repo, update_repos, SWUPD_NO, "update", steps_in_update); + if (ret_code) { + goto exit; + } + /* read the current template copy */ + template_file = sys_path_join("%s/%s/%s", globals_bkp.path_prefix, SWUPD_3RD_PARTY_DIR, SWUPD_3RD_PARTY_TEMPLATE_FILE); + template = sys_mmap_file(template_file, &template_len); + + if (!template || strncmp(template, SCRIPT_TEMPLATE, template_len) != 0) { + /* there is no template file, or the template changed, + * all scripts need to be recreated */ + info("The scripts that export binaries from 3rd-party repositories need to be regenerated\n\n"); + ret_code = third_party_run_operation_multirepo(NULL, regenerate_all_wrapper_scripts, SWUPD_OK, "regenerate_scripts", steps_in_update); + + /* update the template */ + + ret = sys_write_file(template_file, SCRIPT_TEMPLATE, string_len(SCRIPT_TEMPLATE)); + if (ret < 0) { + error("The wrapper scripts template file %s failed to be updated\n", template_file); + ret_code = SWUPD_COULDNT_WRITE_FILE; + } + } + +exit: + free_and_clear_pointer(&template_file); + sys_mmap_free(template, template_len); swupd_deinit(); progress_finish_steps(ret_code); diff --git a/src/lib/sys.c b/src/lib/sys.c index a78f09c3..6410bcb9 100644 --- a/src/lib/sys.c +++ b/src/lib/sys.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -613,3 +614,61 @@ exit: closedir(dir); return ret; } + +int sys_write_file(char *file, void *content, size_t content_size) +{ + FILE *fp = NULL; + int ret = 0; + + fp = fopen(file, "w"); + if (!fp) { + return -errno; + } + + if (fwrite(content, content_size, 1, fp) <= 0) { + ret = -1; + error("There was an error writing to file %s\n", file); + } + + fclose(fp); + return ret; +} + +void *sys_mmap_file(const char *file, size_t *file_length) +{ + struct stat st; + int fd = -1; + void *buffer = NULL; + + fd = open(file, O_RDONLY); + if (fd == -1) { + debug("Failed to open %s: %s", file, strerror(errno)); + goto error; + } + + if (fstat(fd, &st) != 0) { + debug("Failed to stat %s file", file); + goto error; + } + *file_length = st.st_size; + + buffer = mmap(NULL, *file_length, PROT_READ, MAP_PRIVATE, fd, 0); + if (buffer == MAP_FAILED) { + buffer = NULL; + debug("Failed to mmap %s content", file); + } + +error: + if (fd >= 0) { + close(fd); + } + + return buffer; +} + +void sys_mmap_free(void *buffer, size_t buffer_length) +{ + if (buffer && buffer_length > 0) { + munmap(buffer, buffer_length); + } +} diff --git a/src/lib/sys.h b/src/lib/sys.h index 6f65a4c1..22cad94d 100644 --- a/src/lib/sys.h +++ b/src/lib/sys.h @@ -261,6 +261,29 @@ long sys_get_file_size(const char *filename); */ int sys_dir_is_empty(const char *path); +/** + * @brief Writes the specified content into a file + * + * @return 0 on success or a value < 0 on error + */ +int sys_write_file(char *file, void *content, size_t content_size); + +/** + * @brief Maps a file into memory. + * + * The function maps the file into a buffer and it also stores the length of the data + * in the file_length + * + * @return 0 on successfull mapping or an errno on error + */ +void *sys_mmap_file(const char *file, size_t *file_length); + +/** + * @brief Deletes the mapping for the specified address range + * + */ +void sys_mmap_free(void *buffer, size_t buffer_length); + #ifdef __cplusplus } #endif diff --git a/src/manifest.c b/src/manifest.c index 6a3e80d2..2087074d 100644 --- a/src/manifest.c +++ b/src/manifest.c @@ -335,7 +335,7 @@ retry_load: return NULL; } - string_or_die(&filename, "%s/%i/Manifest.MoM", globals.state_dir, version); + filename = sys_path_join("%s/%i/Manifest.MoM", globals.state_dir, version); string_or_die(&url, "%s/%i/Manifest.MoM", globals.content_url, version); if (!globals.sigcheck) { diff --git a/src/signature.c b/src/signature.c index 2efd5544..3fa98c2c 100644 --- a/src/signature.c +++ b/src/signature.c @@ -261,76 +261,33 @@ error: bool signature_verify(const char *file, const char *sig_file, enum signature_flags flags) { - struct stat st; - char *errorstr = NULL; bool result = false; - - int data_fd = -1; size_t data_len; void *data = NULL; - - int sig_fd = -1; size_t sig_len; void *sig = NULL; /* get the signature */ - sig_fd = open(sig_file, O_RDONLY); - if (sig_fd == -1) { - string_or_die(&errorstr, "Failed to open %s: %s", sig_file, strerror(errno)); + sig = sys_mmap_file(sig_file, &sig_len); + if (!sig) { goto error; } - if (fstat(sig_fd, &st) != 0) { - string_or_die(&errorstr, "Failed to stat %s file", sig_file); - goto error; - } - sig_len = st.st_size; - sig = mmap(NULL, sig_len, PROT_READ, MAP_PRIVATE, sig_fd, 0); - if (sig == MAP_FAILED) { - string_or_die(&errorstr, "Failed to mmap %s signature", sig_file); - goto error; - } - /* get the data to be verified */ - data_fd = open(file, O_RDONLY); - if (data_fd == -1) { - string_or_die(&errorstr, "Failed to open %s", file); - goto error; - } - if (fstat(data_fd, &st) != 0) { - string_or_die(&errorstr, "Failed to stat %s", file); - goto error; - } - data_len = st.st_size; - data = mmap(NULL, data_len, PROT_READ, MAP_PRIVATE, data_fd, 0); - if (data == MAP_FAILED) { - string_or_die(&errorstr, "Failed to mmap %s", file); + /* get the data to be verified */ + data = sys_mmap_file(file, &data_len); + if (!data) { goto error; } result = signature_verify_data(data, data_len, sig, sig_len, flags); error: - if (!result && flags & SIGNATURE_PRINT_ERRORS) { - if (errorstr) { - debug("%s\n", errorstr); - } + if (!result && (flags & SIGNATURE_PRINT_ERRORS)) { warn("Signature check failed\n"); } + sys_mmap_free(sig, sig_len); + sys_mmap_free(data, data_len); - free_and_clear_pointer(&errorstr); - - if (sig) { - munmap(sig, sig_len); - } - if (sig_fd >= 0) { - close(sig_fd); - } - if (data) { - munmap(data, data_len); - } - if (data_fd >= 0) { - close(data_fd); - } return result; } diff --git a/src/subscriptions.c b/src/subscriptions.c index c042ad15..f37b0edb 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -62,7 +62,7 @@ void read_subscriptions(struct list **subs) DIR *dir; struct dirent *ent; - string_or_die(&path, "%s/%s", globals.path_prefix, BUNDLES_DIR); + path = sys_path_join("%s/%s", globals.path_prefix, BUNDLES_DIR); dir = opendir(path); if (dir) { diff --git a/src/version.c b/src/version.c index 37a0e912..eb88ff84 100644 --- a/src/version.c +++ b/src/version.c @@ -257,11 +257,11 @@ static bool get_osrelease_value(char *path_prefix, char *key, char *buff) int keystring_len = 0; bool keyfound = false; - string_or_die(&releasefile, "%s/usr/lib/os-release", path_prefix); + releasefile = sys_path_join("%s/usr/lib/os-release", path_prefix); file = fopen(releasefile, "rm"); if (!file) { free_and_clear_pointer(&releasefile); - string_or_die(&releasefile, "%s/etc/os-release", path_prefix); + releasefile = sys_path_join("%s/etc/os-release", path_prefix); file = fopen(releasefile, "rm"); if (!file) { free_and_clear_pointer(&releasefile); diff --git a/test/functional/3rd-party/3rd-party-update-export-template-multi-repo.bats b/test/functional/3rd-party/3rd-party-update-export-template-multi-repo.bats new file mode 100755 index 00000000..92d43bb5 --- /dev/null +++ b/test/functional/3rd-party/3rd-party-update-export-template-multi-repo.bats @@ -0,0 +1,221 @@ +#!/usr/bin/env bats + +# Author: Castulo Martinez +# Email: castulo.martinez@intel.com + +load "../testlib" + +test_setup() { + + # create a couple of 3rd-party repos with one installed bundle that has + # multiple binaries + create_test_environment -r "$TEST_NAME" + create_third_party_repo -a "$TEST_NAME" 10 staging repo1 + create_bundle -L -n test-bundle1 -f /usr/bin/binary_1,/bin/binary_2,/usr/local/bin/binary_3 -u repo1 "$TEST_NAME" + create_third_party_repo -a "$TEST_NAME" 10 staging repo2 + create_bundle -L -n test-bundle2 -f /usr/bin/binary_4,/bin/binary_5,/usr/local/bin/binary_6 -u repo2 "$TEST_NAME" + + # create an update that updates only one of the bundle's binaries + create_version -r "$TEST_NAME" 20 10 staging repo1 + update_bundle "$TEST_NAME" test-bundle1 --update /bin/binary_2 repo1 + + # add an update to the current template file + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" "\nA little update\n" + + # let's add a line to the scripts for all binaries so we can tell if + # they were re-generated after the update + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 "TEST_STRING" + +} + +@test "TPR085: Update 3rd-party repositories that have exported binaries when the template has changed" { + + # pre-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + + # If the template file is different than that in the swupd binary, + # all binaries should be re-generated regardless of if they were updated or not, + # also the template file should be updated + + run sudo sh -c "$SWUPD 3rd-party update $SWUPD_OPTS" + + assert_status_is "$SWUPD_OK" + expected_output=$(cat <<-EOM + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Preparing to update from 10 to 20 + Downloading packs for: + - os-core + - test-bundle1 + Finishing packs extraction... + Statistics for going from version 10 to version 20: + changed bundles : 2 + new bundles : 0 + deleted bundles : 0 + changed files : 3 + new files : 0 + deleted files : 0 + Validate downloaded files + No extra files need to be downloaded + Validating 3rd-party bundle file permissions... + Installing files... + Update was applied + Updating 3rd-party bundle binaries... + Warning: post-update helper scripts skipped due to --no-scripts argument + Update successful - System updated from version 10 to version 20 + _______________________ + 3rd-Party Repo: repo2 + _______________________ + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Version on server (10) is not newer than system version (10) + Update complete - System already up-to-date at version 10 + The scripts that export binaries from 3rd-party repositories need to be regenerated + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + _______________________ + 3rd-Party Repo: repo2 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + EOM + ) + assert_is_output "$expected_output" + + # post-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + assert_not_in_output "TEST_STRING" + + # make sure the template file exists in the system and is correct + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + template_file=$(sudo cat "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE") + template=$(echo -e "$SCRIPT_TEMPLATE") + assert_equal "$template_file" "$template" + +} + +@test "TPR086: Update 3rd-party repository that has exported binaries when the template has changed using --repo" { + + # pre-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + + # If the template file is different than that in the swupd binary, + # all binaries should be re-generated for all repositories, + # regardless of if they were updated or not and regardless of if a + # single repo was specified, also the template file should be updated + + run sudo sh -c "$SWUPD 3rd-party update $SWUPD_OPTS --repo repo1" + + assert_status_is "$SWUPD_OK" + expected_output=$(cat <<-EOM + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Preparing to update from 10 to 20 + Downloading packs for: + - os-core + - test-bundle1 + Finishing packs extraction... + Statistics for going from version 10 to version 20: + changed bundles : 2 + new bundles : 0 + deleted bundles : 0 + changed files : 3 + new files : 0 + deleted files : 0 + Validate downloaded files + No extra files need to be downloaded + Validating 3rd-party bundle file permissions... + Installing files... + Update was applied + Updating 3rd-party bundle binaries... + Warning: post-update helper scripts skipped due to --no-scripts argument + Update successful - System updated from version 10 to version 20 + The scripts that export binaries from 3rd-party repositories need to be regenerated + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + _______________________ + 3rd-Party Repo: repo2 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + EOM + ) + assert_is_output "$expected_output" + + # post-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_4 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_5 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_6 + assert_not_in_output "TEST_STRING" + + # make sure the template file exists in the system and is correct + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + template_file=$(sudo cat "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE") + template=$(echo -e "$SCRIPT_TEMPLATE") + assert_equal "$template_file" "$template" + +} diff --git a/test/functional/3rd-party/3rd-party-update-export-template.bats b/test/functional/3rd-party/3rd-party-update-export-template.bats new file mode 100755 index 00000000..fec888f4 --- /dev/null +++ b/test/functional/3rd-party/3rd-party-update-export-template.bats @@ -0,0 +1,241 @@ +#!/usr/bin/env bats + +# Author: Castulo Martinez +# Email: castulo.martinez@intel.com + +load "../testlib" + +test_setup() { + + # create a 3rd-party repo with one installed bundle that has + # multiple binaries + create_test_environment -r "$TEST_NAME" + create_third_party_repo -a "$TEST_NAME" 10 staging repo1 + create_bundle -L -n test-bundle1 -f /usr/bin/binary_1,/bin/binary_2,/usr/local/bin/binary_3 -u repo1 "$TEST_NAME" + + # create an update that updates only one of the bundle's binaries + create_version -r "$TEST_NAME" 20 10 staging repo1 + update_bundle "$TEST_NAME" test-bundle1 --update /bin/binary_2 repo1 + + # let's add a line to the scripts for all binaries so we can tell if + # they were re-generated after the update + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 "TEST_STRING" + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 "TEST_STRING" + +} + +@test "TPR082: Update a 3rd-party bundle that has exported binaries when the template has not changed" { + + # pre-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + + # If the template file didn't change then only the binary that was + # udpated should be re-generated + + run sudo sh -c "$SWUPD 3rd-party update $SWUPD_OPTS" + + assert_status_is "$SWUPD_OK" + expected_output=$(cat <<-EOM + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Preparing to update from 10 to 20 + Downloading packs for: + - os-core + - test-bundle1 + Finishing packs extraction... + Statistics for going from version 10 to version 20: + changed bundles : 2 + new bundles : 0 + deleted bundles : 0 + changed files : 3 + new files : 0 + deleted files : 0 + Validate downloaded files + No extra files need to be downloaded + Validating 3rd-party bundle file permissions... + Installing files... + Update was applied + Updating 3rd-party bundle binaries... + Warning: post-update helper scripts skipped due to --no-scripts argument + Update successful - System updated from version 10 to version 20 + EOM + ) + assert_is_output "$expected_output" + + # post-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_in_output "TEST_STRING" + + # make sure the template file exists in the system and is correct + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + template_file=$(sudo cat "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE") + template=$(echo -e "$SCRIPT_TEMPLATE") + assert_equal "$template_file" "$template" + +} + +@test "TPR083: Update a 3rd-party bundle that has exported binaries when there is no template" { + + # pre-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + + # delete the template from the system + sudo rm "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + + # If the template file is not found all binaries should be re-generated + # regardless of if they were updated or not, also the template file + # should be created + + run sudo sh -c "$SWUPD 3rd-party update $SWUPD_OPTS" + + assert_status_is "$SWUPD_OK" + expected_output=$(cat <<-EOM + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Preparing to update from 10 to 20 + Downloading packs for: + - os-core + - test-bundle1 + Finishing packs extraction... + Statistics for going from version 10 to version 20: + changed bundles : 2 + new bundles : 0 + deleted bundles : 0 + changed files : 3 + new files : 0 + deleted files : 0 + Validate downloaded files + No extra files need to be downloaded + Validating 3rd-party bundle file permissions... + Installing files... + Update was applied + Updating 3rd-party bundle binaries... + Warning: post-update helper scripts skipped due to --no-scripts argument + Update successful - System updated from version 10 to version 20 + The scripts that export binaries from 3rd-party repositories need to be regenerated + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + EOM + ) + assert_is_output "$expected_output" + + # post-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_not_in_output "TEST_STRING" + + # make sure the template file exists in the system and is correct + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + template_file=$(sudo cat "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE") + template=$(echo -e "$SCRIPT_TEMPLATE") + assert_equal "$template_file" "$template" + +} + +@test "TPR084: Update a 3rd-party bundle that has exported binaries when the template has changed" { + + # pre-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + + # make a change to the template + write_to_protected_file -a "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" "random update" + + # If the template file is different than that in the swupd binary, + # all binaries should be re-generated regardless of if they were updated or not, + # also the template file should be updated + + run sudo sh -c "$SWUPD 3rd-party update $SWUPD_OPTS" + + assert_status_is "$SWUPD_OK" + expected_output=$(cat <<-EOM + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Updates from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons + Update started + Preparing to update from 10 to 20 + Downloading packs for: + - os-core + - test-bundle1 + Finishing packs extraction... + Statistics for going from version 10 to version 20: + changed bundles : 2 + new bundles : 0 + deleted bundles : 0 + changed files : 3 + new files : 0 + deleted files : 0 + Validate downloaded files + No extra files need to be downloaded + Validating 3rd-party bundle file permissions... + Installing files... + Update was applied + Updating 3rd-party bundle binaries... + Warning: post-update helper scripts skipped due to --no-scripts argument + Update successful - System updated from version 10 to version 20 + The scripts that export binaries from 3rd-party repositories need to be regenerated + _______________________ + 3rd-Party Repo: repo1 + _______________________ + Regenerating scripts... + Scripts regenerated successfully + EOM + ) + assert_is_output "$expected_output" + + # post-test checks + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_1 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_2 + assert_not_in_output "TEST_STRING" + + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/binary_3 + assert_not_in_output "TEST_STRING" + + run sudo cat "$TARGETDIR"/"$THIRD_PARTY_BIN_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + assert_not_in_output "random update" + + # make sure the template file exists in the system and is correct + assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" + template_file=$(sudo cat "$TARGETDIR"/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE") + template=$(echo -e "$SCRIPT_TEMPLATE") + assert_equal "$template_file" "$template" + +} diff --git a/test/functional/testlib.bash b/test/functional/testlib.bash index 35de1ae4..6d6ca950 100644 --- a/test/functional/testlib.bash +++ b/test/functional/testlib.bash @@ -1565,6 +1565,7 @@ create_third_party_repo() { #swupd_function debug_msg "3rd-party repo URL: $TPURL" # if requested, add the new repo to the repo.ini file + # and the template file sudo mkdir -p "$env_name"/testfs/target-dir/"$THIRD_PARTY_DIR" if [ "$add" = true ]; then { @@ -1572,6 +1573,7 @@ create_third_party_repo() { #swupd_function printf 'URL=%s\n\n' "file://$TPURL" printf 'VERSION=%s\n\n' "$version" } | sudo tee -a "$env_name"/testfs/target-dir/"$THIRD_PARTY_DIR"/repo.ini > /dev/null + write_to_protected_file "$env_name"/testfs/target-dir/"$THIRD_PARTY_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" "$SCRIPT_TEMPLATE" fi # every 3rd-party repo needs to have at least the special os-core bundle, @@ -1590,12 +1592,6 @@ create_third_party_repo() { #swupd_function create_bundle -n os-core -v "$version" -f /usr/lib/os-release:"$OS_RELEASE",/usr/share/clear/update-ca/Swupd_Root.pem:"$cert",/usr/share/defaults/swupd/format:"$FORMAT" -u "$repo_name" "$env_name" fi - # if requested, add the template file to the target system - if [ "$add" = true ]; then - sudo mkdir -p "$env_name"/testfs/target-dir/"$THIRD_PARTY_BIN_DIR" - write_to_protected_file "$env_name"/testfs/target-dir/"$THIRD_PARTY_BIN_DIR"/"$THIRD_PARTY_SCRIPT_TEMPLATE" "$SCRIPT_TEMPLATE" - fi - if [ "$TEST_ENV_ONLY" = true ]; then print "\nVariables for 3rd-party repo $repo_name:\n" print "TPURL=$TPURL" @@ -4639,6 +4635,10 @@ assert_equal() { # assertion validate_param "$val2" if [ "$val1" != "$val2" ]; then + echo "Assertion Failed" + echo "The two items being compared are not equal" + echo -e "Difference:\\n$sep" + diff -u <(echo "$val1") <(echo "$val2") || true return 1 fi