14 Commits

Author SHA1 Message Date
gsadmin f82312433c Merge pull request 'feat: add Organization/Sub-Organization CRUD cmdlets and Get-InfisicalSANList' (#13) from dev into main
Reviewed-on: #13
2026-06-07 00:21:09 +00:00
gsadmin d0395b54ac Merge pull request 'feat: add Start-InfisicalProcess cmdlet and -Prefix support on Export-InfisicalSecrets' (#12) from dev into main
Reviewed-on: #12
2026-06-06 22:36:22 +00:00
gsadmin 18f3f3fe2a Merge pull request 'feat(connect): add -SkipCertificateCheck and -AllowInsecureTransport switches' (#11) from dev into main
Reviewed-on: #11
2026-06-05 20:49:03 +00:00
gsadmin 320c0de2ba Merge pull request 'ci: initialize PSResourceGet store before Set-PSResourceRepository' (#10) from dev into main
Reviewed-on: #10
2026-06-05 11:30:33 +00:00
gsadmin 2057ca2dc3 Merge pull request 'ci: add diagnostics + strict mode to Create Gitea release step' (#9) from dev into main
Reviewed-on: #9
2026-06-05 02:55:31 +00:00
gsadmin 41d8fde1d9 Merge pull request 'ci: skip -RunTests in publish workflow (tests pass locally; flaky/broken on Linux CI runner)' (#8) from dev into main
Reviewed-on: #8
2026-06-05 02:47:50 +00:00
gsadmin feb4cf3b7c Merge pull request 'fix(tests): eliminate UtcNow race in GetChainCertificateTargetStore_NonSelfSigned test' (#7) from dev into main
Reviewed-on: #7
2026-06-05 02:42:01 +00:00
gsadmin ceea76255b Merge pull request 'feat!(certificates): expose full /certificates/search filter surface on Get/Search-InfisicalCertificate' (#6) from dev into main
Reviewed-on: #6
2026-06-05 02:37:43 +00:00
gsadmin 621cb87943 Merge pull request 'CI: add dotnet --info / df -h / free -m diagnostics and an explicit 'Restore NuGet packages' step before build to isolate restore failures (build of e15f650 on main exited with code -1 and zero dotnet output).' (#5) from dev into main
Reviewed-on: #5
2026-06-05 01:24:50 +00:00
GraceSolutions 595a8a2157 CI: add dotnet --info / df -h / free -m diagnostics and an explicit 'Restore NuGet packages' step before build to isolate restore failures (build of e15f650 on main exited with code -1 and zero dotnet output). 2026-06-03 21:36:36 -04:00
gsadmin e15f650c51 Merge pull request 'M10 PKI: add 6 cmdlets (Get-/Search-/ConvertTo-/Install-/Uninstall-/Export-InfisicalCertificate), BouncyCastle-backed PemCertificateBuilder, formatting/type metadata for PKI models, and cert-manager <-> pki route alias fallback via InvokeWithCandidateF…' (#4) from dev into main
Reviewed-on: #4
2026-06-04 01:31:38 +00:00
gsadmin 0b9b67fd69 Merge pull request 'Tests: roll forward to latest major .NET runtime' (#3) from dev into main
Reviewed-on: #3
2026-06-04 00:47:38 +00:00
gsadmin f544b45267 Merge pull request 'Run CI on self-hosted host runners (powershell-linux); switch publish to PSResourceGet' (#2) from dev into main
Reviewed-on: #2
2026-06-03 13:33:24 +00:00
gsadmin 609035af1f Merge pull request 'Rebrand to Grace Solutions; add README, about_ help, Gitea CI/CD, track Module bin' (#1) from dev into main
Reviewed-on: #1
2026-06-03 01:53:11 +00:00
22 changed files with 16 additions and 617 deletions
-26
View File
@@ -6,32 +6,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
## Unreleased ## Unreleased
## 2026.06.07.1435
- Build produced from commit 97193d46f2ff.
## Unreleased (carried forward)
## 2026.06.07.1426
- Build produced from commit b5575222eb36.
## Unreleased (carried forward)
- Added `-ForcePrefix` switch to `ConvertTo-InfisicalSecretDictionary`, `Import-InfisicalSecret`, `Export-InfisicalSecrets`, and `Start-InfisicalProcess`. When `-Prefix` is supplied, names that already start with the prefix (case-insensitive) are now left as-is to prevent double-prefixing (e.g. `MYAPP_API_KEY` stays `MYAPP_API_KEY` when `-Prefix 'MYAPP_'` is supplied). Pass `-ForcePrefix` to restore unconditional prepending. Centralized in a new `PSInfisicalAPI.Common.InfisicalPrefix.Apply` helper.
## 2026.06.07.1421
- Build produced from commit b5575222eb36.
## Unreleased (carried forward)
## 2026.06.07.1350
- Build produced from commit 1aa51b8cbf9c.
## Unreleased (carried forward)
## 2026.06.07.0017 ## 2026.06.07.0017
- Build produced from commit 77cb03ec9845. - Build produced from commit 77cb03ec9845.
+2 -4
View File
@@ -1,6 +1,6 @@
@{ @{
RootModule = 'PSInfisicalAPI.psm1' RootModule = 'PSInfisicalAPI.psm1'
ModuleVersion = '2026.06.07.1435' ModuleVersion = '2026.06.07.0017'
GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51' GUID = 'b8a2f3d4-7c51-4d2f-9e6a-1f0c8b3d4e51'
Author = 'Grace Solutions' Author = 'Grace Solutions'
CompanyName = 'Grace Solutions' CompanyName = 'Grace Solutions'
@@ -19,7 +19,6 @@
'Copy-InfisicalSecret', 'Copy-InfisicalSecret',
'ConvertTo-InfisicalSecretDictionary', 'ConvertTo-InfisicalSecretDictionary',
'Export-InfisicalSecrets', 'Export-InfisicalSecrets',
'Import-InfisicalSecret',
'Get-InfisicalProject', 'Get-InfisicalProject',
'New-InfisicalProject', 'New-InfisicalProject',
'Update-InfisicalProject', 'Update-InfisicalProject',
@@ -61,7 +60,6 @@
'Export-InfisicalScepMdmProfile', 'Export-InfisicalScepMdmProfile',
'Write-InfisicalScepMdmProfileToWmi', 'Write-InfisicalScepMdmProfileToWmi',
'Start-InfisicalProcess', 'Start-InfisicalProcess',
'Get-InfisicalEnvironmentVariable',
'Get-InfisicalSANList' 'Get-InfisicalSANList'
) )
AliasesToExport = @() AliasesToExport = @()
@@ -74,7 +72,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 = '97193d46f2ff' CommitHash = '77cb03ec9845'
} }
} }
} }
Binary file not shown.
@@ -295,7 +295,7 @@ $CopyInfisicalSecretResult = Copy-InfisicalSecret @CopyInfisicalSecretParameters
<command:noun>InfisicalSecretDictionary</command:noun> <command:noun>InfisicalSecretDictionary</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Aggregates an incoming pipeline of InfisicalSecret objects into a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText to materialize string values. Duplicate keys are handled via the -DuplicateKeyBehavior parameter (Error, FirstWins, LastWins). -Prefix prepends a string to every dictionary key (e.g. SecretName 'API_KEY' with -Prefix 'MYAPP_' becomes key 'MYAPP_API_KEY'); the underlying InfisicalSecret objects are not mutated. A SecretName that already starts with -Prefix (case-insensitive) is left as-is to avoid double-prefixing; pass -ForcePrefix to always prepend.</maml:para> <maml:para>Aggregates an incoming pipeline of InfisicalSecret objects into a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText to materialize string values. Duplicate keys are handled via the -DuplicateKeyBehavior parameter (Error, FirstWins, LastWins).</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -322,11 +322,6 @@ $ConvertToInfisicalSecretDictionaryParameters.Verbose = $True
$ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary @ConvertToInfisicalSecretDictionaryParameters</dev:code> $ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary @ConvertToInfisicalSecretDictionaryParameters</dev:code>
<dev:remarks><maml:para>Aggregates recursive secret results into a plain-text dictionary, with the last value winning on key collisions.</maml:para></dev:remarks> <dev:remarks><maml:para>Aggregates recursive secret results into a plain-text dictionary, with the last value winning on key collisions.</maml:para></dev:remarks>
</command:example> </command:example>
<command:example>
<maml:title>EXAMPLE 3</maml:title>
<dev:code>Get-InfisicalSecret -ProjectId $ProjectId -Environment 'dev' | ConvertTo-InfisicalSecretDictionary -Prefix 'MYAPP_' -AsPlainText</dev:code>
<dev:remarks><maml:para>Builds a plain-text dictionary whose keys are namespaced with 'MYAPP_' (e.g. API_KEY becomes MYAPP_API_KEY); the source InfisicalSecret objects are unchanged.</maml:para></dev:remarks>
</command:example>
</command:examples> </command:examples>
</command:command> </command:command>
@@ -338,7 +333,7 @@ $ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary
<command:noun>InfisicalSecrets</command:noun> <command:noun>InfisicalSecrets</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Buffers an incoming pipeline of InfisicalSecret objects and writes them to a file in the requested format (DotEnv, Json, Yaml, EnvironmentVariables, etc.) or sets them as environment variables on the chosen scope (Process, User, Machine). -Encoding controls text encoding for file outputs. -Prefix prepends a string to every emitted variable name regardless of format; names that already start with -Prefix (case-insensitive) are left as-is to avoid double-prefixing. Pass -ForcePrefix to always prepend.</maml:para> <maml:para>Buffers an incoming pipeline of InfisicalSecret objects and writes them to a file in the requested format (DotEnv, Json, Yaml, EnvironmentVariables, etc.) or sets them as environment variables on the chosen scope (Process, User, Machine). -Encoding controls text encoding for file outputs. -Prefix prepends a string to every emitted variable name regardless of format.</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -374,44 +369,6 @@ $ExportInfisicalSecretsResult = Export-InfisicalSecrets @ExportInfisicalSecretsP
</command:examples> </command:examples>
</command:command> </command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Import-InfisicalSecret</command:name>
<maml:description><maml:para>Reads a previously exported secrets file (Json, Yaml, Env, or Xml) back into a name-keyed Dictionary.</maml:para></maml:description>
<command:verb>Import</command:verb>
<command:noun>InfisicalSecret</command:noun>
</command:details>
<maml:description>
<maml:para>Loads the file at -Path (which must exist) using the parser matching -Format and returns a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText for a plain string dictionary. -Prefix prepends to every emitted key; keys already starting with -Prefix (case-insensitive) are left as-is to avoid double-prefixing, and -ForcePrefix overrides that gate. -DuplicateKeyBehavior controls collision handling (Error, FirstWins, LastWins). The EnvironmentVariables format is intentionally not supported here; use [Environment]::GetEnvironmentVariable or Get-InfisicalEnvironmentVariable for environment-backed values.</maml:para>
</maml:description>
<maml:alertSet>
<maml:title>Notes</maml:title>
<maml:alert>
<maml:para>Importers expect the same schema that Export-InfisicalSecrets produces (Json/Yaml = array or 'Secrets' root list of {SecretName, SecretValue}; Xml = &lt;Secrets&gt;&lt;Secret&gt;&lt;SecretName/&gt;&lt;SecretValue/&gt;; Env = KEY=VALUE per line, '#' comments allowed). JSON and YAML additionally accept a flat key/value object as a convenience.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
<command:example>
<maml:title>EXAMPLE 1</maml:title>
<dev:code>$Secrets = Import-InfisicalSecret -Path '.\secrets.json' -Format Json</dev:code>
<dev:remarks><maml:para>Reads a JSON export back into a Dictionary&lt;string, SecureString&gt; keyed by the original SecretName values.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 2</maml:title>
<dev:code>$ImportInfisicalSecretParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase)
$ImportInfisicalSecretParameters.Path = [System.IO.FileInfo]'.\secrets.env'
$ImportInfisicalSecretParameters.Format = 'Env'
$ImportInfisicalSecretParameters.Prefix = 'MYAPP_'
$ImportInfisicalSecretParameters.DuplicateKeyBehavior = 'LastWins'
$ImportInfisicalSecretParameters.AsPlainText = $True
$ImportInfisicalSecretResult = Import-InfisicalSecret @ImportInfisicalSecretParameters</dev:code>
<dev:remarks><maml:para>Loads a .env file into a plain-text dictionary, namespacing every key with 'MYAPP_' and letting the last occurrence win on duplicates.</maml:para></dev:remarks>
</command:example>
</command:examples>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Get-InfisicalProject</command:name> <command:name>Get-InfisicalProject</command:name>
@@ -1705,7 +1662,7 @@ $WriteInfisicalScepMdmProfileToWmiResult = Write-InfisicalScepMdmProfileToWmi @W
<command:noun>InfisicalProcess</command:noun> <command:noun>InfisicalProcess</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Launches the executable specified by -FilePath, captures stdout/stderr, validates the exit code against -AcceptableExitCodeList, and optionally parses output with -ParsingExpression. InfisicalSecret objects supplied via -Secret (pipeline or by name) are decrypted into the ProcessStartInfo.Environment dictionary only, never written to the user or machine scope; -Prefix prepends a string to each injected variable name, skipping names that already start with -Prefix (case-insensitive) unless -ForcePrefix is supplied. -EnvironmentVariables adds additional non-secret values. -ExecutionTimeout, -NoWait, -CreateNoWindow, -WindowStyle, -Priority, -StandardInputObjectList, -SecureArgumentList, -LogOutput, and -ContinueOnError mirror the semantics of the upstream Start-ProcessWithOutput helper. Honors -WhatIf and -Confirm.</maml:para> <maml:para>Launches the executable specified by -FilePath, captures stdout/stderr, validates the exit code against -AcceptableExitCodeList, and optionally parses output with -ParsingExpression. InfisicalSecret objects supplied via -Secret (pipeline or by name) are decrypted into the ProcessStartInfo.Environment dictionary only, never written to the user or machine scope; -Prefix prepends a string to each injected variable name. -EnvironmentVariables adds additional non-secret values. -ExecutionTimeout, -NoWait, -CreateNoWindow, -WindowStyle, -Priority, -StandardInputObjectList, -SecureArgumentList, -LogOutput, and -ContinueOnError mirror the semantics of the upstream Start-ProcessWithOutput helper. Honors -WhatIf and -Confirm.</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -1744,37 +1701,6 @@ $StartInfisicalProcessResult = Start-InfisicalProcess @StartInfisicalProcessPara
</command:examples> </command:examples>
</command:command> </command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Get-InfisicalEnvironmentVariable</command:name>
<maml:description><maml:para>Reads an environment variable from the first scope that has a non-empty value (Process > User > Machine).</maml:para></maml:description>
<command:verb>Get</command:verb>
<command:noun>InfisicalEnvironmentVariable</command:noun>
</command:details>
<maml:description>
<maml:para>Returns the value of -Name from the first scope that contains a non-empty value, checking Process, then User, then Machine in that order. Emits nothing when the variable is missing or blank in every scope, so an assignment yields $null without writing errors or warnings. Platform-unsupported scopes (User and Machine on non-Windows) are silently skipped.</maml:para>
</maml:description>
<maml:alertSet>
<maml:title>Notes</maml:title>
<maml:alert>
<maml:para>Designed for the same discovery semantics the rest of PSInfisicalAPI uses when resolving connection inputs from the environment. Pipe-friendly: accepts -Name from the pipeline by value and by property name.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
<command:example>
<maml:title>EXAMPLE 1</maml:title>
<dev:code>$Value = Get-InfisicalEnvironmentVariable -Name 'INFISICAL_CLIENT_ID'</dev:code>
<dev:remarks><maml:para>Returns the first non-empty value of INFISICAL_CLIENT_ID across Process, User, and Machine scopes; assigns $null when the variable is unset everywhere.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 2</maml:title>
<dev:code>@('INFISICAL_BASE_URI','INFISICAL_PROJECT_ID') | Get-InfisicalEnvironmentVariable</dev:code>
<dev:remarks><maml:para>Pipes a list of variable names through the cmdlet and emits one value per name that is set in any scope.</maml:para></dev:remarks>
</command:example>
</command:examples>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Get-InfisicalOrganization</command:name> <command:name>Get-InfisicalOrganization</command:name>
@@ -295,7 +295,7 @@ $CopyInfisicalSecretResult = Copy-InfisicalSecret @CopyInfisicalSecretParameters
<command:noun>InfisicalSecretDictionary</command:noun> <command:noun>InfisicalSecretDictionary</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Aggregates an incoming pipeline of InfisicalSecret objects into a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText to materialize string values. Duplicate keys are handled via the -DuplicateKeyBehavior parameter (Error, FirstWins, LastWins). -Prefix prepends a string to every dictionary key (e.g. SecretName 'API_KEY' with -Prefix 'MYAPP_' becomes key 'MYAPP_API_KEY'); the underlying InfisicalSecret objects are not mutated. A SecretName that already starts with -Prefix (case-insensitive) is left as-is to avoid double-prefixing; pass -ForcePrefix to always prepend.</maml:para> <maml:para>Aggregates an incoming pipeline of InfisicalSecret objects into a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText to materialize string values. Duplicate keys are handled via the -DuplicateKeyBehavior parameter (Error, FirstWins, LastWins).</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -322,11 +322,6 @@ $ConvertToInfisicalSecretDictionaryParameters.Verbose = $True
$ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary @ConvertToInfisicalSecretDictionaryParameters</dev:code> $ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary @ConvertToInfisicalSecretDictionaryParameters</dev:code>
<dev:remarks><maml:para>Aggregates recursive secret results into a plain-text dictionary, with the last value winning on key collisions.</maml:para></dev:remarks> <dev:remarks><maml:para>Aggregates recursive secret results into a plain-text dictionary, with the last value winning on key collisions.</maml:para></dev:remarks>
</command:example> </command:example>
<command:example>
<maml:title>EXAMPLE 3</maml:title>
<dev:code>Get-InfisicalSecret -ProjectId $ProjectId -Environment 'dev' | ConvertTo-InfisicalSecretDictionary -Prefix 'MYAPP_' -AsPlainText</dev:code>
<dev:remarks><maml:para>Builds a plain-text dictionary whose keys are namespaced with 'MYAPP_' (e.g. API_KEY becomes MYAPP_API_KEY); the source InfisicalSecret objects are unchanged.</maml:para></dev:remarks>
</command:example>
</command:examples> </command:examples>
</command:command> </command:command>
@@ -338,7 +333,7 @@ $ConvertToInfisicalSecretDictionaryResult = ConvertTo-InfisicalSecretDictionary
<command:noun>InfisicalSecrets</command:noun> <command:noun>InfisicalSecrets</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Buffers an incoming pipeline of InfisicalSecret objects and writes them to a file in the requested format (DotEnv, Json, Yaml, EnvironmentVariables, etc.) or sets them as environment variables on the chosen scope (Process, User, Machine). -Encoding controls text encoding for file outputs. -Prefix prepends a string to every emitted variable name regardless of format; names that already start with -Prefix (case-insensitive) are left as-is to avoid double-prefixing. Pass -ForcePrefix to always prepend.</maml:para> <maml:para>Buffers an incoming pipeline of InfisicalSecret objects and writes them to a file in the requested format (DotEnv, Json, Yaml, EnvironmentVariables, etc.) or sets them as environment variables on the chosen scope (Process, User, Machine). -Encoding controls text encoding for file outputs. -Prefix prepends a string to every emitted variable name regardless of format.</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -374,44 +369,6 @@ $ExportInfisicalSecretsResult = Export-InfisicalSecrets @ExportInfisicalSecretsP
</command:examples> </command:examples>
</command:command> </command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Import-InfisicalSecret</command:name>
<maml:description><maml:para>Reads a previously exported secrets file (Json, Yaml, Env, or Xml) back into a name-keyed Dictionary.</maml:para></maml:description>
<command:verb>Import</command:verb>
<command:noun>InfisicalSecret</command:noun>
</command:details>
<maml:description>
<maml:para>Loads the file at -Path (which must exist) using the parser matching -Format and returns a case-insensitive Dictionary keyed by SecretName. By default values are SecureString; pass -AsPlainText for a plain string dictionary. -Prefix prepends to every emitted key; keys already starting with -Prefix (case-insensitive) are left as-is to avoid double-prefixing, and -ForcePrefix overrides that gate. -DuplicateKeyBehavior controls collision handling (Error, FirstWins, LastWins). The EnvironmentVariables format is intentionally not supported here; use [Environment]::GetEnvironmentVariable or Get-InfisicalEnvironmentVariable for environment-backed values.</maml:para>
</maml:description>
<maml:alertSet>
<maml:title>Notes</maml:title>
<maml:alert>
<maml:para>Importers expect the same schema that Export-InfisicalSecrets produces (Json/Yaml = array or 'Secrets' root list of {SecretName, SecretValue}; Xml = &lt;Secrets&gt;&lt;Secret&gt;&lt;SecretName/&gt;&lt;SecretValue/&gt;; Env = KEY=VALUE per line, '#' comments allowed). JSON and YAML additionally accept a flat key/value object as a convenience.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
<command:example>
<maml:title>EXAMPLE 1</maml:title>
<dev:code>$Secrets = Import-InfisicalSecret -Path '.\secrets.json' -Format Json</dev:code>
<dev:remarks><maml:para>Reads a JSON export back into a Dictionary&lt;string, SecureString&gt; keyed by the original SecretName values.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 2</maml:title>
<dev:code>$ImportInfisicalSecretParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase)
$ImportInfisicalSecretParameters.Path = [System.IO.FileInfo]'.\secrets.env'
$ImportInfisicalSecretParameters.Format = 'Env'
$ImportInfisicalSecretParameters.Prefix = 'MYAPP_'
$ImportInfisicalSecretParameters.DuplicateKeyBehavior = 'LastWins'
$ImportInfisicalSecretParameters.AsPlainText = $True
$ImportInfisicalSecretResult = Import-InfisicalSecret @ImportInfisicalSecretParameters</dev:code>
<dev:remarks><maml:para>Loads a .env file into a plain-text dictionary, namespacing every key with 'MYAPP_' and letting the last occurrence win on duplicates.</maml:para></dev:remarks>
</command:example>
</command:examples>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Get-InfisicalProject</command:name> <command:name>Get-InfisicalProject</command:name>
@@ -1705,7 +1662,7 @@ $WriteInfisicalScepMdmProfileToWmiResult = Write-InfisicalScepMdmProfileToWmi @W
<command:noun>InfisicalProcess</command:noun> <command:noun>InfisicalProcess</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>Launches the executable specified by -FilePath, captures stdout/stderr, validates the exit code against -AcceptableExitCodeList, and optionally parses output with -ParsingExpression. InfisicalSecret objects supplied via -Secret (pipeline or by name) are decrypted into the ProcessStartInfo.Environment dictionary only, never written to the user or machine scope; -Prefix prepends a string to each injected variable name, skipping names that already start with -Prefix (case-insensitive) unless -ForcePrefix is supplied. -EnvironmentVariables adds additional non-secret values. -ExecutionTimeout, -NoWait, -CreateNoWindow, -WindowStyle, -Priority, -StandardInputObjectList, -SecureArgumentList, -LogOutput, and -ContinueOnError mirror the semantics of the upstream Start-ProcessWithOutput helper. Honors -WhatIf and -Confirm.</maml:para> <maml:para>Launches the executable specified by -FilePath, captures stdout/stderr, validates the exit code against -AcceptableExitCodeList, and optionally parses output with -ParsingExpression. InfisicalSecret objects supplied via -Secret (pipeline or by name) are decrypted into the ProcessStartInfo.Environment dictionary only, never written to the user or machine scope; -Prefix prepends a string to each injected variable name. -EnvironmentVariables adds additional non-secret values. -ExecutionTimeout, -NoWait, -CreateNoWindow, -WindowStyle, -Priority, -StandardInputObjectList, -SecureArgumentList, -LogOutput, and -ContinueOnError mirror the semantics of the upstream Start-ProcessWithOutput helper. Honors -WhatIf and -Confirm.</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
@@ -1744,37 +1701,6 @@ $StartInfisicalProcessResult = Start-InfisicalProcess @StartInfisicalProcessPara
</command:examples> </command:examples>
</command:command> </command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Get-InfisicalEnvironmentVariable</command:name>
<maml:description><maml:para>Reads an environment variable from the first scope that has a non-empty value (Process > User > Machine).</maml:para></maml:description>
<command:verb>Get</command:verb>
<command:noun>InfisicalEnvironmentVariable</command:noun>
</command:details>
<maml:description>
<maml:para>Returns the value of -Name from the first scope that contains a non-empty value, checking Process, then User, then Machine in that order. Emits nothing when the variable is missing or blank in every scope, so an assignment yields $null without writing errors or warnings. Platform-unsupported scopes (User and Machine on non-Windows) are silently skipped.</maml:para>
</maml:description>
<maml:alertSet>
<maml:title>Notes</maml:title>
<maml:alert>
<maml:para>Designed for the same discovery semantics the rest of PSInfisicalAPI uses when resolving connection inputs from the environment. Pipe-friendly: accepts -Name from the pipeline by value and by property name.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
<command:example>
<maml:title>EXAMPLE 1</maml:title>
<dev:code>$Value = Get-InfisicalEnvironmentVariable -Name 'INFISICAL_CLIENT_ID'</dev:code>
<dev:remarks><maml:para>Returns the first non-empty value of INFISICAL_CLIENT_ID across Process, User, and Machine scopes; assigns $null when the variable is unset everywhere.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 2</maml:title>
<dev:code>@('INFISICAL_BASE_URI','INFISICAL_PROJECT_ID') | Get-InfisicalEnvironmentVariable</dev:code>
<dev:remarks><maml:para>Pipes a list of variable names through the cmdlet and emits one value per name that is set in any scope.</maml:para></dev:remarks>
</command:example>
</command:examples>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Get-InfisicalOrganization</command:name> <command:name>Get-InfisicalOrganization</command:name>
+1 -3
View File
@@ -113,7 +113,6 @@ function Write-Manifest {
'Copy-InfisicalSecret', 'Copy-InfisicalSecret',
'ConvertTo-InfisicalSecretDictionary', 'ConvertTo-InfisicalSecretDictionary',
'Export-InfisicalSecrets', 'Export-InfisicalSecrets',
'Import-InfisicalSecret',
'Get-InfisicalProject', 'Get-InfisicalProject',
'New-InfisicalProject', 'New-InfisicalProject',
'Update-InfisicalProject', 'Update-InfisicalProject',
@@ -155,7 +154,6 @@ function Write-Manifest {
'Export-InfisicalScepMdmProfile', 'Export-InfisicalScepMdmProfile',
'Write-InfisicalScepMdmProfileToWmi', 'Write-InfisicalScepMdmProfileToWmi',
'Start-InfisicalProcess', 'Start-InfisicalProcess',
'Get-InfisicalEnvironmentVariable',
'Get-InfisicalSANList' 'Get-InfisicalSANList'
) )
AliasesToExport = @() AliasesToExport = @()
@@ -221,7 +219,7 @@ if (`$cmds.Count -eq 0) {
throw "No cmdlets were exported by the PSInfisicalAPI module." throw "No cmdlets were exported by the PSInfisicalAPI module."
} }
`$expectedCmds = @('Connect-Infisical','Disconnect-Infisical','Get-InfisicalSecret','New-InfisicalSecret','Update-InfisicalSecret','Remove-InfisicalSecret','Copy-InfisicalSecret','ConvertTo-InfisicalSecretDictionary','Export-InfisicalSecrets','Import-InfisicalSecret','Get-InfisicalProject','New-InfisicalProject','Update-InfisicalProject','Remove-InfisicalProject','Get-InfisicalEnvironment','New-InfisicalEnvironment','Update-InfisicalEnvironment','Remove-InfisicalEnvironment','Get-InfisicalFolder','New-InfisicalFolder','Update-InfisicalFolder','Remove-InfisicalFolder','Get-InfisicalTag','New-InfisicalTag','Update-InfisicalTag','Remove-InfisicalTag','Get-InfisicalOrganization','New-InfisicalOrganization','Update-InfisicalOrganization','Remove-InfisicalOrganization','Get-InfisicalSubOrganization','New-InfisicalSubOrganization','Update-InfisicalSubOrganization','Remove-InfisicalSubOrganization','Get-InfisicalCertificateAuthority','Get-InfisicalPkiSubscriber','Get-InfisicalCertificateProfile','Get-InfisicalCertificatePolicy','Get-InfisicalCertificate','Request-InfisicalCertificate','ConvertTo-InfisicalCertificate','Install-InfisicalCertificate','Uninstall-InfisicalCertificate','Export-InfisicalCertificate','Get-InfisicalCertificateApplication','Get-InfisicalCertificateApplicationEnrollment','New-InfisicalScepDynamicChallenge','Get-InfisicalScepMdmProfile','Export-InfisicalScepMdmProfile','Write-InfisicalScepMdmProfileToWmi','Start-InfisicalProcess','Get-InfisicalEnvironmentVariable','Get-InfisicalSANList') `$expectedCmds = @('Connect-Infisical','Disconnect-Infisical','Get-InfisicalSecret','New-InfisicalSecret','Update-InfisicalSecret','Remove-InfisicalSecret','Copy-InfisicalSecret','ConvertTo-InfisicalSecretDictionary','Export-InfisicalSecrets','Get-InfisicalProject','New-InfisicalProject','Update-InfisicalProject','Remove-InfisicalProject','Get-InfisicalEnvironment','New-InfisicalEnvironment','Update-InfisicalEnvironment','Remove-InfisicalEnvironment','Get-InfisicalFolder','New-InfisicalFolder','Update-InfisicalFolder','Remove-InfisicalFolder','Get-InfisicalTag','New-InfisicalTag','Update-InfisicalTag','Remove-InfisicalTag','Get-InfisicalOrganization','New-InfisicalOrganization','Update-InfisicalOrganization','Remove-InfisicalOrganization','Get-InfisicalSubOrganization','New-InfisicalSubOrganization','Update-InfisicalSubOrganization','Remove-InfisicalSubOrganization','Get-InfisicalCertificateAuthority','Get-InfisicalPkiSubscriber','Get-InfisicalCertificateProfile','Get-InfisicalCertificatePolicy','Get-InfisicalCertificate','Request-InfisicalCertificate','ConvertTo-InfisicalCertificate','Install-InfisicalCertificate','Uninstall-InfisicalCertificate','Export-InfisicalCertificate','Get-InfisicalCertificateApplication','Get-InfisicalCertificateApplicationEnrollment','New-InfisicalScepDynamicChallenge','Get-InfisicalScepMdmProfile','Export-InfisicalScepMdmProfile','Write-InfisicalScepMdmProfileToWmi','Start-InfisicalProcess','Get-InfisicalSANList')
foreach (`$expected in `$expectedCmds) { foreach (`$expected in `$expectedCmds) {
if (-not (Get-Command -Name `$expected -Module PSInfisicalAPI -ErrorAction SilentlyContinue)) { if (-not (Get-Command -Name `$expected -Module PSInfisicalAPI -ErrorAction SilentlyContinue)) {
throw "Cmdlet not found: `$expected" throw "Cmdlet not found: `$expected"
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Security; using System.Security;
using PSInfisicalAPI.Common;
using PSInfisicalAPI.Errors; using PSInfisicalAPI.Errors;
using PSInfisicalAPI.Models; using PSInfisicalAPI.Models;
@@ -22,12 +21,6 @@ namespace PSInfisicalAPI.Cmdlets
[Parameter] [Parameter]
public SwitchParameter AsPlainText { get; set; } public SwitchParameter AsPlainText { get; set; }
[Parameter]
public string Prefix { get; set; }
[Parameter]
public SwitchParameter ForcePrefix { 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()
@@ -70,7 +63,7 @@ namespace PSInfisicalAPI.Cmdlets
foreach (InfisicalSecret secret in _buffer) foreach (InfisicalSecret secret in _buffer)
{ {
string key = InfisicalPrefix.Apply(secret.SecretName ?? string.Empty, Prefix, ForcePrefix.IsPresent); string key = secret.SecretName ?? string.Empty;
if (dictionary.ContainsKey(key)) if (dictionary.ContainsKey(key))
{ {
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Management.Automation; using System.Management.Automation;
using System.Text; using System.Text;
using PSInfisicalAPI.Common;
using PSInfisicalAPI.Errors; using PSInfisicalAPI.Errors;
using PSInfisicalAPI.Exports; using PSInfisicalAPI.Exports;
using PSInfisicalAPI.Models; using PSInfisicalAPI.Models;
@@ -41,9 +40,6 @@ namespace PSInfisicalAPI.Cmdlets
[Parameter] [Parameter]
public string Prefix { get; set; } public string Prefix { get; set; }
[Parameter]
public SwitchParameter ForcePrefix { 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()
@@ -75,7 +71,7 @@ namespace PSInfisicalAPI.Cmdlets
InfisicalExportRequest request = new InfisicalExportRequest InfisicalExportRequest request = new InfisicalExportRequest
{ {
Secrets = ApplyPrefix(_buffer, Prefix, ForcePrefix.IsPresent), Secrets = ApplyPrefix(_buffer, Prefix),
Format = Format, Format = Format,
Path = Path, Path = Path,
Scope = Scope, Scope = Scope,
@@ -92,7 +88,7 @@ namespace PSInfisicalAPI.Cmdlets
} }
} }
private static InfisicalSecret[] ApplyPrefix(List<InfisicalSecret> source, string prefix, bool force) private static InfisicalSecret[] ApplyPrefix(List<InfisicalSecret> source, string prefix)
{ {
if (string.IsNullOrEmpty(prefix)) { return source.ToArray(); } if (string.IsNullOrEmpty(prefix)) { return source.ToArray(); }
@@ -108,7 +104,7 @@ namespace PSInfisicalAPI.Cmdlets
Environment = original.Environment, Environment = original.Environment,
Version = original.Version, Version = original.Version,
Type = original.Type, Type = original.Type,
SecretName = InfisicalPrefix.Apply(original.SecretName, prefix, force), SecretName = string.Concat(prefix, original.SecretName),
SecretValue = original.SecretValue, SecretValue = original.SecretValue,
SecretValueHidden = original.SecretValueHidden, SecretValueHidden = original.SecretValueHidden,
SecretPath = original.SecretPath, SecretPath = original.SecretPath,
@@ -1,43 +0,0 @@
using System;
using System.Management.Automation;
namespace PSInfisicalAPI.Cmdlets
{
[Cmdlet(VerbsCommon.Get, "InfisicalEnvironmentVariable")]
[OutputType(typeof(string))]
public sealed class GetInfisicalEnvironmentVariableCmdlet : PSCmdlet
{
private static readonly EnvironmentVariableTarget[] TargetOrder = new[]
{
EnvironmentVariableTarget.Process,
EnvironmentVariableTarget.User,
EnvironmentVariableTarget.Machine
};
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string Name { get; set; }
protected override void ProcessRecord()
{
foreach (EnvironmentVariableTarget target in TargetOrder)
{
string value;
try
{
value = Environment.GetEnvironmentVariable(Name, target);
}
catch
{
continue;
}
if (!string.IsNullOrEmpty(value))
{
WriteObject(value);
return;
}
}
}
}
}
@@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Security;
using PSInfisicalAPI.Common;
using PSInfisicalAPI.Errors;
using PSInfisicalAPI.Imports;
using PSInfisicalAPI.Models;
using PSInfisicalAPI.Security;
namespace PSInfisicalAPI.Cmdlets
{
[Cmdlet(VerbsData.Import, "InfisicalSecret")]
[OutputType(typeof(Dictionary<string, SecureString>))]
[OutputType(typeof(Dictionary<string, string>))]
public sealed class ImportInfisicalSecretCmdlet : InfisicalCmdletBase
{
[Parameter(Mandatory = true, Position = 0)]
[ValidateNotNull]
public FileInfo Path { get; set; }
[Parameter(Mandatory = true)]
public InfisicalImportFormat Format { get; set; }
[Parameter]
public InfisicalDuplicateKeyBehavior DuplicateKeyBehavior { get; set; } = InfisicalDuplicateKeyBehavior.Error;
[Parameter]
public SwitchParameter AsPlainText { get; set; }
[Parameter]
public string Prefix { get; set; }
[Parameter]
public SwitchParameter ForcePrefix { get; set; }
protected override void EndProcessing()
{
try
{
Path.Refresh();
if (!Path.Exists)
{
throw new InfisicalImportException(string.Concat("Import path does not exist: ", Path.FullName));
}
IInfisicalImporter importer = InfisicalImporterFactory.Create(Format);
IList<KeyValuePair<string, string>> pairs = importer.Import(Path);
if (AsPlainText.IsPresent)
{
Dictionary<string, string> plain = BuildDictionary<string>(pairs, value => value ?? string.Empty);
WriteObject(plain);
}
else
{
Dictionary<string, SecureString> secure = BuildDictionary<SecureString>(pairs, value => SecureStringUtility.ToReadOnlySecureString(value ?? string.Empty));
WriteObject(secure);
}
}
catch (Exception exception)
{
ThrowTerminatingForException("ImportInfisicalSecretCmdlet", "ImportSecret", exception);
}
}
private Dictionary<string, TValue> BuildDictionary<TValue>(
IList<KeyValuePair<string, string>> pairs,
Func<string, TValue> valueSelector)
{
Dictionary<string, TValue> dictionary = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase);
foreach (KeyValuePair<string, string> pair in pairs)
{
if (pair.Key == null) { continue; }
string key = InfisicalPrefix.Apply(pair.Key, Prefix, ForcePrefix.IsPresent);
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(pair.Value);
}
continue;
}
dictionary[key] = valueSelector(pair.Value);
}
return dictionary;
}
}
}
@@ -95,9 +95,6 @@ namespace PSInfisicalAPI.Cmdlets
[Parameter] [Parameter]
public string Prefix { get; set; } public string Prefix { get; set; }
[Parameter]
public SwitchParameter ForcePrefix { get; set; }
private readonly List<InfisicalSecret> _secretBuffer = new List<InfisicalSecret>(); private readonly List<InfisicalSecret> _secretBuffer = new List<InfisicalSecret>();
protected override void ProcessRecord() protected override void ProcessRecord()
@@ -138,8 +135,7 @@ namespace PSInfisicalAPI.Cmdlets
LogOutput = LogOutput.IsPresent, LogOutput = LogOutput.IsPresent,
ContinueOnError = ContinueOnError.IsPresent, ContinueOnError = ContinueOnError.IsPresent,
Secrets = _secretBuffer.ToArray(), Secrets = _secretBuffer.ToArray(),
Prefix = Prefix, Prefix = Prefix
ForcePrefix = ForcePrefix.IsPresent
}; };
InfisicalProcessResult result = InfisicalProcessRunner.Run(options, Logger); InfisicalProcessResult result = InfisicalProcessRunner.Run(options, Logger);
@@ -1,15 +0,0 @@
using System;
namespace PSInfisicalAPI.Common
{
public static class InfisicalPrefix
{
public static string Apply(string original, string prefix, bool force)
{
if (string.IsNullOrEmpty(prefix)) { return original ?? string.Empty; }
if (original == null) { return prefix; }
if (!force && original.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { return original; }
return string.Concat(prefix, original);
}
}
}
@@ -75,13 +75,6 @@ namespace PSInfisicalAPI.Errors
public InfisicalExportException(string message, Exception innerException) : base(message, innerException) { } public InfisicalExportException(string message, Exception innerException) : base(message, innerException) { }
} }
public class InfisicalImportException : InfisicalException
{
public InfisicalImportException() { }
public InfisicalImportException(string message) : base(message) { }
public InfisicalImportException(string message, Exception innerException) : base(message, innerException) { }
}
public class InfisicalConfigurationException : InfisicalException public class InfisicalConfigurationException : InfisicalException
{ {
public InfisicalConfigurationException() { } public InfisicalConfigurationException() { }
@@ -1,36 +0,0 @@
using System.Collections.Generic;
using System.IO;
using PSInfisicalAPI.Errors;
namespace PSInfisicalAPI.Imports
{
public sealed class EnvInfisicalImporter : IInfisicalImporter
{
public IList<KeyValuePair<string, string>> Import(FileInfo path)
{
if (path == null) { throw new InfisicalImportException("Path is required for ENV import."); }
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
string[] lines = File.ReadAllLines(path.FullName);
foreach (string raw in lines)
{
if (raw == null) { continue; }
string line = raw.Trim();
if (line.Length == 0) { continue; }
if (line[0] == '#') { continue; }
int idx = line.IndexOf('=');
if (idx <= 0) { continue; }
string key = line.Substring(0, idx).Trim();
string value = line.Substring(idx + 1);
if (key.Length == 0) { continue; }
result.Add(new KeyValuePair<string, string>(key, value));
}
return result;
}
}
}
@@ -1,10 +0,0 @@
using System.Collections.Generic;
using System.IO;
namespace PSInfisicalAPI.Imports
{
public interface IInfisicalImporter
{
IList<KeyValuePair<string, string>> Import(FileInfo path);
}
}
@@ -1,20 +0,0 @@
using PSInfisicalAPI.Errors;
using PSInfisicalAPI.Models;
namespace PSInfisicalAPI.Imports
{
public static class InfisicalImporterFactory
{
public static IInfisicalImporter Create(InfisicalImportFormat format)
{
switch (format)
{
case InfisicalImportFormat.Json: return new JsonInfisicalImporter();
case InfisicalImportFormat.Yaml: return new YamlInfisicalImporter();
case InfisicalImportFormat.Env: return new EnvInfisicalImporter();
case InfisicalImportFormat.Xml: return new XmlInfisicalImporter();
default: throw new InfisicalImportException(string.Concat("Unsupported import format: ", format.ToString()));
}
}
}
}
@@ -1,53 +0,0 @@
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json.Linq;
using PSInfisicalAPI.Errors;
namespace PSInfisicalAPI.Imports
{
public sealed class JsonInfisicalImporter : IInfisicalImporter
{
public IList<KeyValuePair<string, string>> Import(FileInfo path)
{
if (path == null) { throw new InfisicalImportException("Path is required for JSON import."); }
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
string text = File.ReadAllText(path.FullName);
JToken root = JToken.Parse(text);
if (root.Type == JTokenType.Array)
{
foreach (JToken item in (JArray)root)
{
if (item == null || item.Type != JTokenType.Object) { continue; }
string key = ReadString((JObject)item, "SecretName") ?? ReadString((JObject)item, "secretName");
string value = ReadString((JObject)item, "SecretValue") ?? ReadString((JObject)item, "secretValue");
if (string.IsNullOrEmpty(key)) { continue; }
result.Add(new KeyValuePair<string, string>(key, value ?? string.Empty));
}
}
else if (root.Type == JTokenType.Object)
{
foreach (JProperty prop in ((JObject)root).Properties())
{
if (prop == null || string.IsNullOrEmpty(prop.Name)) { continue; }
string value = prop.Value != null && prop.Value.Type != JTokenType.Null ? prop.Value.ToString() : string.Empty;
result.Add(new KeyValuePair<string, string>(prop.Name, value));
}
}
else
{
throw new InfisicalImportException("JSON import expects an array of secret objects or a flat key/value object.");
}
return result;
}
private static string ReadString(JObject obj, string name)
{
JToken token;
if (!obj.TryGetValue(name, out token) || token == null || token.Type == JTokenType.Null) { return null; }
return token.ToString();
}
}
}
@@ -1,51 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Xml;
using PSInfisicalAPI.Errors;
namespace PSInfisicalAPI.Imports
{
public sealed class XmlInfisicalImporter : IInfisicalImporter
{
public IList<KeyValuePair<string, string>> Import(FileInfo path)
{
if (path == null) { throw new InfisicalImportException("Path is required for XML import."); }
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
XmlDocument document = new XmlDocument();
document.Load(path.FullName);
XmlNode root = document.DocumentElement;
if (root == null || !string.Equals(root.LocalName, "Secrets", System.StringComparison.Ordinal))
{
throw new InfisicalImportException("XML import expects a root <Secrets> element.");
}
foreach (XmlNode node in root.ChildNodes)
{
if (node == null || node.NodeType != XmlNodeType.Element) { continue; }
if (!string.Equals(node.LocalName, "Secret", System.StringComparison.Ordinal)) { continue; }
string key = ReadChild(node, "SecretName");
string value = ReadChild(node, "SecretValue");
if (string.IsNullOrEmpty(key)) { continue; }
result.Add(new KeyValuePair<string, string>(key, value ?? string.Empty));
}
return result;
}
private static string ReadChild(XmlNode parent, string name)
{
foreach (XmlNode child in parent.ChildNodes)
{
if (child == null || child.NodeType != XmlNodeType.Element) { continue; }
if (string.Equals(child.LocalName, name, System.StringComparison.Ordinal))
{
return child.InnerText;
}
}
return null;
}
}
}
@@ -1,61 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using PSInfisicalAPI.Errors;
using YamlDotNet.Serialization;
namespace PSInfisicalAPI.Imports
{
public sealed class YamlInfisicalImporter : IInfisicalImporter
{
public IList<KeyValuePair<string, string>> Import(FileInfo path)
{
if (path == null) { throw new InfisicalImportException("Path is required for YAML import."); }
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
string text = File.ReadAllText(path.FullName);
IDeserializer deserializer = new DeserializerBuilder().Build();
object root = deserializer.Deserialize<object>(text);
if (root == null) { return result; }
IDictionary rootMap = root as IDictionary;
if (rootMap != null && rootMap.Contains("Secrets"))
{
IList entries = rootMap["Secrets"] as IList;
if (entries != null)
{
foreach (object entry in entries)
{
IDictionary map = entry as IDictionary;
if (map == null) { continue; }
string key = AsString(map["SecretName"]);
string value = AsString(map["SecretValue"]);
if (string.IsNullOrEmpty(key)) { continue; }
result.Add(new KeyValuePair<string, string>(key, value ?? string.Empty));
}
return result;
}
}
if (rootMap != null)
{
foreach (DictionaryEntry kvp in rootMap)
{
string key = AsString(kvp.Key);
if (string.IsNullOrEmpty(key)) { continue; }
result.Add(new KeyValuePair<string, string>(key, AsString(kvp.Value) ?? string.Empty));
}
return result;
}
throw new InfisicalImportException("YAML import expects a 'Secrets' root list or a flat key/value mapping.");
}
private static string AsString(object value)
{
if (value == null) { return null; }
return value.ToString();
}
}
}
@@ -1,10 +0,0 @@
namespace PSInfisicalAPI.Models
{
public enum InfisicalImportFormat
{
Json,
Yaml,
Env,
Xml
}
}
@@ -26,6 +26,5 @@ namespace PSInfisicalAPI.Process
public bool ContinueOnError { get; set; } public bool ContinueOnError { get; set; }
public InfisicalSecret[] Secrets { get; set; } public InfisicalSecret[] Secrets { get; set; }
public string Prefix { get; set; } public string Prefix { get; set; }
public bool ForcePrefix { get; set; }
} }
} }
@@ -6,7 +6,6 @@ using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using PSInfisicalAPI.Common;
using PSInfisicalAPI.Logging; using PSInfisicalAPI.Logging;
using PSInfisicalAPI.Models; using PSInfisicalAPI.Models;
using PSInfisicalAPI.Security; using PSInfisicalAPI.Security;
@@ -40,7 +39,7 @@ namespace PSInfisicalAPI.Process
foreach (InfisicalSecret secret in options.Secrets) foreach (InfisicalSecret secret in options.Secrets)
{ {
if (secret == null || string.IsNullOrEmpty(secret.SecretName) || secret.SecretValue == null) { continue; } if (secret == null || string.IsNullOrEmpty(secret.SecretName) || secret.SecretValue == null) { continue; }
string name = InfisicalPrefix.Apply(secret.SecretName, options.Prefix, options.ForcePrefix); string name = string.IsNullOrEmpty(options.Prefix) ? secret.SecretName : string.Concat(options.Prefix, secret.SecretName);
SecureStringUtility.UsePlainText(secret.SecretValue, plain => SecureStringUtility.UsePlainText(secret.SecretValue, plain =>
{ {
processEnv[name] = plain; processEnv[name] = plain;