Merge pull request #24834 from backstage/blam/replace-password-widget
scaffolder: replace `ui:widget: password` with a warning message
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': minor
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Replace `ui:widget: password` with the a warning message stating that it's not secure and to use the build in `SecretField`.
|
||||
|
||||
You can do this by updating your `template.yaml` files that have the reference `ui:widget: password` to `ui:field: Secret` instead.
|
||||
|
||||
```diff
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Template
|
||||
metadata:
|
||||
...
|
||||
|
||||
spec:
|
||||
parameters:
|
||||
- title: collect some information
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
password:
|
||||
title: Password
|
||||
type: string
|
||||
- ui:widget: password
|
||||
+ ui:field: Secret
|
||||
steps:
|
||||
- id: collect-info
|
||||
name: Collect some information
|
||||
action: acme:do:something
|
||||
input:
|
||||
- password: ${{ parameters.password }}
|
||||
+ password: ${{ secrets.password }}
|
||||
```
|
||||
@@ -33,6 +33,7 @@ import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';
|
||||
import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react';
|
||||
import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { UiSchema } from '@rjsf/utils';
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type BackstageOverrides = Overrides & {
|
||||
@@ -149,6 +150,11 @@ export type ScaffolderReactComponentsNameToClassKey = {
|
||||
// @alpha (undocumented)
|
||||
export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label';
|
||||
|
||||
// @alpha
|
||||
export const SecretWidget: (
|
||||
props: Pick<WidgetProps, 'name' | 'onChange' | 'schema'>,
|
||||
) => React_2.JSX.Element;
|
||||
|
||||
// @alpha
|
||||
export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element;
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import React from 'react';
|
||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||
import { MarkdownContent } from '@backstage/core-components';
|
||||
|
||||
export const PasswordWidget = (
|
||||
props: Pick<WidgetProps, 'onChange' | 'schema' | 'value'>,
|
||||
) => {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
schema: { title },
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<InputLabel htmlFor={title}>{title}</InputLabel>
|
||||
<Input
|
||||
id={title}
|
||||
aria-describedby={title}
|
||||
onChange={e => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
value={value}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<FormHelperText error>
|
||||
<MarkdownContent
|
||||
content="This widget is insecure. Please use [`ui:field: Secret`](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) instead of
|
||||
`ui:widget: password`"
|
||||
/>
|
||||
</FormHelperText>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Secret Widget for overriding the default password input widget
|
||||
* @alpha
|
||||
*/
|
||||
export const SecretWidget = (
|
||||
props: Pick<WidgetProps, 'name' | 'onChange' | 'schema'>,
|
||||
) => {
|
||||
const { setSecrets, secrets } = useTemplateSecrets();
|
||||
const {
|
||||
name,
|
||||
onChange,
|
||||
schema: { title },
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<InputLabel htmlFor={title}>{title}</InputLabel>
|
||||
<Input
|
||||
id={title}
|
||||
aria-describedby={title}
|
||||
onChange={e => {
|
||||
onChange(Array(e.target?.value.length).fill('*').join(''));
|
||||
setSecrets({ [name]: e.target?.value });
|
||||
}}
|
||||
value={secrets[name] ?? ''}
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './SecretWidget';
|
||||
@@ -20,7 +20,6 @@ import MuiStep from '@material-ui/core/Step';
|
||||
import MuiStepLabel from '@material-ui/core/StepLabel';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { type IChangeEvent } from '@rjsf/core';
|
||||
import { ErrorSchema } from '@rjsf/utils';
|
||||
import React, {
|
||||
@@ -49,6 +48,8 @@ import {
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
import { ReviewStepProps } from '@backstage/plugin-scaffolder-react';
|
||||
import { ErrorListTemplate } from './ErrorListTemplate';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { PasswordWidget } from '../PasswordWidget/PasswordWidget';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
backButton: {
|
||||
@@ -232,6 +233,7 @@ export const Stepper = (stepperProps: StepperProps) => {
|
||||
showErrorList="top"
|
||||
templates={{ ErrorListTemplate }}
|
||||
onChange={handleChange}
|
||||
widgets={{ password: PasswordWidget }}
|
||||
experimental_defaultFormStateBehavior={{
|
||||
allOf: 'populateDefaults',
|
||||
}}
|
||||
|
||||
@@ -26,3 +26,4 @@ export * from './TaskLogStream';
|
||||
export * from './TemplateCategoryPicker';
|
||||
export * from './ScaffolderPageContextMenu';
|
||||
export * from './ScaffolderField';
|
||||
export * from './SecretWidget';
|
||||
|
||||
@@ -14,18 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';
|
||||
import { ScaffolderRJSFFieldProps } from '@backstage/plugin-scaffolder-react';
|
||||
import { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import {
|
||||
ScaffolderField,
|
||||
SecretWidget,
|
||||
} from '@backstage/plugin-scaffolder-react/alpha';
|
||||
|
||||
export const SecretInput = (props: ScaffolderRJSFFieldProps) => {
|
||||
const { setSecrets, secrets } = useTemplateSecrets();
|
||||
const {
|
||||
name,
|
||||
onChange,
|
||||
schema: { title, description },
|
||||
schema: { description },
|
||||
rawErrors,
|
||||
disabled,
|
||||
errors,
|
||||
@@ -40,18 +37,7 @@ export const SecretInput = (props: ScaffolderRJSFFieldProps) => {
|
||||
errors={errors}
|
||||
required={required}
|
||||
>
|
||||
<InputLabel htmlFor={title}>{title}</InputLabel>
|
||||
<Input
|
||||
id={title}
|
||||
aria-describedby={title}
|
||||
onChange={e => {
|
||||
onChange(Array(e.target?.value.length).fill('*').join(''));
|
||||
setSecrets({ [name]: e.target?.value });
|
||||
}}
|
||||
value={secrets[name] ?? ''}
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<SecretWidget {...props} />
|
||||
</ScaffolderField>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user