-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Source resilience #1470
Source resilience #1470
Conversation
It seems to me, as a user, I would think the expected behavior (coming from other package managers), would be that winget still installs whatever the closest thing it can find from available sources, since I presumably trust all of the sources I've added equally (or else I wouldn't have them). If that's too unsafe, then maybe a hint under the error would be nice, like:
which would save the trouble of me having to search for someone with the package myself, since presumably |
@JohnMcPMS what do you think about the suggestion from @jedieaston? |
I don't think of it as a security issue, but rather a conservative take that we can't know what the user intent was. So if there is a
This is a good idea and I will add it. |
Ok, it is going to require a bit more work than I expected, but I think it will end up being a better experience overall anyway. |
…able through project, add exploratory E2E test
This comment has been minimized.
This comment has been minimized.
@jedieaston , I updated the PR description with the behavior of showing the search results from the not failing sources. |
That looks awesome! Thanks! |
I think this also performs a search against the sources, this is also used in upgrade command but maybe it's ok we do not perform sophisticated handling for -m cases Refers to: src/AppInstallerCLICore/Commands/UninstallCommand.cpp:119 in c360e5d. [](commit_id = c360e5d, deletion_comment = False) |
// Custom header for Rest sources | ||
std::optional<std::string> CustomHeader; | ||
|
||
// Source information containing source agreements, required/unsupported match fields. | ||
SourceInformation Information; | ||
|
||
// Prevent correlation against this source if true. | ||
bool DoNotCorrelateAgainst = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context << | ||
Workflow::ReportExecutionStage(Workflow::ExecutionStage::Discovery) << | ||
Workflow::OpenSource << | ||
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed) << | ||
Workflow::SearchSourceForMany << | ||
Workflow::HandleSearchResultFailures << |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had considered that, but I'm not sure. I think that there is probably a case to be made to have an uber search task (or two) that takes a few well defined behavior flags and roll search + handle failure + ensure* since they are very much linked.
But given our timeframe I'm going to put that on the debt rather than change it here.
error << Resource::String::SearchFailureError << ' ' << failure.Source->GetDetails().Name << std::endl; | ||
HRESULT failureHR = HandleException(context, failure.Exception); | ||
|
||
// Just take first failure for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to create a new failure bucket that is "multiple failures" yet.
Assert.True(result.StdOut.Contains("Failed when searching source: failSearch")); | ||
Assert.True(result.StdOut.Contains("AppInstallerTest.TestExeInstaller")); | ||
Assert.False(result.StdOut.Contains("Successfully installed")); | ||
Assert.False(VerifyTestExeInstalled(installDir, "/execustom")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -226,6 +226,11 @@ | |||
<SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Windows</SubSystem> | |||
</Link> | |||
</ItemDefinitionGroup> | |||
<ItemDefinitionGroup Condition="'$(WingetDisableTestHooks)'=='true'"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be after this is pulled in.
} | ||
|
||
// Move failures into the single result | ||
for (SearchResult::Failure& failure : availableResult.Failures) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I saw this carries the OpenSource failure. Any reason not adding these failures to OpenSourceResult and handle there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had originally done that, but this pattern made it cleaner to show the suggestions on a failed install
command.
} | ||
|
||
// Move failures into the single result | ||
std::move(availableResult.Failures.begin(), availableResult.Failures.end(), std::back_inserter(result.Failures)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably, although I put that in mostly as a guard against unbounded correlation failures.
{ | ||
LOG_CAUGHT_EXCEPTION(); | ||
AICLI_LOG(Repo, Warning, << "Failed to open source: " << source.get().Name); | ||
openExceptionProxies.emplace_back(std::make_shared<OpenExceptionProxy>(source, std::current_exception())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
never mind, there's a none available check below
[Test] | ||
public void InstallExeWithAlternateSourceFailure() | ||
{ | ||
TestCommon.RunAICLICommand("source add", "failSearch \"{ \"\"SearchHR\"\": \"\"0x80070002\"\" }\" Microsoft.Test.Configurable --header \"{}\""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The double double-quotes are to convince cmd
to actually pass in a single double-quote to the process.
} | ||
|
||
if (sourceUpdated) | ||
{ | ||
sourceList.SaveMetadata(); | ||
} | ||
|
||
// If all sources failed to open, then throw an exception that is specific to this case. | ||
THROW_HR_IF(APPINSTALLER_CLI_ERROR_FAILED_TO_OPEN_ALL_SOURCES, !aggregatedSource->HasAvailableSource()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns a copy of the vector and I didn't need that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -94,7 +93,7 @@ namespace AppInstaller::Repository | |||
details.Arg = s_Source_MSStoreDefault_Arg; | |||
details.Identifier = s_Source_MSStoreDefault_Identifier; | |||
details.TrustLevel = SourceTrustLevel::Trusted; | |||
details.Restricted = true; | |||
details.SupportCorrelation = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixes #1349, #1437 (although #1437 seems to have been re-opened more as a "the store is down" than "the client doesn't handle that well").
Change
Improves handling of errors from one source when multiple are configured by capturing the errors and including them as part of the source open and search results. Some commands will continue to fail if one of the sources has an error to prevent said error from affecting a change to the system. The commands that still fail are
install
,import
, andupgrade --all|<specific>
and they now indicate which source failed.Examples of new behavior:
This change also replaces the experimental
msstore
source with the more official but still greenmsstore
source (previously calledstorepreview
). This source is now capable of providing basic search functionality against the entire Store catalog. It does not provide any correlation for installed packages however. In addition, the store source is being moved out of experimental.Validation
Added test source type that can be configured to fail in specific ways to enable easier validation of changes.
Unit tests added to ensure proper error handling.
E2E test added using test source type.
Microsoft Reviewers: Open in CodeFlow