You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/01 23:30:41 UTC
(superset) 01/01: fix(databases): do not render existing encrypted field value in edit mode
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch fix/encrypted-field-no-render-existing
in repository https://gitbox.apache.org/repos/asf/superset.git
commit e43cf09181ca84ad5e94d183f554b106bb6ee955
Author: Claude Code <no...@anthropic.com>
AuthorDate: Mon Jun 1 16:28:29 2026 -0700
fix(databases): do not render existing encrypted field value in edit mode
In edit mode the backend may return the existing credential for an
encrypted field (e.g. service_account_info / credentials_info) via
`db.parameters`. The component derived its displayed value from that
parameter, so the value was placed into the DOM on the first render
before the mount effect cleared the parameter.
Initialize the displayed value to an empty string in edit mode so an
existing credential is never rendered. Users must re-enter credentials
to change them, which is consistent with the existing clear-on-mount
behavior. The create/copy-paste flow continues to serialize and display
typed values as before.
Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
.../DatabaseConnectionForm/EncryptedField.test.tsx | 52 ++++++++++++++++------
.../DatabaseConnectionForm/EncryptedField.tsx | 12 +++--
2 files changed, 48 insertions(+), 16 deletions(-)
diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.test.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.test.tsx
index ce12f75945f..7a8512bba53 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.test.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.test.tsx
@@ -145,21 +145,42 @@ describe('EncryptedField', () => {
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Parameter Value Processing', () => {
- const testCases = [
+ // In edit mode the existing credential value must never be rendered into
+ // the field, regardless of how it was returned from the backend.
+ const editModeInputs = [
{
input: { key: 'value', nested: { data: 'test' } },
- expected: '{"key":"value","nested":{"data":"test"}}',
- description: 'objects to JSON strings',
+ description: 'objects',
},
- {
- input: true,
- expected: 'true',
- description: 'booleans to strings',
+ { input: true, description: 'booleans' },
+ { input: false, description: 'false booleans' },
+ { input: 'test-string', description: 'strings' },
+ { input: 123, description: 'numbers' },
+ ];
+
+ test.each(editModeInputs)(
+ 'does not render existing $description in edit mode',
+ ({ input }) => {
+ const mockDb = createMockDb('gsheets', {
+ service_account_info: input,
+ });
+ const props = { ...defaultProps, db: mockDb, isEditMode: true };
+
+ const { container } = render(<EncryptedField {...props} />);
+ const textarea = container.querySelector('textarea');
+
+ expect(textarea?.value).toBe('');
},
+ );
+
+ // The copy/paste (create) flow is controlled by the parent, which echoes
+ // typed content back through `db.parameters`. Verify that values are still
+ // serialized for display when not in edit mode.
+ const createModeCases = [
{
- input: false,
- expected: 'false',
- description: 'false booleans to strings',
+ input: { key: 'value', nested: { data: 'test' } },
+ expected: '{"key":"value","nested":{"data":"test"}}',
+ description: 'objects to JSON strings',
},
{
input: 'test-string',
@@ -173,13 +194,18 @@ describe('EncryptedField', () => {
},
];
- test.each(testCases)(
- 'processes $description correctly',
+ test.each(createModeCases)(
+ 'processes $description correctly in create mode',
({ input, expected }) => {
const mockDb = createMockDb('gsheets', {
service_account_info: input,
});
- const props = { ...defaultProps, db: mockDb, isEditMode: true };
+ const props = {
+ ...defaultProps,
+ db: mockDb,
+ isEditMode: false,
+ editNewDb: true,
+ };
const { container } = render(<EncryptedField {...props} />);
const textarea = container.querySelector('textarea');
diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx
index cd21f730a9a..1ba747846ed 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx
@@ -63,10 +63,16 @@ export const EncryptedField = ({
encryptedCredentialsMap[db.engine as keyof typeof encryptedCredentialsMap];
const paramValue =
db?.parameters?.[encryptedField as keyof DatabaseParameters];
+ // In edit mode the backend may return the existing (masked) credential in
+ // the parameters. Do not surface any pre-existing value in the field; the
+ // user must re-enter credentials to change them. This also matches the
+ // mount effect below, which resets the parameter to an empty string.
const encryptedValue =
- paramValue && typeof paramValue === 'object'
- ? JSON.stringify(paramValue)
- : paramValue;
+ isEditMode || !paramValue
+ ? ''
+ : typeof paramValue === 'object'
+ ? JSON.stringify(paramValue)
+ : paramValue;
const readTextFile = (file: File): Promise<string> =>
new Promise((resolve, reject) => {