Files
sure/test/models/provider
AnthonyandClaude Opus 5 9ec28abacc fix(wise): refuse an SCA private key when encryption is unavailable (#3415)
* fix(wise): refuse an SCA private key when encryption is unavailable

WiseItem wraps its `encrypts` declarations in `if encryption_ready?`, which is
false on any install that has not explicitly configured Active Record
encryption. On those installs the declaration never runs, so assigning
sca_private_key writes the PEM into the column verbatim.

That is a tolerable degraded mode for a display name. It is not one for the key
that signs Wise balance-statement requests, and nothing in the flow told the
user it had happened: the panel reported a keypair as generated either way.

generate_sca_keypair! now raises SCAEncryptionUnavailable instead of writing,
and a validation refuses the attribute on every other write path. The exception
is raised rather than returned so no caller can read "not stored" as "stored".
WiseItemsController#generate_sca_keypair already rescues broadly, so the user
sees the same panel error as any other keypair failure rather than a 500.

The three existing tests that generate a keypair now stub encryption_ready? to
true. The test environment configures no encryption keys, so without the stub
they would be exercising the refused path rather than the one they describe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wise): validate the SCA key only when it is being written

Review found a real regression in the first commit, and CI found a scanner hit.

The validation ran on every save. An install that generated a key before this
change still has that plaintext value in the column, so the record became
permanently unsaveable: renaming the connection failed, and the destroy path
failed worse. WiseItemsController#destroy calls unlink_all! and only then
destroy_later, whose update!(scheduled_for_deletion: true) would now raise, so
the accounts were already unlinked while the provider stayed active. Refusing a
NEW key is the point; refusing to let go of an old one is not. The validation
now returns unless sca_private_key is actually changing, and the explicit guard
in generate_sca_keypair! is unchanged.

The regression test fails without the guard, on the reload-and-save assertion.

pipelock flagged the literal "BEGIN RSA PRIVATE KEY" header in the test as a
critical Private Key Header finding in the diff, which is exactly what a secret
scanner should do. The value only ever needed to be non-blank, and the file
already uses a plain placeholder two tests above, so it now uses one too.

Also adds the encrypted-attributes assertion the other Encryptable models carry,
in their shape: it skips when encryption is unconfigured, because the suite
deliberately runs that way (see EncryptionVerificationTest's own comment) and
turning ENV-based encryption on globally would change encryption_ready? for
every Encryptable model, well outside this change.

49 Wise tests green, 1 skipped by that convention. Rubocop clean, Brakeman 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 08:17:40 +02:00
..