From 83b2b60f4bbf023d2c702e896da99c50d1e20c16 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 20 May 2024 14:09:36 +0200 Subject: [PATCH 1/6] feat: move around the secret widget and override the default password one Signed-off-by: blam --- .../components/SecretWidget/SecretWidget.tsx | 53 +++++++++++++++++++ .../src/next/components/SecretWidget/index.ts | 16 ++++++ .../src/next/components/Stepper/Stepper.tsx | 4 +- .../src/next/components/index.ts | 1 + .../fields/SecretInput/SecretInput.tsx | 26 +++------ 5 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 plugins/scaffolder-react/src/next/components/SecretWidget/SecretWidget.tsx create mode 100644 plugins/scaffolder-react/src/next/components/SecretWidget/index.ts 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..00232e2cd7 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 { SecretWidget } from '../SecretWidget'; const useStyles = makeStyles(theme => ({ backButton: { @@ -232,6 +233,7 @@ export const Stepper = (stepperProps: StepperProps) => { showErrorList="top" templates={{ ErrorListTemplate }} onChange={handleChange} + widgets={{ password: SecretWidget }} 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" - /> + ); }; From 62bd9ebfe3e69b5206f2a61a3297ab5a05ff8713 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 20 May 2024 14:10:35 +0200 Subject: [PATCH 2/6] chore: added changeset Signed-off-by: blam --- .changeset/tricky-jobs-clap.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/tricky-jobs-clap.md diff --git a/.changeset/tricky-jobs-clap.md b/.changeset/tricky-jobs-clap.md new file mode 100644 index 0000000000..c11acc7318 --- /dev/null +++ b/.changeset/tricky-jobs-clap.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': minor +'@backstage/plugin-scaffolder': minor +--- + +Replace `ui:widget: password` with the `ui:field: Secret` implementation From 504661ab093ad05e68fdc5c04c76f4ba486ad8fa Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 14 Jun 2024 11:07:46 +0200 Subject: [PATCH 3/6] chore: show an error for now, do not replace Signed-off-by: blam --- .../PasswordWidget/PasswordWidget.tsx | 53 +++++++++++++++++++ .../src/next/components/Stepper/Stepper.tsx | 3 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 plugins/scaffolder-react/src/next/components/PasswordWidget/PasswordWidget.tsx 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/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 00232e2cd7..fb950019ef 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -50,6 +50,7 @@ import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { ErrorListTemplate } from './ErrorListTemplate'; import { makeStyles } from '@material-ui/core/styles'; import { SecretWidget } from '../SecretWidget'; +import { PasswordWidget } from '../PasswordWidget/PasswordWidget'; const useStyles = makeStyles(theme => ({ backButton: { @@ -233,7 +234,7 @@ export const Stepper = (stepperProps: StepperProps) => { showErrorList="top" templates={{ ErrorListTemplate }} onChange={handleChange} - widgets={{ password: SecretWidget }} + widgets={{ password: PasswordWidget }} experimental_defaultFormStateBehavior={{ allOf: 'populateDefaults', }} From fd8fe4598f063172ccf7e9f79b0c8aeb4d4ce6a0 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 14 Jun 2024 11:12:18 +0200 Subject: [PATCH 4/6] chore: update changeset Signed-off-by: blam --- .changeset/tricky-jobs-clap.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.changeset/tricky-jobs-clap.md b/.changeset/tricky-jobs-clap.md index c11acc7318..e773a888c7 100644 --- a/.changeset/tricky-jobs-clap.md +++ b/.changeset/tricky-jobs-clap.md @@ -3,4 +3,32 @@ '@backstage/plugin-scaffolder': minor --- -Replace `ui:widget: password` with the `ui:field: Secret` implementation +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 }} +``` From 7d652f33bc55af88d58adf5496179fda8a27bf6b Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 14 Jun 2024 12:46:11 +0200 Subject: [PATCH 5/6] chore: fixing typescript Signed-off-by: blam --- plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index fb950019ef..269b6a11d5 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -49,7 +49,6 @@ import { import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { ErrorListTemplate } from './ErrorListTemplate'; import { makeStyles } from '@material-ui/core/styles'; -import { SecretWidget } from '../SecretWidget'; import { PasswordWidget } from '../PasswordWidget/PasswordWidget'; const useStyles = makeStyles(theme => ({ From 3e8b5822dba5e29564799dbe5fe93c171857a925 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 14 Jun 2024 14:02:18 +0200 Subject: [PATCH 6/6] chore: added secret widget export Signed-off-by: blam --- plugins/scaffolder-react/api-report-alpha.md | 6 ++++++ 1 file changed, 6 insertions(+) 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;