Skip to content

Comments

OCPBUGS-70273: Prevent binary secret data corruption when editing#16053

Open
TheRealJon wants to merge 1 commit intoopenshift:mainfrom
TheRealJon:OCPBUGS-70273
Open

OCPBUGS-70273: Prevent binary secret data corruption when editing#16053
TheRealJon wants to merge 1 commit intoopenshift:mainfrom
TheRealJon:OCPBUGS-70273

Conversation

@TheRealJon
Copy link
Member

@TheRealJon TheRealJon commented Feb 23, 2026

Summary

  • Fixes corruption of binary secret data (JAR, JCEKS files) when editing text fields in the same secret
  • Binary data was being decoded as UTF-8 text, which inserted replacement characters for non-printable bytes

Changes

  • Pass base64 data directly to DroppableFileInput for binary entries instead of decoding as UTF-8
  • Add isBase64Input prop to handle base64-encoded input properly
  • Preserve original binary values when form updates using immutable reducer pattern
  • Use useMemo for derived binaryData value instead of useState
  • Add Cypress regression test to verify editing text fields doesn't corrupt binary data

Test plan

  • Run Cypress test: yarn run test-cypress-headless --spec packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts
  • Verify test "Validate editing text field does not corrupt binary data (OCPBUGS-70273)" passes
  • Manually test: Create secret with binary file, edit text field, verify binary unchanged

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where editing text fields in secrets could corrupt binary data. Binary files now remain unmodified when users update only text content in mixed secrets.
  • Tests

    • Added test coverage validating binary data integrity during secret editing.

When editing secrets containing binary data (JAR, JCEKS, etc), the
binary values were being corrupted by decoding base64 as UTF-8 text,
which inserts replacement characters for non-printable bytes.

Fixed by:
- Pass base64 data directly to DroppableFileInput for binary entries
- Add isBase64Input prop to properly handle base64-encoded input
- Preserve original binary values when form updates to prevent corruption
- Use useMemo instead of useState for derived binaryData value
- Use immutable reducer pattern to merge binary data

Added Cypress test to verify editing text fields doesn't corrupt
binary data in the same secret.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Feb 23, 2026
@openshift-ci-robot
Copy link
Contributor

@TheRealJon: This pull request references Jira Issue OCPBUGS-70273, which is invalid:

  • expected the bug to target the "4.22.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Summary

  • Fixes corruption of binary secret data (JAR, JCEKS files) when editing text fields in the same secret
  • Binary data was being decoded as UTF-8 text, which inserted replacement characters for non-printable bytes

Changes

  • Pass base64 data directly to DroppableFileInput for binary entries instead of decoding as UTF-8
  • Add isBase64Input prop to handle base64-encoded input properly
  • Preserve original binary values when form updates using immutable reducer pattern
  • Use useMemo for derived binaryData value instead of useState
  • Add Cypress regression test to verify editing text fields doesn't corrupt binary data

Test plan

  • Run Cypress test: yarn run test-cypress-headless --spec packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts
  • Verify test "Validate editing text field does not corrupt binary data (OCPBUGS-70273)" passes
  • Manually test: Create secret with binary file, edit text field, verify binary unchanged

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from cajieh and sg00dwin February 23, 2026 20:48
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 23, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: TheRealJon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added component/core Related to console core functionality kind/cypress Related to Cypress e2e integration testing approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Feb 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

This change addresses a bug where editing text fields in mixed secrets corrupted binary data. The fix introduces a new isBase64Input prop to the DroppableFileInput component to distinguish between base64-encoded and binary data. SecretFormWrapper now uses memoization to preserve binary fields during text edits, merging them with updated base64 data rather than replacing them entirely. OpaqueSecretFormEntry conditionally passes decoded or raw data based on the binary flag. A Cypress test validates the fix by confirming binary data remains intact after text-field edits.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: preventing binary secret data corruption when editing. It references the bug ticket and accurately reflects the core problem being fixed across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts (1)

161-215: Make mixed-secret cleanup resilient to mid-test failures.

Cleanup happens only at the end of the test body, so any earlier failure leaves the mixed secret behind. Consider moving that deletion into afterEach alongside other secret cleanup.

