feat(cryptography): add PGP support for encryption, decryption, signing, and verification#514
Conversation
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs
Fixed
Show fixed
Hide fixed
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs
Fixed
Show fixed
Hide fixed
Address SonarQube S5445 findings from PR #514 — Path.GetTempFileName() is insecure (predictable names, race conditions) and can throw when >65535 temp files exist. Replaced all 19 occurrences in PgpStandaloneTests and PgpTests with Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()). Also updated code-reviewer and software-engineer agent prompts to catch this pattern and the false-positive enum rename breaking change in future reviews. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive PGP (Pretty Good Privacy) cryptography support to the UiPath Cryptography activity pack, significantly expanding its capabilities beyond symmetric encryption algorithms. The implementation integrates PgpCore 6.5.3 and adds 4 new activities while extending 4 existing activities to support PGP operations.
Changes:
- Added PGP algorithm option to existing EncryptFile, DecryptFile, EncryptText, DecryptText activities with dynamic UI toggling
- Added 4 new PGP activities: PgpGenerateKeyPair, PgpSignFile, PgpClearSignFile, and unified PgpVerify
- Renamed
SymmetricAlgorithmsenum toEncryptionAlgorithmto reflect broader scope (PGP is asymmetric) - Added helper classes for PGP stream/resource management and unified file signing logic
- Added comprehensive test coverage (PgpTests and PgpStandaloneTests)
- Fixed pre-existing bug in DecryptText.cs where ContinueOnError description pointed to Result_Description
Reviewed changes
Copilot reviewed 36 out of 42 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| UiPath.Cryptography.csproj | Added PgpCore 6.5.3 dependency and CopyLocalLockFileAssemblies flag |
| EncryptionAlgorithm.cs | Renamed from SymmetricAlgorithms.cs, added PGP enum member |
| CryptographyHelper.cs | Added PGP methods for encrypt/decrypt/sign/verify with exception translation |
| PgpStreamHelper.cs | Helper class for managing PGP key file streams and SecureString conversion |
| PgpFileSignHelper.cs | Shared logic for PgpSignFile and PgpClearSignFile activities |
| Pgp*.cs (4 activities) | New activities for key generation, signing, and verification |
| Encrypt/Decrypt*.cs (4 files) | Extended with PGP support using ViewModel-driven visibility rules |
| *ViewModel.cs (8 files) | ViewModels for all new and modified activities with dynamic property visibility |
| ActivitiesMetadata.json | Metadata entries for all PGP properties and activities |
| *.resx | Resource strings for PGP errors, modes, and property descriptions |
| Test files | Comprehensive unit and integration tests for all PGP functionality |
| Packaging | Added PgpCore and BouncyCastle DLLs to package output |
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Activities/Cryptography/UiPath.Cryptography.Activities/Resources/ActivitiesMetadata.json
Outdated
Show resolved
Hide resolved
sorinconstantin
left a comment
There was a problem hiding this comment.
nit: LocalizedDescriptionAttribute usage on properties is redundant when view models exist. LocalizedDisplayName should also be used only for properties marked as Required, so the validation message is pointing to the correct display name of a localized property
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 44 changed files in this pull request and generated 11 comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/DecryptCryptoViewModelBase.cs
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/EncryptFile.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography/CryptographyHelper.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography/CryptographyHelper.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/Helpers/PgpStreamHelper.cs
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/Helpers/PgpStreamHelper.cs
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/DecryptFile.cs
Outdated
Show resolved
Hide resolved
...Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/EncryptCryptoViewModelBase.cs
Show resolved
Hide resolved
- Remove duplicate File.WriteAllBytes in EncryptFile/DecryptFile (CryptographyLocalItem constructor already writes) - Clear Key/KeySecureString IsRequired flags when switching to PGP algorithm in both Encrypt/Decrypt ViewModels - Move EncryptionKeys construction inside try blocks for consistent error translation - Use string.IsNullOrEmpty for passphrase checks instead of null-only - Preserve stack traces via ExceptionDispatchInfo when PGP exceptions are not translated - Add File.Exists validation with localized errors in PgpStreamHelper before File.OpenRead - Remove unused using System.IO from EncryptText.cs and DecryptText.cs - Fix IsPrincipal metadata inconsistency for Result in EncryptText/DecryptText - Remove redundant LocalizedDisplayName/LocalizedDescription from non-required PGP properties Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 44 changed files in this pull request and generated no new comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 44 changed files in this pull request and generated 6 comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Activities/Cryptography/UiPath.Cryptography/CryptographyHelper.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography/CryptographyHelper.cs
Outdated
Show resolved
Hide resolved
Address SonarQube S5445 findings from PR #514 — Path.GetTempFileName() is insecure (predictable names, race conditions) and can throw when >65535 temp files exist. Replaced all 19 occurrences in PgpStandaloneTests and PgpTests with Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()). Also updated code-reviewer and software-engineer agent prompts to catch this pattern and the false-positive enum rename breaking change in future reviews. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove duplicate File.WriteAllBytes in EncryptFile/DecryptFile (CryptographyLocalItem constructor already writes) - Clear Key/KeySecureString IsRequired flags when switching to PGP algorithm in both Encrypt/Decrypt ViewModels - Move EncryptionKeys construction inside try blocks for consistent error translation - Use string.IsNullOrEmpty for passphrase checks instead of null-only - Preserve stack traces via ExceptionDispatchInfo when PGP exceptions are not translated - Add File.Exists validation with localized errors in PgpStreamHelper before File.OpenRead - Remove unused using System.IO from EncryptText.cs and DecryptText.cs - Fix IsPrincipal metadata inconsistency for Result in EncryptText/DecryptText - Remove redundant LocalizedDisplayName/LocalizedDescription from non-required PGP properties Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
a2df16a to
a5849f2
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 43 changed files in this pull request and generated 4 comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Activities/Cryptography/UiPath.Cryptography.Activities/Resources/ActivitiesMetadata.json
Show resolved
Hide resolved
- Add LocalizedDisplayName/LocalizedDescription attributes to PGP properties in EncryptFile, DecryptFile, EncryptText, DecryptText - Fix typo "backwords" → "backwards" in CryptographyHelper - Wrap publicKeyStream in NonClosingStreamWrapper in PgpVerifyPublicKey to prevent BouncyCastle's decoder from closing the caller's stream - Remove CopyLocalLockFileAssemblies from library project; add PgpCore reference to packaging project instead - Remove static IsRequired from InputFilePath/PublicKeyFilePath in PgpVerify metadata — ViewModel handles this dynamically per Mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 43 changed files in this pull request and generated 4 comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Activities/Cryptography/UiPath.Cryptography.Activities/Helpers/PgpFileSignHelper.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/PgpVerify.cs
Outdated
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/Resources/ActivitiesMetadata.json
Show resolved
Hide resolved
Activities/Cryptography/UiPath.Cryptography.Activities/Helpers/PgpStreamHelper.cs
Show resolved
Hide resolved
…ng, and verification ## Problem The Cryptography activity pack only supported symmetric AES/DES/RC2/Rijndael algorithms. Users needed PGP (asymmetric, key-based) cryptography for encrypting/decrypting files and text, signing files, clear-signing files, verifying signatures, and generating PGP key pairs — all common requirements in enterprise automation workflows. ## Solution Considerations - Extend existing Encrypt/Decrypt activities with a PGP algorithm option rather than creating entirely separate activities, keeping the API surface minimal. - Create dedicated activities only for PGP-specific operations (sign, clear-sign, verify, generate key pair) that have no symmetric equivalent. - Use PgpCore NuGet package as the underlying PGP implementation. - Share signing logic via PgpFileSignHelper; manage key stream lifecycle via PgpStreamHelper. ## Actual Fix - Extended EncryptFile, DecryptFile, EncryptText, DecryptText with PGP algorithm support (public/private key + optional passphrase). - Added new activities: PgpSignFile, PgpClearSignFile, PgpVerify (unified signature + clear-signature + public-key verification), PgpGenerateKeyPair. - Added ViewModels for all new and modified activities with rule-based visibility toggling between symmetric and PGP property groups. - Added PgpStreamHelper, PgpFileSignHelper, CryptographyLocalItem model, PgpVerifyMode enum, and TranslatePgpException for user-friendly error messages. - Added comprehensive xUnit tests: PgpTests (activity-level round-trips) and PgpStandaloneTests (helper-level tests). - Registered all activities in ActivitiesMetadata.json with icons. ## Caveats - Metadata IsPrincipal mismatch on PgpVerify.Result (cosmetic, ViewModel wins at runtime). - Orphaned resource strings remain for removed intermediate verify activities (cleanup item).
Address SonarQube S5445 findings from PR #514 — Path.GetTempFileName() is insecure (predictable names, race conditions) and can throw when >65535 temp files exist. Replaced all 19 occurrences in PgpStandaloneTests and PgpTests with Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()). Also updated code-reviewer and software-engineer agent prompts to catch this pattern and the false-positive enum rename breaking change in future reviews. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- S2583: Replace unnecessary null-conditional telemetry calls with #if ENABLE_DEFAULT_TELEMETRY blocks in PgpSignFile, PgpClearSignFile, PgpGenerateKeyPair, PgpVerify - S3776: Reduce cognitive complexity by extracting helper methods in EncryptFile, DecryptFile, EncryptText, DecryptText - S3928: Use resource strings instead of nameof() for ArgumentNullException parameter names in PgpGenerateKeyPair, PgpVerify - S1854: Remove dead store increments in all 8 ViewModel files - S3881: Add proper IDisposable pattern in PgpStandaloneTests and PgpTests - S2325: Make GetPassphraseSecureString static in test classes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove duplicate File.WriteAllBytes in EncryptFile/DecryptFile (CryptographyLocalItem constructor already writes) - Clear Key/KeySecureString IsRequired flags when switching to PGP algorithm in both Encrypt/Decrypt ViewModels - Move EncryptionKeys construction inside try blocks for consistent error translation - Use string.IsNullOrEmpty for passphrase checks instead of null-only - Preserve stack traces via ExceptionDispatchInfo when PGP exceptions are not translated - Add File.Exists validation with localized errors in PgpStreamHelper before File.OpenRead - Remove unused using System.IO from EncryptText.cs and DecryptText.cs - Fix IsPrincipal metadata inconsistency for Result in EncryptText/DecryptText - Remove redundant LocalizedDisplayName/LocalizedDescription from non-required PGP properties Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…elds Set IsRequired alongside IsVisible using the same condition expression, making property state easier to reason about at a glance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of silently falling back to unsigned encrypt or unverified decrypt, throw ArgumentException when sign=true without private key/passphrase, or verifySignature=true without public key. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change ThrowTranslatedPgpException (void) to TranslatePgpException (returns Exception) so callers use "throw TranslatePgpException(ex)" and the compiler sees all paths return/throw — removing the "return null; // unreachable" workarounds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add LocalizedDisplayName/LocalizedDescription attributes to PGP properties in EncryptFile, DecryptFile, EncryptText, DecryptText - Fix typo "backwords" → "backwards" in CryptographyHelper - Wrap publicKeyStream in NonClosingStreamWrapper in PgpVerifyPublicKey to prevent BouncyCastle's decoder from closing the caller's stream - Remove CopyLocalLockFileAssemblies from library project; add PgpCore reference to packaging project instead - Remove static IsRequired from InputFilePath/PublicKeyFilePath in PgpVerify metadata — ViewModel handles this dynamically per Mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace nameof(...) with localized resource strings in PgpFileSignHelper and PgpStreamHelper exception parameter names so error messages reference UI field names instead of internal parameter identifiers - Add shared display name resources: PrivateKeyFilePathDisplayName, PublicKeyFilePathDisplayName, PassphraseDisplayName - Add null/whitespace check for inputFilePath in PgpVerify and use PgpVerify-specific display name resource - Restore IsRequired: true for PublicKeyFilePath in PgpVerify metadata (always required per [RequiredArgument] attribute) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5bcd476 to
ba2fe81
Compare
…et dependency Refactor PgpVerify.Execute to reduce cognitive complexity from 16 to 15 by consolidating the File.Exists check and removing the else branch. Declare PgpCore as a PackageReference (NuGet dependency) in the packaging project instead of bundling DLLs, matching the pattern used by other dependencies like System.Security.Cryptography.Cng. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, fix metadata formatting Add null/whitespace check for inputFilePath in PgpFileSignHelper before File.Exists to produce a clear error message. Centralize PgpCore version in Directory.build.targets (matching the pattern for other dependencies). Fix stray trailing comma in ActivitiesMetadata.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 44 changed files in this pull request and generated no new comments.
Files not reviewed (2)
- Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Language not supported
- Activities/Cryptography/UiPath.Cryptography/Properties/UiPath.Cryptography.Designer.cs: Language not supported
Comments suppressed due to low confidence (1)
Activities/Cryptography/UiPath.Cryptography/EncryptionAlgorithm.cs:7
- Renaming the public enum from
SymmetricAlgorithmstoEncryptionAlgorithmis a breaking API change: any external code and, more importantly, existing workflows/XAML serialized with the old enum type name may fail to compile/load. If backward compatibility is required, consider keeping aSymmetricAlgorithmsenum (marked[Obsolete]) or adding a type-forward/serialization remap so older workflows still deserialize, while exposing the new name for new usage.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <EmbeddedResource Include="Resources\Icons\PGP_generate_keys.svg" /> | ||
| <EmbeddedResource Include="Resources\Icons\PGP_sign_file.svg" /> | ||
| <EmbeddedResource Include="Resources\Icons\PGP_clear_sign_file.svg" /> | ||
| <EmbeddedResource Include="Resources\Icons\PGP_verify.svg" /> |
There was a problem hiding this comment.
nit: we can do this with a wild card
| namespace UiPath.Cryptography | ||
| { | ||
| public enum SymmetricAlgorithms | ||
| public enum EncryptionAlgorithm |
There was a problem hiding this comment.
Isn't this a breaking change?
There was a problem hiding this comment.
tl;dr No
explanation: the Algorithm property only accepts a value from the drop-down and that is what we store in the xaml. It could break if the user insists on having a variable/argument of that type and then on upgrade the type is no longer there, but having such a variable makes no sense.


Summary
The Cryptography activity pack only supported symmetric algorithms (AES, DES, RC2, Rijndael). Users needed PGP (asymmetric, key-based) cryptography for encrypting/decrypting files and text, signing files, clear-signing files, verifying signatures, and generating key pairs — common requirements in enterprise automation workflows.
Changes
Extended existing activities (EncryptFile, DecryptFile, EncryptText, DecryptText) with a PGP algorithm option that dynamically shows/hides public key, private key, and passphrase inputs based on the selected algorithm.
Added 4 new activities:
Added helpers:
Reduced ViewModel duplication with shared base classes: EncryptCryptoViewModelBase, DecryptCryptoViewModelBase, and PgpSignViewModelBase.
Added ViewModels for all new and modified activities with full metadata registration and SVG icons.
Added tests: PgpTests (activity-level encrypt/decrypt/sign/verify round-trips) and PgpStandaloneTests (helper-level unit tests), with shared setup extracted into PgpTestBase.
Renamed SymmetricAlgorithms.cs → EncryptionAlgorithm.cs (file rename only — the enum was already named EncryptionAlgorithm).
Bug fixes and cleanup:
return nullworkarounds and preserving original stack traces via ExceptionDispatchInfoUses PgpCore NuGet package (v6.5.3) as the underlying PGP implementation.
43 files changed — 4,655 insertions, 936 deletions.
Test plan
🤖 Generated with Claude Code