mirror of https://github.com/portainer/portainer
fix(k8s/gitops): missing git auth toggle in k8s app edit page [EE-5320] (#8741)
parent
5ac1ea3df8
commit
a65ffe519a
|
@ -151,6 +151,9 @@ func (handler *Handler) stackUpdateGit(w http.ResponseWriter, r *http.Request) *
|
|||
|
||||
if payload.RepositoryAuthentication {
|
||||
password := payload.RepositoryPassword
|
||||
|
||||
// When the existing stack is using the custom username/password and the password is not updated,
|
||||
// the stack should keep using the saved username/password
|
||||
if password == "" && stack.GitConfig != nil && stack.GitConfig.Authentication != nil {
|
||||
password = stack.GitConfig.Authentication.Password
|
||||
}
|
||||
|
|
|
@ -139,6 +139,9 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request)
|
|||
repositoryPassword := ""
|
||||
if payload.RepositoryAuthentication {
|
||||
repositoryPassword = payload.RepositoryPassword
|
||||
|
||||
// When the existing stack is using the custom username/password and the password is not updated,
|
||||
// the stack should keep using the saved username/password
|
||||
if repositoryPassword == "" && stack.GitConfig != nil && stack.GitConfig.Authentication != nil {
|
||||
repositoryPassword = stack.GitConfig.Authentication.Password
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { GitAuthModel } from '@/react/portainer/gitops/types';
|
|||
import { gitAuthValidation } from '@/react/portainer/gitops/AuthFieldset';
|
||||
import { GitCredential } from '@/react/portainer/account/git-credentials/types';
|
||||
import { getGitCredentials } from '@/react/portainer/account/git-credentials/git-credentials.service';
|
||||
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
||||
|
||||
import { validateForm } from '@@/form-components/validate-form';
|
||||
|
||||
|
@ -23,6 +24,8 @@ export default class GitFormAuthFieldsetController {
|
|||
|
||||
value?: GitAuthModel;
|
||||
|
||||
isAuthEdit: boolean;
|
||||
|
||||
onChange?: (value: GitAuthModel) => void;
|
||||
|
||||
/* @ngInject */
|
||||
|
@ -33,6 +36,7 @@ export default class GitFormAuthFieldsetController {
|
|||
this.$async = $async;
|
||||
this.Authentication = Authentication;
|
||||
|
||||
this.isAuthEdit = false;
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.runGitValidation = this.runGitValidation.bind(this);
|
||||
}
|
||||
|
@ -48,10 +52,10 @@ export default class GitFormAuthFieldsetController {
|
|||
...newValues,
|
||||
};
|
||||
this.onChange?.(value);
|
||||
await this.runGitValidation(value);
|
||||
await this.runGitValidation(value, false);
|
||||
}
|
||||
|
||||
async runGitValidation(value: GitAuthModel) {
|
||||
async runGitValidation(value: GitAuthModel, isAuthEdit: boolean) {
|
||||
return this.$async(async () => {
|
||||
this.errors = {};
|
||||
this.gitFormAuthFieldset?.$setValidity(
|
||||
|
@ -61,7 +65,7 @@ export default class GitFormAuthFieldsetController {
|
|||
);
|
||||
|
||||
this.errors = await validateForm<GitAuthModel>(
|
||||
() => gitAuthValidation(this.gitCredentials),
|
||||
() => gitAuthValidation(this.gitCredentials, isAuthEdit),
|
||||
value
|
||||
);
|
||||
if (this.errors && Object.keys(this.errors).length > 0) {
|
||||
|
@ -75,23 +79,24 @@ export default class GitFormAuthFieldsetController {
|
|||
}
|
||||
|
||||
async $onInit() {
|
||||
try {
|
||||
this.gitCredentials = await getGitCredentials(
|
||||
this.Authentication.getUserDetails().ID
|
||||
);
|
||||
} catch (err) {
|
||||
notifyError(
|
||||
'Failure',
|
||||
err as Error,
|
||||
'Unable to retrieve user saved git credentials'
|
||||
);
|
||||
if (isBE) {
|
||||
try {
|
||||
// Only BE version support /gitcredentials
|
||||
this.gitCredentials = await getGitCredentials(
|
||||
this.Authentication.getUserDetails().ID
|
||||
);
|
||||
} catch (err) {
|
||||
notifyError(
|
||||
'Failure',
|
||||
err as Error,
|
||||
'Unable to retrieve user saved git credentials'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// this should never happen, but just in case
|
||||
if (!this.value) {
|
||||
throw new Error('GitFormController: value is required');
|
||||
}
|
||||
|
||||
await this.runGitValidation(this.value);
|
||||
await this.runGitValidation(this.value, this.isAuthEdit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,15 @@ export const gitFormAuthFieldset: IComponentOptions = {
|
|||
<react-git-form-auth-fieldset
|
||||
value="$ctrl.value"
|
||||
on-change="$ctrl.handleChange"
|
||||
is-explanation-visible="$ctrl.isExplanationVisible"
|
||||
errors="$ctrl.errors">
|
||||
is-auth-explanation-visible="$ctrl.isAuthExplanationVisible"
|
||||
errors="$ctrl.errors"
|
||||
is-auth-edit="$ctrl.isAuthEdit">
|
||||
</react-git-form-auth-fieldset>
|
||||
</ng-form>`,
|
||||
bindings: {
|
||||
value: '<',
|
||||
onChange: '<',
|
||||
isExplanationVisible: '<',
|
||||
isAuthExplanationVisible: '<',
|
||||
isAuthEdit: '<',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -18,6 +18,15 @@ class KubernetesRedeployAppGitFormController {
|
|||
redeployInProgress: false,
|
||||
showConfig: false,
|
||||
isEdit: false,
|
||||
|
||||
// isAuthEdit is used to preserve the editing state of the AuthFieldset component.
|
||||
// Within the stack editing page, users have the option to turn the AuthFieldset on or off
|
||||
// and save the stack setting. If the user enables the AuthFieldset, it implies that they
|
||||
// must input new Git authentication, rather than edit existing authentication. Thus,
|
||||
// a dedicated state tracker is required to differentiate between the editing state of
|
||||
// AuthFieldset component and the whole stack
|
||||
// When isAuthEdit is true, PAT field needs to be validated.
|
||||
isAuthEdit: false,
|
||||
hasUnsavedChanges: false,
|
||||
baseWebhookUrl: baseStackWebhookUrl(),
|
||||
webhookId: createWebhookId(),
|
||||
|
@ -121,6 +130,13 @@ class KubernetesRedeployAppGitFormController {
|
|||
await this.StackService.updateKubeStack({ EndpointId: this.stack.EndpointId, Id: this.stack.Id }, { gitConfig: this.formValues, webhookId: this.state.webhookId });
|
||||
this.savedFormValues = angular.copy(this.formValues);
|
||||
this.state.hasUnsavedChanges = false;
|
||||
|
||||
if (!(this.stack.GitConfig && this.stack.GitConfig.Authentication)) {
|
||||
// update the AuthFieldset setting
|
||||
this.state.isAuthEdit = false;
|
||||
this.formValues.RepositoryUsername = '';
|
||||
this.formValues.RepositoryPassword = '';
|
||||
}
|
||||
this.Notifications.success('Success', 'Save stack settings successfully');
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to save application settings');
|
||||
|
@ -139,14 +155,17 @@ class KubernetesRedeployAppGitFormController {
|
|||
|
||||
this.formValues.AutoUpdate = parseAutoUpdateResponse(this.stack.AutoUpdate);
|
||||
|
||||
if (this.stack.AutoUpdate.Webhook) {
|
||||
if (this.stack.AutoUpdate && this.stack.AutoUpdate.Webhook) {
|
||||
this.state.webhookId = this.stack.AutoUpdate.Webhook;
|
||||
}
|
||||
|
||||
if (this.stack.GitConfig && this.stack.GitConfig.Authentication) {
|
||||
this.formValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username;
|
||||
this.formValues.RepositoryPassword = this.stack.GitConfig.Authentication.Password;
|
||||
|
||||
this.formValues.RepositoryAuthentication = true;
|
||||
this.state.isEdit = true;
|
||||
this.state.isAuthEdit = true;
|
||||
}
|
||||
|
||||
this.savedFormValues = angular.copy(this.formValues);
|
||||
|
|
|
@ -35,6 +35,14 @@
|
|||
is-url-valid="true"
|
||||
></git-form-ref-field>
|
||||
|
||||
<git-form-auth-fieldset
|
||||
ng-if="$ctrl.state.showConfig"
|
||||
value="$ctrl.formValues"
|
||||
on-change="($ctrl.onChangeGitAuth)"
|
||||
is-auth-explanation-visible="true"
|
||||
is-auth-edit="$ctrl.state.isAuthEdit"
|
||||
></git-form-auth-fieldset>
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Actions </div>
|
||||
<!-- #Git buttons -->
|
||||
<button
|
||||
|
|
|
@ -21,6 +21,15 @@ class StackRedeployGitFormController {
|
|||
redeployInProgress: false,
|
||||
showConfig: false,
|
||||
isEdit: false,
|
||||
|
||||
// isAuthEdit is used to preserve the editing state of the AuthFieldset component.
|
||||
// Within the stack editing page, users have the option to turn the AuthFieldset on or off
|
||||
// and save the stack setting. If the user enables the AuthFieldset, it implies that they
|
||||
// must input new Git authentication, rather than edit existing authentication. Thus,
|
||||
// a dedicated state tracker is required to differentiate between the editing state of
|
||||
// AuthFieldset component and the whole stack
|
||||
// When isAuthEdit is true, PAT field needs to be validated.
|
||||
isAuthEdit: false,
|
||||
hasUnsavedChanges: false,
|
||||
baseWebhookUrl: baseStackWebhookUrl(),
|
||||
webhookId: createWebhookId(),
|
||||
|
@ -140,6 +149,12 @@ class StackRedeployGitFormController {
|
|||
this.state.hasUnsavedChanges = false;
|
||||
this.Notifications.success('Success', 'Save stack settings successfully');
|
||||
|
||||
if (!(this.stack.GitConfig && this.stack.GitConfig.Authentication)) {
|
||||
// update the AuthFieldset setting
|
||||
this.state.isAuthEdit = false;
|
||||
this.formValues.RepositoryUsername = '';
|
||||
this.formValues.RepositoryPassword = '';
|
||||
}
|
||||
this.stack = stack;
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to save stack settings');
|
||||
|
@ -188,8 +203,10 @@ class StackRedeployGitFormController {
|
|||
|
||||
if (this.stack.GitConfig && this.stack.GitConfig.Authentication) {
|
||||
this.formValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username;
|
||||
this.formValues.RepositoryPassword = this.stack.GitConfig.Authentication.Password;
|
||||
this.formValues.RepositoryAuthentication = true;
|
||||
this.state.isEdit = true;
|
||||
this.state.isAuthEdit = true;
|
||||
}
|
||||
|
||||
this.savedFormValues = angular.copy(this.formValues);
|
||||
|
|
|
@ -37,7 +37,13 @@
|
|||
is-url-valid="true"
|
||||
stack-id="$ctrl.gitStackId"
|
||||
></git-form-ref-field>
|
||||
<git-form-auth-fieldset ng-if="$ctrl.state.showConfig" value="$ctrl.formValues" on-change="($ctrl.onChangeGitAuth)" is-auth-explanation-visible="true"></git-form-auth-fieldset>
|
||||
<git-form-auth-fieldset
|
||||
ng-if="$ctrl.state.showConfig"
|
||||
value="$ctrl.formValues"
|
||||
on-change="($ctrl.onChangeGitAuth)"
|
||||
is-auth-explanation-visible="true"
|
||||
is-auth-edit="$ctrl.state.isAuthEdit"
|
||||
></git-form-auth-fieldset>
|
||||
|
||||
<environment-variables-panel
|
||||
ng-model="$ctrl.formValues.Env"
|
||||
|
|
|
@ -56,7 +56,7 @@ export const gitFormModule = angular
|
|||
'reactGitFormAuthFieldset',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(AuthFieldset))), [
|
||||
'value',
|
||||
'isExplanationVisible',
|
||||
'isAuthExplanationVisible',
|
||||
'onChange',
|
||||
'errors',
|
||||
])
|
||||
|
|
|
@ -18,14 +18,14 @@ import { NewCredentialForm } from './NewCredentialForm';
|
|||
interface Props {
|
||||
value: GitAuthModel;
|
||||
onChange: (value: Partial<GitAuthModel>) => void;
|
||||
isExplanationVisible?: boolean;
|
||||
isAuthExplanationVisible?: boolean;
|
||||
errors?: FormikErrors<GitAuthModel>;
|
||||
}
|
||||
|
||||
export function AuthFieldset({
|
||||
value,
|
||||
onChange,
|
||||
isExplanationVisible,
|
||||
isAuthExplanationVisible,
|
||||
errors,
|
||||
}: Props) {
|
||||
const [username, setUsername] = useDebounce(
|
||||
|
@ -56,7 +56,7 @@ export function AuthFieldset({
|
|||
|
||||
{value.RepositoryAuthentication && (
|
||||
<>
|
||||
{isExplanationVisible && (
|
||||
{isAuthExplanationVisible && (
|
||||
<TextTip color="orange">
|
||||
Enabling authentication will store the credentials and it is
|
||||
advisable to use a git service account
|
||||
|
@ -143,7 +143,8 @@ export function AuthFieldset({
|
|||
}
|
||||
|
||||
export function gitAuthValidation(
|
||||
gitCredentials: Array<GitCredential>
|
||||
gitCredentials: Array<GitCredential>,
|
||||
isAuthEdit: boolean
|
||||
): SchemaOf<GitAuthModel> {
|
||||
return object({
|
||||
RepositoryAuthentication: boolean().default(false),
|
||||
|
@ -156,7 +157,7 @@ export function gitAuthValidation(
|
|||
.default(''),
|
||||
RepositoryPassword: string()
|
||||
.when(['RepositoryAuthentication', 'RepositoryGitCredentialID'], {
|
||||
is: (auth: boolean, id: number) => auth && !id,
|
||||
is: (auth: boolean, id: number) => auth && !id && !isAuthEdit,
|
||||
then: string().required('Password is required'),
|
||||
})
|
||||
.default(''),
|
||||
|
|
|
@ -51,7 +51,7 @@ export function GitForm({
|
|||
<AuthFieldset
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
isExplanationVisible={isAuthExplanationVisible}
|
||||
isAuthExplanationVisible={isAuthExplanationVisible}
|
||||
errors={errors}
|
||||
/>
|
||||
|
||||
|
@ -162,5 +162,5 @@ export function buildGitValidationSchema(
|
|||
RepositoryURLValid: boolean().default(false),
|
||||
AutoUpdate: autoUpdateValidation().nullable(),
|
||||
TLSSkipVerify: boolean().default(false),
|
||||
}).concat(gitAuthValidation(gitCredentials));
|
||||
}).concat(gitAuthValidation(gitCredentials, false));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue