Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98f5d7704e | |||
| 94bd15a8f8 | |||
| daf1cdce65 | |||
| 80871b73af | |||
| 9a2f81fc02 | |||
| 97193d46f2 | |||
| b5575222eb |
+44
-10
@@ -6,18 +6,52 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 2026.06.10.2018
|
||||||
|
|
||||||
|
- Build produced from commit daf1cdce6576.
|
||||||
|
|
||||||
|
## Unreleased (carried forward)
|
||||||
|
|
||||||
|
- Renamed prefix-related parameters across `ConvertTo-InfisicalSecretDictionary`, `Import-InfisicalSecret`, `Export-InfisicalSecrets`, and `Start-InfisicalProcess`: `-Prefix` is now `-SecretsPrefix` and `-ForcePrefix` is now `-ForceSecretsPrefix`. `Start-InfisicalProcess` also renames the pipeline parameter `-Secret` to `-Secrets`. The previous names remain available as parameter aliases (`Prefix`, `ForcePrefix`, `Secret`) for backward compatibility.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
## Unreleased (carried forward)
|
## Unreleased (carried forward)
|
||||||
|
|
||||||
- Added Organization CRUD cmdlets: `Get-InfisicalOrganization`, `New-InfisicalOrganization`, `Update-InfisicalOrganization`, `Remove-InfisicalOrganization`. `Get` lists every organization the active session can see (List parameter set, default) and returns a single record when `-OrganizationId` is supplied (Single parameter set). `New`/`Update`/`Remove` honor `-WhatIf`/`-Confirm`; `Remove` defaults to High `ConfirmImpact` and supports `-PassThru`. No project context required. Backed by new `InfisicalOrganization` model, DTO, mapper, and client wired into `InfisicalEndpointRegistry` (`ListOrganizations`, `RetrieveOrganization`, `CreateOrganization`, `UpdateOrganization`, `DeleteOrganization`).
|
- Added Organization CRUD cmdlets: `Get-InfisicalOrganization`, `New-InfisicalOrganization`, `Update-InfisicalOrganization`, `Remove-InfisicalOrganization`. `Get` lists every organization the active session can see (List parameter set, default) and returns a single record when `-OrganizationId` is supplied (Single parameter set). `New`/`Update`/`Remove` honor `-WhatIf`/`-Confirm`; `Remove` defaults to High `ConfirmImpact` and supports `-PassThru`. No project context required. Backed by new `InfisicalOrganization` model, DTO, mapper, and client wired into `InfisicalEndpointRegistry` (`ListOrganizations`, `RetrieveOrganization`, `CreateOrganization`, `UpdateOrganization`, `DeleteOrganization`).
|
||||||
- Added Sub-Organization CRUD cmdlets: `Get-InfisicalSubOrganization`, `New-InfisicalSubOrganization`, `Update-InfisicalSubOrganization`, `Remove-InfisicalSubOrganization`, targeting the `/api/v1/sub-organizations` Beta endpoints. `Get` lists by default and accepts optional `-Limit`, `-Offset`, `-Search`, `-OrderBy`, `-OrderDirection`, and `-IsAccessible` query parameters; supplying `-SubOrganizationId` returns a single record. `New`/`Update`/`Remove` honor `-WhatIf`/`-Confirm`; `Remove` defaults to High `ConfirmImpact` and supports `-PassThru`. No project context required. Backed by new `InfisicalSubOrganization` model, DTO, mapper, and client wired into `InfisicalEndpointRegistry` (`ListSubOrganizations`, `RetrieveSubOrganization`, `CreateSubOrganization`, `UpdateSubOrganization`, `DeleteSubOrganization`).
|
- Added Sub-Organization CRUD cmdlets: `Get-InfisicalSubOrganization`, `New-InfisicalSubOrganization`, `Update-InfisicalSubOrganization`, `Remove-InfisicalSubOrganization`, targeting the `/api/v1/sub-organizations` Beta endpoints. `Get` lists by default and accepts optional `-Limit`, `-Offset`, `-Search`, `-OrderBy`, `-OrderDirection`, and `-IsAccessible` query parameters; supplying `-SubOrganizationId` returns a single record. `New`/`Update`/`Remove` honor `-WhatIf`/`-Confirm`; `Remove` defaults to High `ConfirmImpact` and supports `-PassThru`. No project context required. Backed by new `InfisicalSubOrganization` model, DTO, mapper, and client wired into `InfisicalEndpointRegistry` (`ListSubOrganizations`, `RetrieveSubOrganization`, `CreateSubOrganization`, `UpdateSubOrganization`, `DeleteSubOrganization`).
|
||||||
- Added `Get-InfisicalSANList` cmdlet: emits a deduplicated SAN candidate set containing the local device name, the device name suffixed with each non-empty DNS suffix found across operational adapters and the system primary domain, every IPv4 unicast address falling within RFC 1918 (10/8, 172.16/12, 192.168/16) or CGNAT (100.64/10), and the IPv4/IPv6 loopback addresses (127.0.0.1, ::1). Intended to feed `Request-InfisicalCertificate -DnsName` directly.
|
- Added `Get-InfisicalSANList` cmdlet: emits a deduplicated SAN candidate set containing the local device name, the device name suffixed with each non-empty DNS suffix found across operational adapters and the system primary domain, every IPv4 unicast address falling within RFC 1918 (10/8, 172.16/12, 192.168/16) or CGNAT (100.64/10), and the IPv4/IPv6 loopback addresses (127.0.0.1, ::1). Intended to feed `Request-InfisicalCertificate -DnsName` directly.
|
||||||
- `Get-InfisicalSANList`: added optional `-InclusionExpression` and `-ExclusionExpression` case-insensitive regex filters. Applied in fetch -> include -> exclude -> output order after the deduplicated set is built; both default to unset (no filtering).
|
- `Get-InfisicalSANList`: added optional `-InclusionExpression` and `-ExclusionExpression` case-insensitive regex filters. Applied in fetch -> include -> exclude -> output order after the deduplicated set is built; both default to unset (no filtering).
|
||||||
- `Get-InfisicalSANList`: output is a single strongly-typed `System.String[]` array emitted non-enumerated (`OutputType(string[])`), so variable assignment yields `string[]` rather than `object[]`. This lets `[System.Collections.Generic.List[string]]::AddRange()` consume the result directly and lets the array bind straight to `string[]` parameters such as `Request-InfisicalCertificate -DnsName`.
|
- `Get-InfisicalSANList`: output is a single strongly-typed `System.String[]` array emitted non-enumerated (`OutputType(string[])`), so variable assignment yields `string[]` rather than `object[]`. This lets `[System.Collections.Generic.List[string]]::AddRange()` consume the result directly and lets the array bind straight to `string[]` parameters such as `Request-InfisicalCertificate -DnsName`.
|
||||||
- `build.ps1` `CmdletsToExport` and `Test-ModuleImports` expected list now contain 51 cmdlets. `docs/DesignSpec.md` updated with `§16.7` (Organizations) and `§16.8` (Sub-Organizations); full MAML help added for all 9 new cmdlets in `Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml`.
|
- `build.ps1` `CmdletsToExport` and `Test-ModuleImports` expected list now contain 51 cmdlets. `docs/DesignSpec.md` updated with `§16.7` (Organizations) and `§16.8` (Sub-Organizations); full MAML help added for all 9 new cmdlets in `Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml`.
|
||||||
|
|
||||||
## 2026.06.06.2229
|
## 2026.06.06.2229
|
||||||
|
|
||||||
@@ -179,7 +213,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
- **BREAKING**: Removed the plural-noun discovery cmdlets `Get-InfisicalProjects`, `Get-InfisicalEnvironments`, `Get-InfisicalFolders`, `Get-InfisicalTags`, `Get-InfisicalSecrets`, and `Get-InfisicalCertificates`. Their behavior is now folded into the corresponding singular cmdlets via a `List` (default) / single-record parameter set pair, matching the existing `Get-InfisicalCertificateAuthority` precedent. Callers should drop the trailing `s`; invocation without the identity parameter (`-ProjectId`, `-EnvironmentSlugOrId`, `-FolderNameOrId`, `-TagSlugOrId`, `-SecretName`, `-SerialNumber`) now returns the list, and supplying the identity parameter returns the single record. No back-compat aliases were added.
|
- **BREAKING**: Removed the plural-noun discovery cmdlets `Get-InfisicalProjects`, `Get-InfisicalEnvironments`, `Get-InfisicalFolders`, `Get-InfisicalTags`, `Get-InfisicalSecrets`, and `Get-InfisicalCertificates`. Their behavior is now folded into the corresponding singular cmdlets via a `List` (default) / single-record parameter set pair, matching the existing `Get-InfisicalCertificateAuthority` precedent. Callers should drop the trailing `s`; invocation without the identity parameter (`-ProjectId`, `-EnvironmentSlugOrId`, `-FolderNameOrId`, `-TagSlugOrId`, `-SecretName`, `-SerialNumber`) now returns the list, and supplying the identity parameter returns the single record. No back-compat aliases were added.
|
||||||
- Added `Get-InfisicalPkiSubscriber` with `List` (default) and `ByName` parameter sets, backed by new `InfisicalPkiClient.ListPkiSubscribers` and `GetPkiSubscriber` methods, an `InfisicalPkiSubscriber` model, and corresponding DTOs/mapper. Use the emitted `Name` (slug) on `Request-InfisicalCertificate -PkiSubscriberSlug`.
|
- Added `Get-InfisicalPkiSubscriber` with `List` (default) and `ByName` parameter sets, backed by new `InfisicalPkiClient.ListPkiSubscribers` and `GetPkiSubscriber` methods, an `InfisicalPkiSubscriber` model, and corresponding DTOs/mapper. Use the emitted `Name` (slug) on `Request-InfisicalCertificate -PkiSubscriberSlug`.
|
||||||
- **Bug fix**: `Request-InfisicalCertificate -PkiSubscriberSlug ...` was returning 404 because the registry's `SignCertificateBySubscriber` endpoint pointed at `/api/v1/pki/pki-subscribers/{subscriberName}/sign-certificate` and `/api/v1/cert-manager/pki-subscribers/...`. Per Infisical's `v1/index.ts`, the subscriber router is mounted at `/pki/subscribers`, so the single correct path is `/api/v1/pki/subscribers/{subscriberName}/sign-certificate`. The redundant `cert-manager` template was removed; the PKI endpoint registry tests were updated to match.
|
- **Bug fix**: `Request-InfisicalCertificate -PkiSubscriberSlug ...` was returning 404 because the registry's `SignCertificateBySubscriber` endpoint pointed at `/api/v1/pki/pki-subscribers/{subscriberName}/sign-certificate` and `/api/v1/cert-manager/pki-subscribers/...`. Per Infisical's `v1/index.ts`, the subscriber router is mounted at `/pki/subscribers`, so the single correct path is `/api/v1/pki/subscribers/{subscriberName}/sign-certificate`. The redundant `cert-manager` template was removed; the PKI endpoint registry tests were updated to match.
|
||||||
- Updated MAML help in `Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml`: the six consolidated cmdlets and the new `Get-InfisicalPkiSubscriber` each ship three examples — two straight-line invocations (one per parameter set) plus one `OrderedDictionary` splat example. All in-text references to the removed plural cmdlets across other cmdlets' examples were updated to the singular form.
|
- Updated MAML help in `Module/PSInfisicalAPI/en-US/PSInfisicalAPI.dll-Help.xml`: the six consolidated cmdlets and the new `Get-InfisicalPkiSubscriber` each ship three examples  two straight-line invocations (one per parameter set) plus one `OrderedDictionary` splat example. All in-text references to the removed plural cmdlets across other cmdlets' examples were updated to the singular form.
|
||||||
- `build.ps1`: `CmdletsToExport` and the `Test-ModuleImports` expected cmdlet list were updated to drop the six plural cmdlets and add `Get-InfisicalPkiSubscriber` (total: 34 exported cmdlets).
|
- `build.ps1`: `CmdletsToExport` and the `Test-ModuleImports` expected cmdlet list were updated to drop the six plural cmdlets and add `Get-InfisicalPkiSubscriber` (total: 34 exported cmdlets).
|
||||||
|
|
||||||
## 2026.06.04.1825
|
## 2026.06.04.1825
|
||||||
@@ -257,9 +291,9 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
- List/single CA and single certificate response parsing now tolerate raw arrays, wrapper objects (`{certificate: {...}}`, `{certificates: [...]}`), and nested `configuration` blocks. `InfisicalCaMapper` reads CA detail fields from `configuration` first, falling back to top-level.
|
- List/single CA and single certificate response parsing now tolerate raw arrays, wrapper objects (`{certificate: {...}}`, `{certificates: [...]}`), and nested `configuration` blocks. `InfisicalCaMapper` reads CA detail fields from `configuration` first, falling back to top-level.
|
||||||
- `RetrieveCertificate(connection, identifier)` added on `InfisicalPkiClient`.
|
- `RetrieveCertificate(connection, identifier)` added on `InfisicalPkiClient`.
|
||||||
- **New cmdlets**:
|
- **New cmdlets**:
|
||||||
- **`Get-InfisicalCertificate`** — single-record retrieval by `-SerialNumber`/`-Id` (mandatory positional).
|
- **`Get-InfisicalCertificate`**  single-record retrieval by `-SerialNumber`/`-Id` (mandatory positional).
|
||||||
- **`Get-InfisicalCertificates`** — listing with light filtering (`-CommonName`, `-FriendlyName`, `-Status`, `-CaId`, `-Limit`, `-Offset`, `-NoAutoPage`). Auto-paginates by default.
|
- **`Get-InfisicalCertificates`**  listing with light filtering (`-CommonName`, `-FriendlyName`, `-Status`, `-CaId`, `-Limit`, `-Offset`, `-NoAutoPage`). Auto-paginates by default.
|
||||||
- **`Request-InfisicalCertificate`** — generates a keypair locally (private key never leaves the device), submits a PKCS#10 CSR to either `pki-subscribers/{name}/sign-certificate` (`-PkiSubscriberSlug`) or `ca/{caId}/sign-certificate` (`-CertificateAuthorityId`), and returns a single `InfisicalCertificateResult` object with the leaf and chain pre-classified. The result exposes `Leaf : X509Certificate2`, `Intermediates : X509Certificate2[]`, `Root : X509Certificate2` (nullable), `Chain : X509Certificate2[]` (ordered leaf → intermediates → root, deduplicated by thumbprint), plus pass-through `SerialNumber`, `CertificatePem`, `CertificateChainPem`, and `PrivateKeyPem`. Supports `-Subject` (`IDictionary` with `CN`/`C`/`ST`/`L`/`O`/`OU`/`E` keys) merged with individual `-CommonName`/`-Country`/etc. parameters (individual params win), `-DnsName`/`-IpAddress` SANs (auto-populated from local FQDN when omitted). Idempotency: scans the local `X509Store` for an existing certificate matching `CN` and an Infisical-known serial number; returns the existing certificate wrapped in an `InfisicalCertificateResult` whose `Intermediates`/`Root`/`Chain` are populated by walking the local trust stores via `X509Chain` (no network calls, revocation checks disabled), and whose `CertificatePem`/`CertificateChainPem` are reconstructed from the resolved certs. Reuse is short-circuited unless `-Force` or `-AllowRenewal` (with optional `-RenewalThresholdDays`, default 30) requests a new one. Installation: `-Install` adds the leaf to `-StoreName`/`-StoreLocation` (default `My`/`CurrentUser`); `-InstallChain` additionally places intermediates into `CertificateAuthority` and self-signed roots into `Root` for the same `-StoreLocation`. `-KeyStorageFlags` is passed through to `X509Certificate2` import.
|
- **`Request-InfisicalCertificate`**  generates a keypair locally (private key never leaves the device), submits a PKCS#10 CSR to either `pki-subscribers/{name}/sign-certificate` (`-PkiSubscriberSlug`) or `ca/{caId}/sign-certificate` (`-CertificateAuthorityId`), and returns a single `InfisicalCertificateResult` object with the leaf and chain pre-classified. The result exposes `Leaf : X509Certificate2`, `Intermediates : X509Certificate2[]`, `Root : X509Certificate2` (nullable), `Chain : X509Certificate2[]` (ordered leaf → intermediates → root, deduplicated by thumbprint), plus pass-through `SerialNumber`, `CertificatePem`, `CertificateChainPem`, and `PrivateKeyPem`. Supports `-Subject` (`IDictionary` with `CN`/`C`/`ST`/`L`/`O`/`OU`/`E` keys) merged with individual `-CommonName`/`-Country`/etc. parameters (individual params win), `-DnsName`/`-IpAddress` SANs (auto-populated from local FQDN when omitted). Idempotency: scans the local `X509Store` for an existing certificate matching `CN` and an Infisical-known serial number; returns the existing certificate wrapped in an `InfisicalCertificateResult` whose `Intermediates`/`Root`/`Chain` are populated by walking the local trust stores via `X509Chain` (no network calls, revocation checks disabled), and whose `CertificatePem`/`CertificateChainPem` are reconstructed from the resolved certs. Reuse is short-circuited unless `-Force` or `-AllowRenewal` (with optional `-RenewalThresholdDays`, default 30) requests a new one. Installation: `-Install` adds the leaf to `-StoreName`/`-StoreLocation` (default `My`/`CurrentUser`); `-InstallChain` additionally places intermediates into `CertificateAuthority` and self-signed roots into `Root` for the same `-StoreLocation`. `-KeyStorageFlags` is passed through to `X509Certificate2` import.
|
||||||
- **Multi-algorithm CSR support** on `Request-InfisicalCertificate` via split parameters: `-KeyAlgorithm` (`Rsa`/`Ecdsa`/`Ed25519`, default `Rsa`), `-KeySize` (`2048`/`3072`/`4096`, default `2048`, applies to RSA only), `-Curve` (`P256`/`P384`, default `P256`, applies to ECDSA only). Signature algorithms are picked automatically: SHA256WITHRSA for RSA, SHA256WITHECDSA / SHA384WITHECDSA for ECDSA P-256/P-384, and Ed25519 (pure-EdDSA) for Ed25519. The underlying `InfisicalCsrBuilder.Build(subject, dns, ip, options)` API was updated to take an `InfisicalCsrOptions` object in place of the prior `keySize` int.
|
- **Multi-algorithm CSR support** on `Request-InfisicalCertificate` via split parameters: `-KeyAlgorithm` (`Rsa`/`Ecdsa`/`Ed25519`, default `Rsa`), `-KeySize` (`2048`/`3072`/`4096`, default `2048`, applies to RSA only), `-Curve` (`P256`/`P384`, default `P256`, applies to ECDSA only). Signature algorithms are picked automatically: SHA256WITHRSA for RSA, SHA256WITHECDSA / SHA384WITHECDSA for ECDSA P-256/P-384, and Ed25519 (pure-EdDSA) for Ed25519. The underlying `InfisicalCsrBuilder.Build(subject, dns, ip, options)` API was updated to take an `InfisicalCsrOptions` object in place of the prior `keySize` int.
|
||||||
- **Sign-certificate endpoint registrations**: `SignCertificateBySubscriber` and `SignCertificateByCa` registered with both `/api/v1/pki/...` and `/api/v1/cert-manager/...` candidate paths and marked `ContainsSecretMaterialInResponse = true`.
|
- **Sign-certificate endpoint registrations**: `SignCertificateBySubscriber` and `SignCertificateByCa` registered with both `/api/v1/pki/...` and `/api/v1/cert-manager/...` candidate paths and marked `ContainsSecretMaterialInResponse = true`.
|
||||||
|
|
||||||
@@ -281,7 +315,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
|
|
||||||
## Unreleased (carried forward)
|
## Unreleased (carried forward)
|
||||||
|
|
||||||
- **CI  Gitea artifact upload fix**: Replaced `actions/upload-artifact@v4` and `actions/download-artifact@v4` with the Gitea-compatible forks `christopherhx/gitea-upload-artifact@v4` and `christopherhx/gitea-download-artifact@v4` in `.gitea/workflows/publish-psgallery.yml`. The upstream v4 actions abort on Gitea because Gitea is detected as GHES, which the upstream v4 actions do not support (see [go-gitea/gitea#28853](https://github.com/go-gitea/gitea/issues/28853)).
|
- **CI  Gitea artifact upload fix**: Replaced `actions/upload-artifact@v4` and `actions/download-artifact@v4` with the Gitea-compatible forks `christopherhx/gitea-upload-artifact@v4` and `christopherhx/gitea-download-artifact@v4` in `.gitea/workflows/publish-psgallery.yml`. The upstream v4 actions abort on Gitea because Gitea is detected as GHES, which the upstream v4 actions do not support (see [go-gitea/gitea#28853](https://github.com/go-gitea/gitea/issues/28853)).
|
||||||
|
|
||||||
## 2026.06.04.0123
|
## 2026.06.04.0123
|
||||||
|
|
||||||
@@ -289,7 +323,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
|
|
||||||
## Unreleased (carried forward)
|
## Unreleased (carried forward)
|
||||||
|
|
||||||
- **M10 polish  formatting, type metadata, and PKI route aliases**:
|
- **M10 polish  formatting, type metadata, and PKI route aliases**:
|
||||||
- Added default table views and `DefaultDisplayPropertySet` entries for `InfisicalCertificateAuthority`, `InfisicalCertificate`, and `InfisicalCertificateBundle` in the module `Format.ps1xml` / `Types.ps1xml`.
|
- Added default table views and `DefaultDisplayPropertySet` entries for `InfisicalCertificateAuthority`, `InfisicalCertificate`, and `InfisicalCertificateBundle` in the module `Format.ps1xml` / `Types.ps1xml`.
|
||||||
- Realigned PKI endpoint registry to current Infisical paths: `ListInternalCertificateAuthorities` and `RetrieveInternalCertificateAuthority` now use `/api/v1/cert-manager/ca/internal[/{caId}]` as primary, with legacy `/api/v1/pki/ca/internal[/{caId}]` retained as a fallback alias. `GetCertificateBundle` and `RetrieveCertificate` similarly carry `cert-manager` fallback aliases.
|
- Realigned PKI endpoint registry to current Infisical paths: `ListInternalCertificateAuthorities` and `RetrieveInternalCertificateAuthority` now use `/api/v1/cert-manager/ca/internal[/{caId}]` as primary, with legacy `/api/v1/pki/ca/internal[/{caId}]` retained as a fallback alias. `GetCertificateBundle` and `RetrieveCertificate` similarly carry `cert-manager` fallback aliases.
|
||||||
- `InfisicalApiInvoker.InvokeWithCandidateFallback` walks the candidate list and falls back on `404`/`405`, used by `InfisicalPkiClient` so older self-hosted Infisical instances are tolerated transparently.
|
- `InfisicalApiInvoker.InvokeWithCandidateFallback` walks the candidate list and falls back on `404`/`405`, used by `InfisicalPkiClient` so older self-hosted Infisical instances are tolerated transparently.
|
||||||
@@ -300,7 +334,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
|
|
||||||
## Unreleased (carried forward)
|
## Unreleased (carried forward)
|
||||||
|
|
||||||
- **M10  PKI Internal CAs, Certificates & Windows Store integration**:
|
- **M10  PKI Internal CAs, Certificates & Windows Store integration**:
|
||||||
- **`Get-InfisicalCertificateAuthority`** lists internal certificate authorities for the current project, or returns a single CA with `-CaId`.
|
- **`Get-InfisicalCertificateAuthority`** lists internal certificate authorities for the current project, or returns a single CA with `-CaId`.
|
||||||
- **`Search-InfisicalCertificate`** wraps `POST /api/v1/projects/{projectId}/certificates/search` with rich filters (`-CommonName`, `-FriendlyName`, `-Search`, `-Status`, `-CaId`, `-ProfileId`, `-ApplicationId`, `-EnrollmentType`, `-KeyAlgorithm`, `-SignatureAlgorithm`, `-Source`, `-NotAfterFrom/To`, `-NotBeforeFrom/To`, `-SortBy/-SortOrder`, `-Limit/-Offset`). Auto-paginates unless `-NoAutoPage` is set.
|
- **`Search-InfisicalCertificate`** wraps `POST /api/v1/projects/{projectId}/certificates/search` with rich filters (`-CommonName`, `-FriendlyName`, `-Search`, `-Status`, `-CaId`, `-ProfileId`, `-ApplicationId`, `-EnrollmentType`, `-KeyAlgorithm`, `-SignatureAlgorithm`, `-Source`, `-NotAfterFrom/To`, `-NotBeforeFrom/To`, `-SortBy/-SortOrder`, `-Limit/-Offset`). Auto-paginates unless `-NoAutoPage` is set.
|
||||||
- **`ConvertTo-InfisicalCertificate`** accepts an `InfisicalCertificate`, `InfisicalCertificateBundle`, or `-SerialNumber`, fetches the bundle endpoint when needed, and emits a `System.Security.Cryptography.X509Certificates.X509Certificate2` with the private key attached. `-NoPrivateKey` skips key parsing; `-IncludeChain` additionally emits intermediates; `-KeyStorageFlags` controls import behavior.
|
- **`ConvertTo-InfisicalCertificate`** accepts an `InfisicalCertificate`, `InfisicalCertificateBundle`, or `-SerialNumber`, fetches the bundle endpoint when needed, and emits a `System.Security.Cryptography.X509Certificates.X509Certificate2` with the private key attached. `-NoPrivateKey` skips key parsing; `-IncludeChain` additionally emits intermediates; `-KeyStorageFlags` controls import behavior.
|
||||||
@@ -327,7 +361,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
## 2026.06.03.2207
|
## 2026.06.03.2207
|
||||||
|
|
||||||
- Build produced from commit 09c3d5c68bbc.
|
- Build produced from commit 09c3d5c68bbc.
|
||||||
- **M9  Bulk, Duplicate & Inheritance**:
|
- **M9  Bulk, Duplicate & Inheritance**:
|
||||||
- **Bulk parameter sets** added to `New-InfisicalSecret`, `Update-InfisicalSecret`, and `Remove-InfisicalSecret` accepting `-Secrets Hashtable[]`; client methods `CreateBatch`/`UpdateBatch`/`DeleteBatch` wrap `POST|PATCH|DELETE /api/v3/secrets/batch/raw`.
|
- **Bulk parameter sets** added to `New-InfisicalSecret`, `Update-InfisicalSecret`, and `Remove-InfisicalSecret` accepting `-Secrets Hashtable[]`; client methods `CreateBatch`/`UpdateBatch`/`DeleteBatch` wrap `POST|PATCH|DELETE /api/v3/secrets/batch/raw`.
|
||||||
- **`Copy-InfisicalSecret`** cmdlet added, wrapping `POST /api/v4/secrets/duplicate` with source/destination environment + path parameters and per-attribute copy toggles.
|
- **`Copy-InfisicalSecret`** cmdlet added, wrapping `POST /api/v4/secrets/duplicate` with source/destination environment + path parameters and per-attribute copy toggles.
|
||||||
- **Connection inheritance** centralized in `InfisicalCmdletBase` (`ResolveProjectId`/`ResolveEnvironment`/`ResolveSecretPath`/`ResolveApiVersion`/`ResolveOrganizationId`). Explicit parameters always win; missing values fall back to the active connection and emit a `-Verbose` line.
|
- **Connection inheritance** centralized in `InfisicalCmdletBase` (`ResolveProjectId`/`ResolveEnvironment`/`ResolveSecretPath`/`ResolveApiVersion`/`ResolveOrganizationId`). Explicit parameters always win; missing values fall back to the active connection and emit a `-Verbose` line.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@{
|
@{
|
||||||
RootModule = 'PSInfisicalAPI.psm1'
|
RootModule = 'PSInfisicalAPI.psm1'
|
||||||
ModuleVersion = '2026.06.07.0017'
|
ModuleVersion = '2026.06.10.2018'
|
||||||
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,6 +19,7 @@
|
|||||||
'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',
|
||||||
@@ -60,6 +61,7 @@
|
|||||||
'Export-InfisicalScepMdmProfile',
|
'Export-InfisicalScepMdmProfile',
|
||||||
'Write-InfisicalScepMdmProfileToWmi',
|
'Write-InfisicalScepMdmProfileToWmi',
|
||||||
'Start-InfisicalProcess',
|
'Start-InfisicalProcess',
|
||||||
|
'Get-InfisicalEnvironmentVariable',
|
||||||
'Get-InfisicalSANList'
|
'Get-InfisicalSANList'
|
||||||
)
|
)
|
||||||
AliasesToExport = @()
|
AliasesToExport = @()
|
||||||
@@ -72,7 +74,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 = '77cb03ec9845'
|
CommitHash = 'daf1cdce6576'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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).</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). -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:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -322,6 +322,11 @@ $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>
|
||||||
|
|
||||||
@@ -333,7 +338,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.</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; names that already start with -Prefix (case-insensitive) are left as-is to avoid double-prefixing. Pass -ForcePrefix to always prepend.</maml:para>
|
||||||
</maml:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -369,6 +374,44 @@ $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 = <Secrets><Secret><SecretName/><SecretValue/>; 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<string, SecureString> 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>
|
||||||
@@ -1662,7 +1705,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. -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, 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:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -1701,6 +1744,37 @@ $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).</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). -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:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -322,6 +322,11 @@ $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>
|
||||||
|
|
||||||
@@ -333,7 +338,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.</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; names that already start with -Prefix (case-insensitive) are left as-is to avoid double-prefixing. Pass -ForcePrefix to always prepend.</maml:para>
|
||||||
</maml:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -369,6 +374,44 @@ $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 = <Secrets><Secret><SecretName/><SecretValue/>; 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<string, SecureString> 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>
|
||||||
@@ -1662,7 +1705,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. -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, 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:description>
|
</maml:description>
|
||||||
<maml:alertSet>
|
<maml:alertSet>
|
||||||
<maml:title>Notes</maml:title>
|
<maml:title>Notes</maml:title>
|
||||||
@@ -1701,6 +1744,37 @@ $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>
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ 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',
|
||||||
@@ -154,6 +155,7 @@ function Write-Manifest {
|
|||||||
'Export-InfisicalScepMdmProfile',
|
'Export-InfisicalScepMdmProfile',
|
||||||
'Write-InfisicalScepMdmProfileToWmi',
|
'Write-InfisicalScepMdmProfileToWmi',
|
||||||
'Start-InfisicalProcess',
|
'Start-InfisicalProcess',
|
||||||
|
'Get-InfisicalEnvironmentVariable',
|
||||||
'Get-InfisicalSANList'
|
'Get-InfisicalSANList'
|
||||||
)
|
)
|
||||||
AliasesToExport = @()
|
AliasesToExport = @()
|
||||||
@@ -219,7 +221,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','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')
|
`$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')
|
||||||
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"
|
||||||
|
|||||||
@@ -1222,7 +1222,8 @@ Export-InfisicalSecrets `
|
|||||||
[-Scope <Process|User|Machine>] `
|
[-Scope <Process|User|Machine>] `
|
||||||
[-Force] `
|
[-Force] `
|
||||||
[-Encoding <UTF8|UTF8Bom|Unicode>] `
|
[-Encoding <UTF8|UTF8Bom|Unicode>] `
|
||||||
[-Prefix <string>]
|
[-SecretsPrefix <string>] `
|
||||||
|
[-ForceSecretsPrefix]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Parameter Rules
|
## Parameter Rules
|
||||||
@@ -1521,8 +1522,9 @@ Start-InfisicalProcess
|
|||||||
[-SecureArgumentList]
|
[-SecureArgumentList]
|
||||||
[-LogOutput]
|
[-LogOutput]
|
||||||
[-ContinueOnError]
|
[-ContinueOnError]
|
||||||
[-Secret <InfisicalSecret[]>]
|
[-Secrets <InfisicalSecret[]>]
|
||||||
[-Prefix <string>]
|
[-SecretsPrefix <string>]
|
||||||
|
[-ForceSecretsPrefix]
|
||||||
```
|
```
|
||||||
|
|
||||||
Behavior:
|
Behavior:
|
||||||
@@ -1530,7 +1532,7 @@ Behavior:
|
|||||||
```text
|
```text
|
||||||
Buffer pipeline InfisicalSecret objects in ProcessRecord.
|
Buffer pipeline InfisicalSecret objects in ProcessRecord.
|
||||||
Decrypt secrets only into ProcessStartInfo.Environment.
|
Decrypt secrets only into ProcessStartInfo.Environment.
|
||||||
Apply -Prefix to each secret name before injection.
|
Apply -SecretsPrefix to each secret name before injection.
|
||||||
Never write secret plaintext to user or machine environment scope.
|
Never write secret plaintext to user or machine environment scope.
|
||||||
Honor -WhatIf / -Confirm.
|
Honor -WhatIf / -Confirm.
|
||||||
Default -AcceptableExitCodeList = @('0','3010').
|
Default -AcceptableExitCodeList = @('0','3010').
|
||||||
@@ -2,6 +2,7 @@ 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;
|
||||||
|
|
||||||
@@ -21,6 +22,14 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public SwitchParameter AsPlainText { get; set; }
|
public SwitchParameter AsPlainText { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Alias("Prefix")]
|
||||||
|
public string SecretsPrefix { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Alias("ForcePrefix")]
|
||||||
|
public SwitchParameter ForceSecretsPrefix { 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()
|
||||||
@@ -63,7 +72,7 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
|
|
||||||
foreach (InfisicalSecret secret in _buffer)
|
foreach (InfisicalSecret secret in _buffer)
|
||||||
{
|
{
|
||||||
string key = secret.SecretName ?? string.Empty;
|
string key = InfisicalPrefix.Apply(secret.SecretName ?? string.Empty, SecretsPrefix, ForceSecretsPrefix.IsPresent);
|
||||||
|
|
||||||
if (dictionary.ContainsKey(key))
|
if (dictionary.ContainsKey(key))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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;
|
||||||
@@ -38,7 +39,12 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
public InfisicalExportEncoding Encoding { get; set; } = InfisicalExportEncoding.UTF8;
|
public InfisicalExportEncoding Encoding { get; set; } = InfisicalExportEncoding.UTF8;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Prefix { get; set; }
|
[Alias("Prefix")]
|
||||||
|
public string SecretsPrefix { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Alias("ForcePrefix")]
|
||||||
|
public SwitchParameter ForceSecretsPrefix { get; set; }
|
||||||
|
|
||||||
private readonly List<InfisicalSecret> _buffer = new List<InfisicalSecret>();
|
private readonly List<InfisicalSecret> _buffer = new List<InfisicalSecret>();
|
||||||
|
|
||||||
@@ -71,7 +77,7 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
|
|
||||||
InfisicalExportRequest request = new InfisicalExportRequest
|
InfisicalExportRequest request = new InfisicalExportRequest
|
||||||
{
|
{
|
||||||
Secrets = ApplyPrefix(_buffer, Prefix),
|
Secrets = ApplySecretsPrefix(_buffer, SecretsPrefix, ForceSecretsPrefix.IsPresent),
|
||||||
Format = Format,
|
Format = Format,
|
||||||
Path = Path,
|
Path = Path,
|
||||||
Scope = Scope,
|
Scope = Scope,
|
||||||
@@ -88,7 +94,7 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InfisicalSecret[] ApplyPrefix(List<InfisicalSecret> source, string prefix)
|
private static InfisicalSecret[] ApplySecretsPrefix(List<InfisicalSecret> source, string prefix, bool force)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(prefix)) { return source.ToArray(); }
|
if (string.IsNullOrEmpty(prefix)) { return source.ToArray(); }
|
||||||
|
|
||||||
@@ -104,7 +110,7 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
Environment = original.Environment,
|
Environment = original.Environment,
|
||||||
Version = original.Version,
|
Version = original.Version,
|
||||||
Type = original.Type,
|
Type = original.Type,
|
||||||
SecretName = string.Concat(prefix, original.SecretName),
|
SecretName = InfisicalPrefix.Apply(original.SecretName, prefix, force),
|
||||||
SecretValue = original.SecretValue,
|
SecretValue = original.SecretValue,
|
||||||
SecretValueHidden = original.SecretValueHidden,
|
SecretValueHidden = original.SecretValueHidden,
|
||||||
SecretPath = original.SecretPath,
|
SecretPath = original.SecretPath,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
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]
|
||||||
|
[Alias("Prefix")]
|
||||||
|
public string SecretsPrefix { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Alias("ForcePrefix")]
|
||||||
|
public SwitchParameter ForceSecretsPrefix { 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, SecretsPrefix, ForceSecretsPrefix.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,18 +89,23 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
public SwitchParameter ContinueOnError { get; set; }
|
public SwitchParameter ContinueOnError { get; set; }
|
||||||
|
|
||||||
[Parameter(ValueFromPipeline = true)]
|
[Parameter(ValueFromPipeline = true)]
|
||||||
[Alias("Secrets", "InputObject")]
|
[Alias("Secret", "InputObject")]
|
||||||
public InfisicalSecret[] Secret { get; set; }
|
public InfisicalSecret[] Secrets { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Prefix { get; set; }
|
[Alias("Prefix")]
|
||||||
|
public string SecretsPrefix { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Alias("ForcePrefix")]
|
||||||
|
public SwitchParameter ForceSecretsPrefix { 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()
|
||||||
{
|
{
|
||||||
if (Secret == null) { return; }
|
if (Secrets == null) { return; }
|
||||||
foreach (InfisicalSecret secret in Secret)
|
foreach (InfisicalSecret secret in Secrets)
|
||||||
{
|
{
|
||||||
if (secret != null) { _secretBuffer.Add(secret); }
|
if (secret != null) { _secretBuffer.Add(secret); }
|
||||||
}
|
}
|
||||||
@@ -135,7 +140,8 @@ namespace PSInfisicalAPI.Cmdlets
|
|||||||
LogOutput = LogOutput.IsPresent,
|
LogOutput = LogOutput.IsPresent,
|
||||||
ContinueOnError = ContinueOnError.IsPresent,
|
ContinueOnError = ContinueOnError.IsPresent,
|
||||||
Secrets = _secretBuffer.ToArray(),
|
Secrets = _secretBuffer.ToArray(),
|
||||||
Prefix = Prefix
|
SecretsPrefix = SecretsPrefix,
|
||||||
|
ForceSecretsPrefix = ForceSecretsPrefix.IsPresent
|
||||||
};
|
};
|
||||||
|
|
||||||
InfisicalProcessResult result = InfisicalProcessRunner.Run(options, Logger);
|
InfisicalProcessResult result = InfisicalProcessRunner.Run(options, Logger);
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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,6 +75,13 @@ 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() { }
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Imports
|
||||||
|
{
|
||||||
|
public interface IInfisicalImporter
|
||||||
|
{
|
||||||
|
IList<KeyValuePair<string, string>> Import(FileInfo path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace PSInfisicalAPI.Models
|
||||||
|
{
|
||||||
|
public enum InfisicalImportFormat
|
||||||
|
{
|
||||||
|
Json,
|
||||||
|
Yaml,
|
||||||
|
Env,
|
||||||
|
Xml
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ namespace PSInfisicalAPI.Process
|
|||||||
public bool LogOutput { get; set; }
|
public bool LogOutput { get; set; }
|
||||||
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 SecretsPrefix { get; set; }
|
||||||
|
public bool ForceSecretsPrefix { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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;
|
||||||
@@ -39,7 +40,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 = string.IsNullOrEmpty(options.Prefix) ? secret.SecretName : string.Concat(options.Prefix, secret.SecretName);
|
string name = InfisicalPrefix.Apply(secret.SecretName, options.SecretsPrefix, options.ForceSecretsPrefix);
|
||||||
SecureStringUtility.UsePlainText(secret.SecretValue, plain =>
|
SecureStringUtility.UsePlainText(secret.SecretValue, plain =>
|
||||||
{
|
{
|
||||||
processEnv[name] = plain;
|
processEnv[name] = plain;
|
||||||
|
|||||||
Reference in New Issue
Block a user