♻️ Suggested refactor
-  const tlsSecretName = `key-value-tls-secret-${testName}`;
+  const tlsSecretName = `key-value-tls-secret-${testName}`;
+  const mixedSecretName = `key-value-mixed-secret-${testName}`;
@@
-    cy.exec(
-      `oc delete secret -n ${testName} ${binarySecretName} ${asciiSecretName} ${unicodeSecretName}`,
+    cy.exec(
+      `oc delete secret -n ${testName} ${binarySecretName} ${asciiSecretName} ${unicodeSecretName} ${mixedSecretName}`,
       {
         failOnNonZeroExit: false,
       },
     );
@@
-    const mixedSecretName = `key-value-mixed-secret-${testName}`;
@@
-      // Cleanup
-      cy.exec(`oc delete secret -n ${testName} ${mixedSecretName}`, {
-        failOnNonZeroExit: false,
-      });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts`
around lines 161 - 215, The test currently only deletes mixedSecretName at the
end of the test body, leaving the secret if the test fails mid-run; fix by
declaring mixedSecretName (and any related keys) in the outer scope (e.g., let
mixedSecretName = ``) so it is accessible to hooks, assign it inside the it(...)
block, and add an afterEach hook that runs cy.exec(`oc delete secret -n
${testName} ${mixedSecretName}`, { failOnNonZeroExit: false }) to reliably clean
up the secret regardless of test outcome; ensure the afterEach uses the same
mixedSecretName symbol and keeps failOnNonZeroExit: false for idempotent
deletion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx`:
- Around line 87-101: The merge in onDataChanged currently overwrites edited
binary entries by replacing keys present in secretsData?.base64StringData with
values from binaryData; change the merge so it only backfills missing keys:
iterate binaryData entries and for each [key,value] if acc[key] is undefined (or
not present) then set acc[key]=value, otherwise keep the existing acc[key]; then
call setBase64StringData with that merged result. Reference onDataChanged,
setStringData, binaryData, secretsData?.base64StringData, mergedData, and
setBase64StringData to locate and update the logic.

---

Nitpick comments:
In
`@frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts`:
- Around line 161-215: The test currently only deletes mixedSecretName at the
end of the test body, leaving the secret if the test fails mid-run; fix by
declaring mixedSecretName (and any related keys) in the outer scope (e.g., let
mixedSecretName = ``) so it is accessible to hooks, assign it inside the it(...)
block, and add an afterEach hook that runs cy.exec(`oc delete secret -n
${testName} ${mixedSecretName}`, { failOnNonZeroExit: false }) to reliably clean
up the secret regardless of test outcome; ensure the afterEach uses the same
mixedSecretName symbol and keeps failOnNonZeroExit: false for idempotent
deletion.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c305cad and dbbd532.

📒 Files selected for processing (4)
  • frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts
  • frontend/public/components/secrets/create-secret/OpaqueSecretFormEntry.tsx
  • frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx
  • frontend/public/components/utils/file-input.tsx

Comment on lines 87 to +101
const onDataChanged = (secretsData) => {
setStringData({ ...secretsData?.stringData });
setBase64StringData({ ...secretsData?.base64StringData });
// Preserve binary values by merging them with form data
// This prevents corruption of binary data when editing other fields
const mergedData = Object.entries(binaryData).reduce(
(acc, [key, value]) => {
// If the binary entry still exists in the form data (same key), preserve its value
if (acc[key]) {
return { ...acc, [key]: value };
}
return acc;
},
{ ...secretsData?.base64StringData },
);
setBase64StringData(mergedData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid clobbering edited binary entries when merging.

The current merge overwrites any key present in secretsData.base64StringData, which means a user’s updated binary upload (or a conversion to text) will be replaced by the original binary value. That makes binary updates impossible and can lose user edits. Backfill only missing keys instead.

🔧 Suggested fix (only backfill missing keys)
-    const mergedData = Object.entries(binaryData).reduce(
-      (acc, [key, value]) => {
-        // If the binary entry still exists in the form data (same key), preserve its value
-        if (acc[key]) {
-          return { ...acc, [key]: value };
-        }
-        return acc;
-      },
-      { ...secretsData?.base64StringData },
-    );
+    const mergedData = { ...(secretsData?.base64StringData ?? {}) };
+    for (const [key, value] of Object.entries(binaryData)) {
+      if (!Object.prototype.hasOwnProperty.call(mergedData, key)) {
+        mergedData[key] = value;
+      }
+    }
     setBase64StringData(mergedData);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const onDataChanged = (secretsData) => {
setStringData({ ...secretsData?.stringData });
setBase64StringData({ ...secretsData?.base64StringData });
// Preserve binary values by merging them with form data
// This prevents corruption of binary data when editing other fields
const mergedData = Object.entries(binaryData).reduce(
(acc, [key, value]) => {
// If the binary entry still exists in the form data (same key), preserve its value
if (acc[key]) {
return { ...acc, [key]: value };
}
return acc;
},
{ ...secretsData?.base64StringData },
);
setBase64StringData(mergedData);
const onDataChanged = (secretsData) => {
setStringData({ ...secretsData?.stringData });
// Preserve binary values by merging them with form data
// This prevents corruption of binary data when editing other fields
const mergedData = { ...(secretsData?.base64StringData ?? {}) };
for (const [key, value] of Object.entries(binaryData)) {
if (!Object.prototype.hasOwnProperty.call(mergedData, key)) {
mergedData[key] = value;
}
}
setBase64StringData(mergedData);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx`
around lines 87 - 101, The merge in onDataChanged currently overwrites edited
binary entries by replacing keys present in secretsData?.base64StringData with
values from binaryData; change the merge so it only backfills missing keys:
iterate binaryData entries and for each [key,value] if acc[key] is undefined (or
not present) then set acc[key]=value, otherwise keep the existing acc[key]; then
call setBase64StringData with that merged result. Reference onDataChanged,
setStringData, binaryData, secretsData?.base64StringData, mergedData, and
setBase64StringData to locate and update the logic.

@TheRealJon
Copy link
Member Author

/retest

timed out

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 24, 2026

@TheRealJon: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-console dbbd532 link true /test e2e-gcp-console

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. kind/cypress Related to Cypress e2e integration testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants