diff --git a/CHANGELOG.md b/CHANGELOG.md index 187bd42..199874f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,46 +1,54 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely, but version numbers use the build timestamp format `yyyy.MM.dd.HHmm`. - +# Changelog + +All notable changes to this project will be documented in this file. + +The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely, but version numbers use the build timestamp format `yyyy.MM.dd.HHmm`. + ## Unreleased +## 2026.06.03.0113 + +- Build produced from commit 09c577ebd0fd. +- Added `InfisicalSecret.GetPlainTextValue()` for direct plain-text access to secret material from PowerShell without needing `Marshal.SecureStringToBSTR`. +- Added `-AsPlainText` switch to `ConvertTo-InfisicalSecretDictionary`; when present the cmdlet emits `Dictionary` instead of the default `Dictionary`. + +## Unreleased (carried forward) + ## 2026.06.03.0057 - Build produced from commit 7e5209190ac2. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.03.0056 - Build produced from commit 7e5209190ac2. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.03.0055 - Build produced from commit 7e5209190ac2. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.03.0047 - Build produced from commit 7e5209190ac2. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.03.0046 - Build produced from commit 7e5209190ac2. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.03.0032 - Build produced from commit c86676010532. -## Unreleased (carried forward) +## Unreleased (carried forward) ## 2026.06.02.1907 @@ -802,15 +810,15 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos - Build produced from commit fa65c18bc171. -## Unreleased (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) - -### Added - -- Initial repository skeleton, C# `netstandard2.0` project, and PowerShell module layout. -- Centralized logging (`InfisicalLogger`), error types/handler, sanitizer, path utility, and `SecureString` utility. -- Endpoint registry covering `UniversalAuthLogin`, `ListSecrets`, and `RetrieveSecret`, and a `System.Uri`-based URI builder. -- Synchronous HTTP client, JSON/YAML/XML/ENV serializers, and DTO/mapper for secrets. -- Connection model, process-level session manager, Universal Auth and Token Auth providers. -- Cmdlets: `Connect-Infisical`, `Disconnect-Infisical`, `Get-InfisicalSecrets`, `Get-InfisicalSecret`, `ConvertTo-InfisicalSecretDictionary`, `Export-InfisicalSecrets`. -- Build script (`build.ps1`) generating manifest, copying binaries, creating release folders, and supporting unit/integration tests. -- xUnit test project with unit tests and opt-in integration tests. +## Unreleased (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) (carried forward) + +### Added + +- Initial repository skeleton, C# `netstandard2.0` project, and PowerShell module layout. +- Centralized logging (`InfisicalLogger`), error types/handler, sanitizer, path utility, and `SecureString` utility. +- Endpoint registry covering `UniversalAuthLogin`, `ListSecrets`, and `RetrieveSecret`, and a `System.Uri`-based URI builder. +- Synchronous HTTP client, JSON/YAML/XML/ENV serializers, and DTO/mapper for secrets. +- Connection model, process-level session manager, Universal Auth and Token Auth providers. +- Cmdlets: `Connect-Infisical`, `Disconnect-Infisical`, `Get-InfisicalSecrets`, `Get-InfisicalSecret`, `ConvertTo-InfisicalSecretDictionary`, `Export-InfisicalSecrets`. +- Build script (`build.ps1`) generating manifest, copying binaries, creating release folders, and supporting unit/integration tests. +- xUnit test project with unit tests and opt-in integration tests. diff --git a/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 b/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 index e313a14..362cd1a 100644 --- a/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 +++ b/Module/PSInfisicalAPI/PSInfisicalAPI.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSInfisicalAPI.psm1' - ModuleVersion = '2026.06.03.0057' + ModuleVersion = '2026.06.03.0113' GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51' Author = 'Grace Solutions' CompanyName = 'Grace Solutions' @@ -27,7 +27,7 @@ LicenseUri = 'https://www.gnu.org/licenses/agpl-3.0.html' ProjectUri = 'https://prod.git.gracesolution.info/gsadmin/PSInfisicalAPI' ReleaseNotes = 'See CHANGELOG.md in the project repository for release history.' - CommitHash = '7e5209190ac2' + CommitHash = '09c577ebd0fd' } } } \ No newline at end of file diff --git a/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll b/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll index 6f0a94e..8f9805d 100644 Binary files a/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll and b/Module/PSInfisicalAPI/bin/PSInfisicalAPI.dll differ diff --git a/src/PSInfisicalAPI/Cmdlets/ConvertToInfisicalSecretDictionaryCmdlet.cs b/src/PSInfisicalAPI/Cmdlets/ConvertToInfisicalSecretDictionaryCmdlet.cs index 0b660ca..25925f4 100644 --- a/src/PSInfisicalAPI/Cmdlets/ConvertToInfisicalSecretDictionaryCmdlet.cs +++ b/src/PSInfisicalAPI/Cmdlets/ConvertToInfisicalSecretDictionaryCmdlet.cs @@ -9,6 +9,7 @@ namespace PSInfisicalAPI.Cmdlets { [Cmdlet(VerbsData.ConvertTo, "InfisicalSecretDictionary")] [OutputType(typeof(Dictionary))] + [OutputType(typeof(Dictionary))] public sealed class ConvertToInfisicalSecretDictionaryCmdlet : InfisicalCmdletBase { [Parameter(Mandatory = true, ValueFromPipeline = true)] @@ -17,6 +18,9 @@ namespace PSInfisicalAPI.Cmdlets [Parameter] public InfisicalDuplicateKeyBehavior DuplicateKeyBehavior { get; set; } = InfisicalDuplicateKeyBehavior.Error; + [Parameter] + public SwitchParameter AsPlainText { get; set; } + private readonly List _buffer = new List(); protected override void ProcessRecord() @@ -36,36 +40,50 @@ namespace PSInfisicalAPI.Cmdlets { try { - Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (InfisicalSecret secret in _buffer) + if (AsPlainText.IsPresent) { - string key = secret.SecretName ?? string.Empty; - - if (dictionary.ContainsKey(key)) - { - if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.Error) - { - throw new InfisicalConfigurationException(string.Concat("Duplicate secret name encountered: ", key)); - } - - if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.LastWins) - { - dictionary[key] = secret.SecretValue; - } - - continue; - } - - dictionary[key] = secret.SecretValue; + Dictionary plain = BuildDictionary(secret => secret.GetPlainTextValue()); + WriteObject(plain); + } + else + { + Dictionary secure = BuildDictionary(secret => secret.SecretValue); + WriteObject(secure); } - - WriteObject(dictionary); } catch (Exception exception) { ThrowTerminatingForException("ConvertToInfisicalSecretDictionaryCmdlet", "ConvertToDictionary", exception); } } + + private Dictionary BuildDictionary(Func valueSelector) + { + Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (InfisicalSecret secret in _buffer) + { + string key = secret.SecretName ?? string.Empty; + + if (dictionary.ContainsKey(key)) + { + if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.Error) + { + throw new InfisicalConfigurationException(string.Concat("Duplicate secret name encountered: ", key)); + } + + if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.LastWins) + { + dictionary[key] = valueSelector(secret); + } + + continue; + } + + dictionary[key] = valueSelector(secret); + } + + return dictionary; + } } } diff --git a/src/PSInfisicalAPI/Models/InfisicalSecret.cs b/src/PSInfisicalAPI/Models/InfisicalSecret.cs index 0fee725..0d2abf5 100644 --- a/src/PSInfisicalAPI/Models/InfisicalSecret.cs +++ b/src/PSInfisicalAPI/Models/InfisicalSecret.cs @@ -34,6 +34,12 @@ namespace PSInfisicalAPI.Models SecureStringUtility.UsePlainText(SecretValue, action); } + public string GetPlainTextValue() + { + if (SecretValue == null) { return null; } + return SecureStringUtility.UsePlainText(SecretValue, plainText => plainText); + } + public override string ToString() { return SecretName;