diff --git a/.changeset/tricky-jobs-clap.md b/.changeset/tricky-jobs-clap.md new file mode 100644 index 0000000000..e773a888c7 --- /dev/null +++ b/.changeset/tricky-jobs-clap.md @@ -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 }} +``` diff --git a/plugins/scaffolder-react/api-report-alpha.md b/plugins/scaffolder-react/api-report-alpha.md index 683b8cf8be..4655cbfd62 100644 --- a/plugins/scaffolder-react/api-report-alpha.md +++ b/plugins/scaffolder-react/api-report-alpha.md @@ -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, +) => React_2.JSX.Element; + // @alpha export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; diff --git a/plugins/scaffolder-react/src/next/components/PasswordWidget/PasswordWidget.tsx b/plugins/scaffolder-react/src/next/components/PasswordWidget/PasswordWidget.tsx new file mode 100644 index 0000000000..6c1c2c176f --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/PasswordWidget/PasswordWidget.tsx @@ -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, +) => { + const { + value, + onChange, + schema: { title }, + } = props; + + return ( + <> + {title} + { + onChange(e.target.value); + }} + value={value} + autoComplete="off" + /> + + + + + ); +}; diff --git a/plugins/scaffolder-react/src/next/components/SecretWidget/SecretWidget.tsx b/plugins/scaffolder-react/src/next/components/SecretWidget/SecretWidget.tsx new file mode 100644 index 0000000000..e2d139f98b --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/SecretWidget/SecretWidget.tsx @@ -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, +) => { + const { setSecrets, secrets } = useTemplateSecrets(); + const { + name, + onChange, + schema: { title }, + } = props; + + return ( + <> + {title} + { + onChange(Array(e.target?.value.length).fill('*').join('')); + setSecrets({ [name]: e.target?.value }); + }} + value={secrets[name] ?? ''} + type="password" + autoComplete="off" + /> + + ); +}; diff --git a/plugins/scaffolder-react/src/next/components/SecretWidget/index.ts b/plugins/scaffolder-react/src/next/components/SecretWidget/index.ts new file mode 100644 index 0000000000..9f0964516c --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/SecretWidget/index.ts @@ -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'; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 5bfdf1a44a..269b6a11d5 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -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', }} diff --git a/plugins/scaffolder-react/src/next/components/index.ts b/plugins/scaffolder-react/src/next/components/index.ts index 119f983a9f..02f00bb1a8 100644 --- a/plugins/scaffolder-react/src/next/components/index.ts +++ b/plugins/scaffolder-react/src/next/components/index.ts @@ -26,3 +26,4 @@ export * from './TaskLogStream'; export * from './TemplateCategoryPicker'; export * from './ScaffolderPageContextMenu'; export * from './ScaffolderField'; +export * from './SecretWidget'; diff --git a/plugins/scaffolder/src/components/fields/SecretInput/SecretInput.tsx b/plugins/scaffolder/src/components/fields/SecretInput/SecretInput.tsx index aac0cf809a..a588286d97 100644 --- a/plugins/scaffolder/src/components/fields/SecretInput/SecretInput.tsx +++ b/plugins/scaffolder/src/components/fields/SecretInput/SecretInput.tsx @@ -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} > - {title} - { - onChange(Array(e.target?.value.length).fill('*').join('')); - setSecrets({ [name]: e.target?.value }); - }} - value={secrets[name] ?? ''} - type="password" - autoComplete="off" - /> + ); };