Rebrand to Grace Solutions; add README, about_ help, Gitea CI/CD, track Module bin #1

Merged
gsadmin merged 8 commits from dev into main 2026-06-03 01:53:11 +00:00
5 changed files with 81 additions and 49 deletions
Showing only changes of commit 7be0b7b420 - Show all commits
+8
View File
@@ -6,6 +6,14 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
## Unreleased ## 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<string, string>` instead of the default `Dictionary<string, SecureString>`.
## Unreleased (carried forward)
## 2026.06.03.0057 ## 2026.06.03.0057
- Build produced from commit 7e5209190ac2. - Build produced from commit 7e5209190ac2.
+2 -2
View File
@@ -1,6 +1,6 @@
@{ @{
RootModule = 'PSInfisicalAPI.psm1' RootModule = 'PSInfisicalAPI.psm1'
ModuleVersion = '2026.06.03.0057' ModuleVersion = '2026.06.03.0113'
GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51' GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51'
Author = 'Grace Solutions' Author = 'Grace Solutions'
CompanyName = 'Grace Solutions' CompanyName = 'Grace Solutions'
@@ -27,7 +27,7 @@
LicenseUri = 'https://www.gnu.org/licenses/agpl-3.0.html' LicenseUri = 'https://www.gnu.org/licenses/agpl-3.0.html'
ProjectUri = 'https://prod.git.gracesolution.info/gsadmin/PSInfisicalAPI' ProjectUri = 'https://prod.git.gracesolution.info/gsadmin/PSInfisicalAPI'
ReleaseNotes = 'See CHANGELOG.md in the project repository for release history.' ReleaseNotes = 'See CHANGELOG.md in the project repository for release history.'
CommitHash = '7e5209190ac2' CommitHash = '09c577ebd0fd'
} }
} }
} }
Binary file not shown.
@@ -9,6 +9,7 @@ namespace PSInfisicalAPI.Cmdlets
{ {
[Cmdlet(VerbsData.ConvertTo, "InfisicalSecretDictionary")] [Cmdlet(VerbsData.ConvertTo, "InfisicalSecretDictionary")]
[OutputType(typeof(Dictionary<string, SecureString>))] [OutputType(typeof(Dictionary<string, SecureString>))]
[OutputType(typeof(Dictionary<string, string>))]
public sealed class ConvertToInfisicalSecretDictionaryCmdlet : InfisicalCmdletBase public sealed class ConvertToInfisicalSecretDictionaryCmdlet : InfisicalCmdletBase
{ {
[Parameter(Mandatory = true, ValueFromPipeline = true)] [Parameter(Mandatory = true, ValueFromPipeline = true)]
@@ -17,6 +18,9 @@ namespace PSInfisicalAPI.Cmdlets
[Parameter] [Parameter]
public InfisicalDuplicateKeyBehavior DuplicateKeyBehavior { get; set; } = InfisicalDuplicateKeyBehavior.Error; public InfisicalDuplicateKeyBehavior DuplicateKeyBehavior { get; set; } = InfisicalDuplicateKeyBehavior.Error;
[Parameter]
public SwitchParameter AsPlainText { get; set; }
private readonly List<InfisicalSecret> _buffer = new List<InfisicalSecret>(); private readonly List<InfisicalSecret> _buffer = new List<InfisicalSecret>();
protected override void ProcessRecord() protected override void ProcessRecord()
@@ -36,36 +40,50 @@ namespace PSInfisicalAPI.Cmdlets
{ {
try try
{ {
Dictionary<string, SecureString> dictionary = new Dictionary<string, SecureString>(StringComparer.OrdinalIgnoreCase); if (AsPlainText.IsPresent)
foreach (InfisicalSecret secret in _buffer)
{ {
string key = secret.SecretName ?? string.Empty; Dictionary<string, string> plain = BuildDictionary<string>(secret => secret.GetPlainTextValue());
WriteObject(plain);
if (dictionary.ContainsKey(key)) }
{ else
if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.Error) {
{ Dictionary<string, SecureString> secure = BuildDictionary<SecureString>(secret => secret.SecretValue);
throw new InfisicalConfigurationException(string.Concat("Duplicate secret name encountered: ", key)); WriteObject(secure);
}
if (DuplicateKeyBehavior == InfisicalDuplicateKeyBehavior.LastWins)
{
dictionary[key] = secret.SecretValue;
}
continue;
}
dictionary[key] = secret.SecretValue;
} }
WriteObject(dictionary);
} }
catch (Exception exception) catch (Exception exception)
{ {
ThrowTerminatingForException("ConvertToInfisicalSecretDictionaryCmdlet", "ConvertToDictionary", exception); ThrowTerminatingForException("ConvertToInfisicalSecretDictionaryCmdlet", "ConvertToDictionary", exception);
} }
} }
private Dictionary<string, TValue> BuildDictionary<TValue>(Func<InfisicalSecret, TValue> valueSelector)
{
Dictionary<string, TValue> dictionary = new Dictionary<string, TValue>(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;
}
} }
} }
@@ -34,6 +34,12 @@ namespace PSInfisicalAPI.Models
SecureStringUtility.UsePlainText(SecretValue, action); SecureStringUtility.UsePlainText(SecretValue, action);
} }
public string GetPlainTextValue()
{
if (SecretValue == null) { return null; }
return SecureStringUtility.UsePlainText(SecretValue, plainText => plainText);
}
public override string ToString() public override string ToString()
{ {
return SecretName; return SecretName;