Skip to content

Commit

Permalink
Handle reset credentials in UI
Browse files Browse the repository at this point in the history
  • Loading branch information
marcosnav committed Dec 20, 2024
1 parent af224e5 commit 349c41f
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 2 deletions.
9 changes: 9 additions & 0 deletions extensions/vscode/src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import {
getStatusFromError,
getSummaryStringFromError,
} from "src/utils/errors";
import {
isErrCredentialsReset,
errCredentialsResetMessage,
} from "src/utils/errorTypes";
import { DeploymentSelector, SelectionState } from "src/types/shared";
import { LocalState, Views } from "./constants";

Expand Down Expand Up @@ -283,6 +287,11 @@ export class PublisherState implements Disposable {
this.credentials = response.data;
});
} catch (error: unknown) {
if (isErrCredentialsReset(error)) {
const warnMsg = errCredentialsResetMessage();
window.showWarningMessage(warnMsg);
return;
}
const summary = getSummaryStringFromError("refreshCredentials", error);
window.showErrorMessage(summary);
}
Expand Down
18 changes: 17 additions & 1 deletion extensions/vscode/src/utils/errorTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export type ErrorCode =
| "deployedContentNotRunning"
| "tomlValidationError"
| "tomlUnknownError"
| "pythonExecNotFound";
| "pythonExecNotFound"
| "credentialCorruptedReset";

export type axiosErrorWithJson<T = { code: ErrorCode; details: unknown }> =
AxiosError & {
Expand Down Expand Up @@ -162,6 +163,15 @@ export type ErrInvalidConfigFiles = MkErrorDataType<
export const isErrInvalidConfigFile =
mkErrorTypeGuard<ErrInvalidConfigFiles>("invalidConfigFile");

// Invalid configuration file(s)
export type ErrCredentialsReset = MkErrorDataType<"credentialCorruptedReset">;
export const isErrCredentialsReset = mkErrorTypeGuard<ErrInvalidConfigFiles>(
"credentialCorruptedReset",
);
export const errCredentialsResetMessage = () => {
return "Stored credentials for Posit Publisher found in an unrecognizable state. A reset was required in order to proceed.";
};

// Tries to match an Axios error that comes with an identifiable Json structured data
// defaulting to be ErrUnknown message when
export function resolveAgentJsonErrorMsg(err: axiosErrorWithJson) {
Expand All @@ -185,5 +195,11 @@ export function resolveAgentJsonErrorMsg(err: axiosErrorWithJson) {
return errPythonExecNotFoundErrorMessage(err);
}

// Ignore errors coming from credentials being reset,
// a warning is shown when PublisherState is updated.
if (isErrPythonExecNotFoundError(err)) {
return errPythonExecNotFoundErrorMessage(err);
}

return errUnknownMessage(err as axiosErrorWithJson<ErrUnknown>);
}
7 changes: 6 additions & 1 deletion internal/accounts/provider_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package accounts
import (
"github.com/posit-dev/publisher/internal/credentials"
"github.com/posit-dev/publisher/internal/logging"
"github.com/posit-dev/publisher/internal/types"
)

type CredentialsProvider struct {
Expand All @@ -14,7 +15,11 @@ type CredentialsProvider struct {
func NewCredentialsProvider(log logging.Logger) (*CredentialsProvider, error) {
cs, err := credentials.NewCredentialsService(log)
if err != nil {
return nil, err
// Ignore errors from credentials reset at this point
_, isCredsReset := types.IsAgentErrorOf(err, types.ErrorCredentialCorruptedReset)
if !isCredsReset {
return nil, err
}
}

return &CredentialsProvider{cs}, nil
Expand Down
5 changes: 5 additions & 0 deletions internal/services/api/get_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ func GetCredentialsHandlerFunc(log logging.Logger) http.HandlerFunc {
apiErr.JSONResponse(w)
return
}
if aerr.Code == types.ErrorCredentialCorruptedReset {
apiErr := types.APIErrorCredentialCorruptedResetFromAgentError(*aerr)
apiErr.JSONResponse(w)
return
}
}
InternalError(w, req, log, err)
return
Expand Down
14 changes: 14 additions & 0 deletions internal/types/api_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ func APIErrorCredentialsUnavailableFromAgentError(aerr AgentError) APIErrorCrede
}
}

type APIErrorCredentialCorruptedReset struct {
Code ErrorCode `json:"code"`
}

func (apierr *APIErrorCredentialCorruptedReset) JSONResponse(w http.ResponseWriter) {
jsonResult(w, http.StatusConflict, apierr)
}

func APIErrorCredentialCorruptedResetFromAgentError(aerr AgentError) APIErrorCredentialCorruptedReset {
return APIErrorCredentialCorruptedReset{
Code: ErrorCredentialCorruptedReset,
}
}

type APIErrorPythonExecNotFound struct {
Code ErrorCode `json:"code"`
}
Expand Down
20 changes: 20 additions & 0 deletions internal/types/api_errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,23 @@ func (s *ApiErrorsSuite) TestAPIErrorPythonExecNotFoundFromAgentError() {
s.Equal(http.StatusUnprocessableEntity, rec.Result().StatusCode)
s.Contains(bodyRes, `{"code":"pythonExecNotFound"}`)
}

func (s *ApiErrorsSuite) TestAPIErrorCredentialCorruptedResetFromAgentError() {
agentErr := AgentError{
Message: "",
Code: ErrorCredentialCorruptedReset,
Err: errors.New("unknown field error"),
Data: ErrorData{},
}

rec := httptest.NewRecorder()

apiError := APIErrorCredentialCorruptedResetFromAgentError(agentErr)
s.Equal(apiError.Code, ErrorCredentialCorruptedReset)

apiError.JSONResponse(rec)

bodyRes := rec.Body.String()
s.Equal(http.StatusConflict, rec.Result().StatusCode)
s.Contains(bodyRes, `{"code":"credentialCorruptedReset"}`)
}

0 comments on commit 349c41f

Please sign in to comment.