From d4e409e3ceb7eadd9cf94b1d1f99ac04fec570ee Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 2 May 2018 20:02:09 +0300 Subject: Add support for dependent repository trust --- bpkg/auth.cxx | 103 +++++++++++------ bpkg/auth.hxx | 8 +- bpkg/package.hxx | 3 +- bpkg/package.xml | 1 + bpkg/rep-create.cxx | 3 +- bpkg/rep-fetch.cxx | 195 ++++++++++++++++++++++++-------- bpkg/rep-fetch.hxx | 4 +- bpkg/rep-info.cxx | 5 +- tests/common/git/state0/libbar.tar | Bin 71680 -> 71680 bytes tests/common/git/state0/libfoo.tar | Bin 307200 -> 317440 bytes tests/common/git/state0/libfox.tar | Bin 133120 -> 133120 bytes tests/common/git/state0/style-basic.tar | Bin 71680 -> 71680 bytes tests/common/git/state0/style.tar | Bin 133120 -> 133120 bytes tests/common/git/state1/libbaz.tar | Bin 61440 -> 61440 bytes tests/common/git/state1/libfoo.tar | Bin 389120 -> 389120 bytes tests/common/git/state1/libfox.tar | Bin 133120 -> 133120 bytes tests/common/git/state1/style-basic.tar | Bin 71680 -> 71680 bytes tests/common/git/state1/style.tar | Bin 133120 -> 133120 bytes tests/rep-fetch.test | 128 ++++++++++++++++++++- 19 files changed, 359 insertions(+), 91 deletions(-) diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx index 89f2b56..8868c48 100644 --- a/bpkg/auth.cxx +++ b/bpkg/auth.cxx @@ -481,13 +481,22 @@ namespace bpkg } } - // Authenticate a real certificate. + // Authenticate a real certificate. Return the authenticated certificate and + // flag if it was authenticated by the user (via the command line/prompt) or + // by the dependent trust. // - static shared_ptr + struct cert_auth + { + shared_ptr cert; + bool user; + }; + + static cert_auth auth_real (const common_options& co, const fingerprint& fp, const string& pem, - const repository_location& rl) + const repository_location& rl, + const optional& dependent_trust) { tracer trace ("auth_real"); @@ -515,7 +524,16 @@ namespace bpkg info << "certificate for repository " << rl.canonical_name () << " authenticated by command line"; - return cert; + return cert_auth {move (cert), true}; + } + + if (dependent_trust && *dependent_trust == cert->fingerprint) + { + if (verb >= 2) + info << "certificate for repository " << rl.canonical_name () << + " authenticated by dependent trust"; + + return cert_auth {move (cert), false}; } (co.trust_no () ? error : warn) @@ -534,7 +552,7 @@ namespace bpkg if (co.trust_no () || !yn_prompt ("trust this certificate? [y/n]")) throw failed (); - return cert; + return cert_auth {move (cert), true}; } // Authenticate a certificate with the database. First check if it is @@ -545,7 +563,8 @@ namespace bpkg const dir_path& conf, database& db, const optional& pem, - const repository_location& rl) + const repository_location& rl, + const optional& dependent_trust) { tracer trace ("auth_cert"); tracer_guard tg (db, trace); @@ -553,6 +572,10 @@ namespace bpkg fingerprint fp (cert_fingerprint (co, pem, rl)); shared_ptr cert (db.find (fp.abbreviated)); + // If the certificate is in the database then it is authenticated by the + // user. In this case the dependent trust doesn't really matter as the + // user is more authoritative then the dependent. + // if (cert != nullptr) { l4 ([&]{trace << "existing cert: " << *cert;}); @@ -560,27 +583,37 @@ namespace bpkg return cert; } - cert = pem - ? auth_real (co, fp, *pem, rl) - : auth_dummy (co, fp.abbreviated, rl); + // Note that an unsigned certificate use cannot be authenticated by the + // dependent trust. + // + cert_auth ca (pem + ? auth_real (co, fp, *pem, rl, dependent_trust) + : cert_auth {auth_dummy (co, fp.abbreviated, rl), true}); - db.persist (cert); + cert = move (ca.cert); - // Save the certificate file. + // Persist the certificate only if it is authenticated by the user. // - if (pem) + if (ca.user) { - path f (conf / certs_dir / path (cert->id + ".pem")); + db.persist (cert); - try - { - ofdstream ofs (f); - ofs << *pem; - ofs.close (); - } - catch (const io_error& e) + // Save the certificate file. + // + if (pem) { - fail << "unable to write certificate to " << f << ": " << e; + path f (conf / certs_dir / path (cert->id + ".pem")); + + try + { + ofdstream ofs (f); + ofs << *pem; + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write certificate to " << f << ": " << e; + } } } @@ -591,7 +624,8 @@ namespace bpkg authenticate_certificate (const common_options& co, const dir_path* conf, const optional& pem, - const repository_location& rl) + const repository_location& rl, + const optional& dependent_trust) { tracer trace ("authenticate_certificate"); @@ -612,18 +646,23 @@ namespace bpkg // fingerprint fp (cert_fingerprint (co, pem, rl)); r = pem - ? auth_real (co, fp, *pem, rl) + ? auth_real (co, fp, *pem, rl, dependent_trust).cert : auth_dummy (co, fp.abbreviated, rl); } else if (transaction::has_current ()) { - r = auth_cert (co, *conf, transaction::current ().database (), pem, rl); + r = auth_cert (co, + *conf, + transaction::current ().database (), + pem, + rl, + dependent_trust); } else { database db (open (*conf, trace)); transaction t (db); - r = auth_cert (co, *conf, db, pem, rl); + r = auth_cert (co, *conf, db, pem, rl, dependent_trust); t.commit (); } @@ -648,11 +687,13 @@ namespace bpkg path f; auto_rmfile rm; - if (conf == nullptr) + // If we have no configuration or the certificate was authenticated by the + // dependent trust (see auth_cert() function for details), create the + // temporary certificate PEM file. + // + if (conf == nullptr || + !exists (f = *conf / certs_dir / path (cert.id + ".pem"))) { - // If we have no configuration, create the temporary certificate - // PEM file. - // assert (cert_pem); try @@ -674,10 +715,6 @@ namespace bpkg fail << "unable to obtain temporary file: " << e; } } - else - { - f = *conf / certs_dir / path (cert.id + ".pem"); - } // Make sure the names are either equal or the certificate name is a // prefix (at /-boundary) of the repository name. Note that the certificate diff --git a/bpkg/auth.hxx b/bpkg/auth.hxx index 90f60e4..8b9a871 100644 --- a/bpkg/auth.hxx +++ b/bpkg/auth.hxx @@ -22,6 +22,11 @@ namespace bpkg // other values (including '.') are assumed to be valid configuration paths // and will be diagnosed if that's not the case. // + // If the dependent trust fingerprint is present then try to authenticate + // the certificate for use by the dependent prior to prompting the user. + // Note that if certificate is authenticated for such a use, then it is not + // persisted into the database. + // // If the configuration is used, then check if we are already in transaction. // If so, then assume the configuration database is already opened and use // that. Otherwise, open the database and start a new transaction. @@ -35,7 +40,8 @@ namespace bpkg authenticate_certificate (const common_options&, const dir_path* configuration, const optional& cert_pem, - const repository_location&); + const repository_location&, + const optional& dependent_trust); // Authenticate a repository. First check that the certificate can be used // to authenticate this repository by making sure their names match. Then diff --git a/bpkg/package.hxx b/bpkg/package.hxx index ff05301..f6bada3 100644 --- a/bpkg/package.hxx +++ b/bpkg/package.hxx @@ -345,8 +345,9 @@ namespace bpkg using fragments_type = std::vector; - string name; // Object id (canonical name). + string name; // Object id (canonical name). repository_location location; + optional certificate; // PEM representation. fragments_type fragments; public: diff --git a/bpkg/package.xml b/bpkg/package.xml index a6cc552..fe297e7 100644 --- a/bpkg/package.xml +++ b/bpkg/package.xml @@ -50,6 +50,7 @@ + diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx index ba2eb73..2de1de1 100644 --- a/bpkg/rep-create.cxx +++ b/bpkg/rep-create.cxx @@ -227,7 +227,8 @@ namespace bpkg ofs.close (); } - const optional& cert (rms.back ().certificate); + const optional& cert (find_base_repository (rms).certificate); + if (cert) { const string& key (o.key ()); diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx index ba0c4f3..def7cd0 100644 --- a/bpkg/rep-fetch.cxx +++ b/bpkg/rep-fetch.cxx @@ -4,6 +4,7 @@ #include +#include #include #include // equal() @@ -40,10 +41,18 @@ namespace bpkg // static bool filesystem_state_changed; + inline static bool + need_auth (const common_options& co, const repository_location& rl) + { + return rl.type () == repository_type::pkg && co.auth () != auth::none && + (co.auth () == auth::all || rl.remote ()); + } + static rep_fetch_data rep_fetch_pkg (const common_options& co, const dir_path* conf, const repository_location& rl, + const optional& dependent_trust, bool ignore_unknown) { // First fetch the repositories list and authenticate the base's @@ -55,15 +64,17 @@ namespace bpkg rep_fetch_data::fragment fr; fr.repositories = move (rmc.first); - bool a (co.auth () != auth::none && - (co.auth () == auth::all || rl.remote ())); + bool a (need_auth (co, rl)); shared_ptr cert; - optional cert_pem (move (fr.repositories.back ().certificate)); + const optional& cert_pem ( + find_base_repository (fr.repositories).certificate); if (a) { - cert = authenticate_certificate (co, conf, cert_pem, rl); + cert = authenticate_certificate ( + co, conf, cert_pem, rl, dependent_trust); + a = !cert->dummy (); } @@ -430,15 +441,16 @@ namespace bpkg return r; } - rep_fetch_data + static rep_fetch_data rep_fetch (const common_options& co, const dir_path* conf, const repository_location& rl, + const optional& dt, bool iu) { switch (rl.type ()) { - case repository_type::pkg: return rep_fetch_pkg (co, conf, rl, iu); + case repository_type::pkg: return rep_fetch_pkg (co, conf, rl, dt, iu); case repository_type::dir: return rep_fetch_dir (co, rl, iu); case repository_type::git: return rep_fetch_git (co, conf, rl, iu); } @@ -447,17 +459,29 @@ namespace bpkg return rep_fetch_data (); } + rep_fetch_data + rep_fetch (const common_options& co, + const dir_path* conf, + const repository_location& rl, + bool iu) + { + return rep_fetch (co, conf, rl, nullopt /* dependent_trust */, iu); + } + // Return an existing repository fragment or create a new one. Update the // existing object unless it is immutable (see repository_fragment class // description for details). Don't fetch the complement and prerequisite // repositories. // + using repository_trust = map, optional>; + static shared_ptr rep_fragment (const common_options& co, const dir_path& conf, transaction& t, const repository_location& rl, - rep_fetch_data::fragment&& fr) + rep_fetch_data::fragment&& fr, + repository_trust& repo_trust) { tracer trace ("rep_fragment"); @@ -495,6 +519,56 @@ namespace bpkg shared_ptr rf ( db.find (rfl.canonical_name ())); + // Complete the repository manifest relative locations using this + // repository as a base. + // + for (repository_manifest& rm: fr.repositories) + { + if (rm.effective_role () != repository_role::base) + { + repository_location& l (rm.location); + + if (l.relative ()) + { + try + { + l = repository_location (l, rl); + } + catch (const invalid_argument& e) + { + fail << "invalid relative repository location '" << l + << "': " << e << + info << "base repository location is " << rl; + } + } + } + } + + // Add/upgrade (e.g., from the latest commit) the dependent trust for + // the prerequisite/complement repositories. Here we rely on the fact that + // rep_fragment() function is called for fragments (e.g., commits) in + // earliest to latest order, as they appear in the repository object. + // + // Note that we also rely on the manifest location values be + // absolute/remote (see above) and the corresponding repository objects be + // present in the database. + // + auto add_trust = [&fr, &repo_trust, &db] () + { + for (repository_manifest& rm: fr.repositories) + { + if (rm.effective_role () != repository_role::base) + { + auto i (repo_trust.emplace ( + db.load (rm.location.canonical_name ()), + rm.trust)); + + if (!i.second) + i.first->second = move (rm.trust); + } + } + }; + // Return the existing repository fragment if it is immutable. // bool exists (rf != nullptr); @@ -514,7 +588,10 @@ namespace bpkg } if (!mut) + { + add_trust (); return rf; + } } // Create or update the repository fragment. @@ -536,24 +613,7 @@ namespace bpkg if (rr == repository_role::base) continue; // Entry for this repository. - repository_location& l (rm.location); - - // If the location is relative, complete it using this repository - // as a base. - // - if (l.relative ()) - { - try - { - l = repository_location (l, rl); - } - catch (const invalid_argument& e) - { - fail << "invalid relative repository location '" << l - << "': " << e << - info << "base repository location is " << rl; - } - } + const repository_location& l (rm.location); // Create the new repository if it is not in the database yet, otherwise // update its location if it is changed, unless the repository is a @@ -565,7 +625,7 @@ namespace bpkg if (r == nullptr) { - r = make_shared (move (l)); + r = make_shared (l); db.persist (r); // Enter into session, important if recursive. } else if (r->location.url () != l.url ()) @@ -577,7 +637,7 @@ namespace bpkg if (ua.find (r) == ua.end ()) { - r->location = move (l); + r->location = l; db.update (r); } } @@ -616,6 +676,8 @@ namespace bpkg } } + add_trust (); + // For dir and git repositories that have neither prerequisites nor // complements we use the root repository as the default complement. // @@ -753,6 +815,7 @@ namespace bpkg const dir_path& conf, transaction& t, const shared_ptr& r, + const optional& dependent_trust, repositories& fetched_repositories, repositories& removed_repositories, repository_fragments& removed_fragments, @@ -772,7 +835,21 @@ namespace bpkg // dependencies. // if (!fetched_repositories.insert (r).second) // Is already fetched. + { + // Authenticate the repository use by the dependent, if required. + // + // Note that we only need to authenticate the certificate but not the + // repository that was already fetched (and so is already authenticated). + // + if (need_auth (co, r->location)) + authenticate_certificate (co, + &conf, + r->certificate, + r->location, + dependent_trust); + return; + } const repository_location& rl (r->location); l4 ([&]{trace << r->name << " " << rl;}); @@ -833,17 +910,24 @@ namespace bpkg // repository fragments list, as well as its prerequisite and complement // repository sets. // - rep_fetch_data rfd (rep_fetch (co, &conf, rl, true /* ignore_unknow */)); + rep_fetch_data rfd ( + rep_fetch (co, &conf, rl, dependent_trust, true /* ignore_unknow */)); + + // Save for subsequent certificate authentication for repository use by + // its dependents. + // + r->certificate = move (rfd.certificate_pem); repository_fragment::complements_type new_complements; repository_fragment::prerequisites_type new_prerequisites; + repository_trust repo_trust; for (rep_fetch_data::fragment& fr: rfd.fragments) { string nm (fr.friendly_name); // Don't move, still may be used. shared_ptr rf ( - rep_fragment (co, conf, t, rl, move (fr))); + rep_fragment (co, conf, t, rl, move (fr), repo_trust)); collect_deps (rf, new_complements, new_prerequisites); @@ -907,34 +991,48 @@ namespace bpkg for (const lazy_weak_ptr& pr: old_prerequisites) rm (lazy_shared_ptr (pr)); - const string& rn (rl.canonical_name ()); - - // Fetch complements and prerequisites. - // - for (const auto& cr: new_complements) + auto fetch = [&co, + &conf, + &t, + &fetched_repositories, + &removed_repositories, + &removed_fragments, + &rl, + &repo_trust] + (const shared_ptr& r, const char* what) { - if (cr.object_id () != "") - rep_fetch (co, - conf, - t, - cr.load (), - fetched_repositories, - removed_repositories, - removed_fragments, - false /* shallow */, - "complements " + rn); - } + auto i (repo_trust.find (r)); + assert (i != repo_trust.end ()); - for (const auto& pr: new_prerequisites) rep_fetch (co, conf, t, - pr.load (), + r, + i->second, fetched_repositories, removed_repositories, removed_fragments, false /* shallow */, - "prerequisite of " + rn); + what + rl.canonical_name ()); + }; + + // Fetch complements and prerequisites. + // + for (const auto& cr: new_complements) + { + if (cr.object_id () != "") + { + fetch (cr.load (), "complements "); + + // Remove the repository from the prerequisites, if present, to avoid + // the use re-authentication. + // + new_prerequisites.erase (cr); + } + } + + for (const auto& pr: new_prerequisites) + fetch (pr.load (), "prerequisite of "); } } @@ -978,6 +1076,7 @@ namespace bpkg conf, t, r.load (), + nullopt /* dependent_trust */, fetched_repositories, removed_repositories, removed_fragments, diff --git a/bpkg/rep-fetch.hxx b/bpkg/rep-fetch.hxx index 7e7777f..3b5e80d 100644 --- a/bpkg/rep-fetch.hxx +++ b/bpkg/rep-fetch.hxx @@ -41,9 +41,9 @@ namespace bpkg vector fragments; - // For base pkg repo (can be nullopt/NULL). + // For pkg repositories (can be nullopt/NULL). // - optional cert_pem; + optional certificate_pem; shared_ptr certificate; // Authenticated. }; diff --git a/bpkg/rep-info.cxx b/bpkg/rep-info.cxx index 7dd4a28..1ffeee3 100644 --- a/bpkg/rep-info.cxx +++ b/bpkg/rep-info.cxx @@ -73,7 +73,7 @@ namespace bpkg if (all || cert_info) { shared_ptr& cert (rfd.certificate); - const optional& cert_pem (rfd.cert_pem); + const optional& cert_pem (rfd.certificate_pem); if (cert_pem) { @@ -174,7 +174,8 @@ namespace bpkg assert (!rfd.fragments.empty () && !rfd.fragments.back ().repositories.empty ()); - rms.push_back (move (rfd.fragments.back ().repositories.back ())); + rms.push_back ( + find_base_repository (rfd.fragments.back ().repositories)); // Note: serializing without any extra repository_manifests info. // diff --git a/tests/common/git/state0/libbar.tar b/tests/common/git/state0/libbar.tar index 1db19e5..791d8f2 100644 Binary files a/tests/common/git/state0/libbar.tar and b/tests/common/git/state0/libbar.tar differ diff --git a/tests/common/git/state0/libfoo.tar b/tests/common/git/state0/libfoo.tar index b2fa494..e6bb1c2 100644 Binary files a/tests/common/git/state0/libfoo.tar and b/tests/common/git/state0/libfoo.tar differ diff --git a/tests/common/git/state0/libfox.tar b/tests/common/git/state0/libfox.tar index fe226a3..31dda5a 100644 Binary files a/tests/common/git/state0/libfox.tar and b/tests/common/git/state0/libfox.tar differ diff --git a/tests/common/git/state0/style-basic.tar b/tests/common/git/state0/style-basic.tar index 63904e2..098e0ff 100644 Binary files a/tests/common/git/state0/style-basic.tar and b/tests/common/git/state0/style-basic.tar differ diff --git a/tests/common/git/state0/style.tar b/tests/common/git/state0/style.tar index 8c6c6ea..5ad84da 100644 Binary files a/tests/common/git/state0/style.tar and b/tests/common/git/state0/style.tar differ diff --git a/tests/common/git/state1/libbaz.tar b/tests/common/git/state1/libbaz.tar index 7ca795c..cd2d215 100644 Binary files a/tests/common/git/state1/libbaz.tar and b/tests/common/git/state1/libbaz.tar differ diff --git a/tests/common/git/state1/libfoo.tar b/tests/common/git/state1/libfoo.tar index af5212b..57befb1 100644 Binary files a/tests/common/git/state1/libfoo.tar and b/tests/common/git/state1/libfoo.tar differ diff --git a/tests/common/git/state1/libfox.tar b/tests/common/git/state1/libfox.tar index 6e108ba..648811f 100644 Binary files a/tests/common/git/state1/libfox.tar and b/tests/common/git/state1/libfox.tar differ diff --git a/tests/common/git/state1/style-basic.tar b/tests/common/git/state1/style-basic.tar index cd6416e..ab302de 100644 Binary files a/tests/common/git/state1/style-basic.tar and b/tests/common/git/state1/style-basic.tar differ diff --git a/tests/common/git/state1/style.tar b/tests/common/git/state1/style.tar index d2c2a70..7772b98 100644 Binary files a/tests/common/git/state1/style.tar and b/tests/common/git/state1/style.tar differ diff --git a/tests/rep-fetch.test b/tests/rep-fetch.test index 6f563d4..2264462 100644 --- a/tests/rep-fetch.test +++ b/tests/rep-fetch.test @@ -79,7 +79,21 @@ # Create 'foo/*' repositories. # cp -r $src/foo $out/foo - $rep_create $out/foo/stable &$out/foo/stable/packages.manifest + + # Sign foo/stable repository. + # + cat <<<$cert_manifest >+$out/foo/stable/repositories.manifest + $rep_create --key $key $out/foo/stable &$out/foo/stable/packages.manifest \ + &$out/foo/stable/signature.manifest + + # Add dependent trust to foo complement repository into the foo/testing + # repository manifest. + # + tv = "trust: $cert_fp +:" + + sed -i -e "s/^\(:\)\$/$tv/" $out/foo/testing/repositories.manifest + $rep_create $out/foo/testing &$out/foo/testing/packages.manifest # Create 'bar/*' repositories. @@ -154,7 +168,7 @@ $* 2>>/EOE != 0 { $clone_root_cfg && $rep_add $rep/bar/unstable; - $* --trust-yes 2>>EOE; + $* --trust-yes 2>>EOE &cfg/.bpkg/certs/**; fetching pkg:build2.org/rep-fetch/bar/unstable fetching pkg:build2.org/rep-fetch/bar/testing (complements pkg:build2.org/rep-fetch/bar/unstable) fetching pkg:build2.org/rep-fetch/bar/stable (complements pkg:build2.org/rep-fetch/bar/testing) @@ -204,7 +218,7 @@ $* 2>>/EOE != 0 { $clone_root_cfg; - $* --trust-yes $rep/bar/unstable 2>>EOE; + $* --trust-yes $rep/bar/unstable 2>>EOE &cfg/.bpkg/certs/**; added pkg:build2.org/rep-fetch/bar/unstable fetching pkg:build2.org/rep-fetch/bar/testing (complements pkg:build2.org/rep-fetch/bar/unstable) fetching pkg:build2.org/rep-fetch/bar/stable (complements pkg:build2.org/rep-fetch/bar/testing) @@ -325,6 +339,114 @@ $* 2>>/EOE != 0 EOO } } + + : use-auth + : + { + : dependent-trust + : + : Test that the certificate of foo/stable complement repository is + : silently authenticated for use by the dependent foo/testing repository. + : In this case the certificate is not saved into the database (see the + : subsequent 'rep-fetch $rep/foo/stable' test) and certificate file is not + : persisted (otherwise cleanup of non-empty cfg/ directory would fail). + : + { + $clone_root_cfg; + + $* --verbose 2 $rep/foo/testing <'y' 2>>~%EOE%; + added pkg:build2.org/rep-fetch/foo/testing + %.* + warning: repository pkg:build2.org/rep-fetch/foo/testing is unsigned + %continue without authenticating repositories at .+\? \[y/n\] .+% + %.+ + info: certificate for repository pkg:build2.org/rep-fetch/foo/stable authenticated by dependent trust + %.+ + 2 package(s) in 2 repository(s) + EOE + + $* $rep/foo/stable 2>>~%EOE% != 0 + %.+ + warning: authenticity of the certificate for repository pkg:build2.org/rep-fetch/foo/stable cannot be established + %.+ + EOE + } + + : dependent-command-line + : + : Test that the certificate of foo/stable complement repository is + : authenticated for use by the command line (persisted into the database + : and the filesystem) rather than dependent trust. + : + { + $clone_root_cfg; + + $* --trust $cert_fp --verbose 2 $rep/foo/testing <'y' 2>>~%EOE% &cfg/.bpkg/certs/** + added pkg:build2.org/rep-fetch/foo/testing + %.* + warning: repository pkg:build2.org/rep-fetch/foo/testing is unsigned + %continue without authenticating repositories at .+\? \[y/n\] .+% + %.+ + info: certificate for repository pkg:build2.org/rep-fetch/foo/stable authenticated by command line + %.+ + 2 package(s) in 2 repository(s) + EOE + } + + : dependent-trust-prompt + : + : Test that the certificate of foo/stable repository is first authenticated + : for use by the dependent foo/test repository and then by the user (via + : the prompt) as a top-level repository during a single rep-fetch + : operation. + : + { + yy = 'y +y' + $clone_root_cfg; + + $* --verbose 2 $rep/foo/testing $rep/foo/stable <$yy 2>>~%EOE% &cfg/.bpkg/certs/** + added pkg:build2.org/rep-fetch/foo/testing + added pkg:build2.org/rep-fetch/foo/stable + fetching pkg:build2.org/rep-fetch/foo/testing + %.* + warning: repository pkg:build2.org/rep-fetch/foo/testing is unsigned + %continue without authenticating repositories at .+\? \[y/n\] .+% + %.+ + info: certificate for repository pkg:build2.org/rep-fetch/foo/stable authenticated by dependent trust + %.+ + warning: authenticity of the certificate for repository pkg:build2.org/rep-fetch/foo/stable cannot be established + certificate is for build2.org, "Code Synthesis" + %.+ + %.+2 package\(s\) in 2 repository\(s\)% + EOE + } + + : command-line-dependent-noop + : + : Test that the certificate of foo/stable repository is first authenticated + : by the user (via the command line) as a top-level repository and so + : authentication for use by the dependent foo/test is noop. + : + { + $clone_root_cfg; + + $* --trust $cert_fp --verbose 2 $rep/foo/stable $rep/foo/testing <'y' 2>>~%EOE% &cfg/.bpkg/certs/** + added pkg:build2.org/rep-fetch/foo/stable + added pkg:build2.org/rep-fetch/foo/testing + fetching pkg:build2.org/rep-fetch/foo/stable + %.+ + info: certificate for repository pkg:build2.org/rep-fetch/foo/stable authenticated by command line + %.+ + fetching pkg:build2.org/rep-fetch/foo/testing + %.* + warning: repository pkg:build2.org/rep-fetch/foo/testing is unsigned + %continue without authenticating repositories at .+\? \[y/n\] .+% + %.* + 2 package(s) in 2 repository(s) + EOE + } + } } : dir-rep -- cgit v1.1