Skip to content

Commit ea01935

Browse files
♻️ [Maintenance]: Combine TestSecrets and TestVariables into a single TestData secret
Replace the separate TestSecrets secret and TestVariables input with one TestData secret that carries a { "secrets": {...}, "variables": {...} } object, so callers have a single overview of everything the module tests receive. - workflow.yml + the three ModuleLocal workflows declare/pass TestData; the expose step parses both maps, masks only the "secrets" values, and leaves "variables" unmasked. - Self-test callers build TestData with the CodeQL-clean direct "${{ secrets.X }}" form for secrets and toJSON(vars.X) for variables, kept single-line via a folded >- scalar so GitHub registers one mask. - Drop the multi-line self-test secret (the direct form cannot carry newlines); README documents base64 for multi-line/special-character secrets. - Update Environment.Tests.ps1 and the README accordingly.
1 parent 5ae2f4c commit ea01935

9 files changed

Lines changed: 140 additions & 213 deletions

File tree

.github/workflows/AfterAll-ModuleLocal.yml

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,17 @@ name: AfterAll-ModuleLocal
33
on:
44
workflow_call:
55
secrets:
6-
TestSecrets:
6+
TestData:
77
description: |
8-
Optional JSON object mapping environment variable names to secret values. Each entry is
9-
exposed as an environment variable available to the AfterAll teardown script.
8+
Optional single-line JSON object with 'secrets' and 'variables' maps. Each entry is exposed
9+
as an environment variable available to the AfterAll teardown script; 'secrets' values are
10+
masked in the logs, 'variables' values are not.
1011
required: false
1112
inputs:
1213
Settings:
1314
type: string
1415
description: The complete settings object including test suites.
1516
required: true
16-
TestVariables:
17-
type: string
18-
description: |
19-
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
20-
environment variables (not masked) to the AfterAll teardown script. Built from toJSON(vars.<name>).
21-
required: false
22-
default: ''
2317

2418
permissions:
2519
contents: read # to checkout the repo
@@ -37,25 +31,27 @@ jobs:
3731
persist-credentials: false
3832
fetch-depth: 0
3933

40-
- name: Expose caller-provided test secrets and variables
34+
- name: Expose caller-provided test data
4135
shell: pwsh
4236
env:
43-
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
44-
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
37+
PSMODULE_TEST_DATA: ${{ secrets.TestData }}
4538
run: |
46-
function Add-EnvFromJson {
39+
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_DATA)) {
40+
Write-Host 'No test data was provided by the calling workflow.'
41+
return
42+
}
43+
try {
44+
$data = $env:PSMODULE_TEST_DATA | ConvertFrom-Json -ErrorAction Stop
45+
} catch {
46+
throw "The 'TestData' secret must be a JSON object with 'secrets' and/or 'variables' maps. $_"
47+
}
48+
function Add-EnvFromMap {
4749
param(
48-
[string] $Json,
49-
[string] $Source,
50+
[object] $Map,
5051
[switch] $Mask
5152
)
52-
if ([string]::IsNullOrWhiteSpace($Json)) { return }
53-
try {
54-
$items = $Json | ConvertFrom-Json -ErrorAction Stop
55-
} catch {
56-
throw "The '$Source' value must be a JSON object mapping names to values. $_"
57-
}
58-
foreach ($item in $items.PSObject.Properties) {
53+
if (-not $Map) { return }
54+
foreach ($item in $Map.PSObject.Properties) {
5955
$name = $item.Name
6056
$value = [string]$item.Value
6157
if ($Mask) {
@@ -74,12 +70,8 @@ jobs:
7470
}
7571
}
7672
77-
Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
78-
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'
79-
80-
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
81-
Write-Host 'No test secrets or variables were provided by the calling workflow.'
82-
}
73+
Add-EnvFromMap -Map $data.secrets -Mask
74+
Add-EnvFromMap -Map $data.variables
8375
8476
- name: Run AfterAll Teardown Scripts
8577
if: always()

.github/workflows/BeforeAll-ModuleLocal.yml

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,17 @@ name: BeforeAll-ModuleLocal
33
on:
44
workflow_call:
55
secrets:
6-
TestSecrets:
6+
TestData:
77
description: |
8-
Optional JSON object mapping environment variable names to secret values. Each entry is
9-
exposed as an environment variable available to the BeforeAll setup script.
8+
Optional single-line JSON object with 'secrets' and 'variables' maps. Each entry is exposed
9+
as an environment variable available to the BeforeAll setup script; 'secrets' values are
10+
masked in the logs, 'variables' values are not.
1011
required: false
1112
inputs:
1213
Settings:
1314
type: string
1415
description: The complete settings object including test suites.
1516
required: true
16-
TestVariables:
17-
type: string
18-
description: |
19-
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
20-
environment variables (not masked) to the BeforeAll setup script. Built from toJSON(vars.<name>).
21-
required: false
22-
default: ''
2317

2418
permissions:
2519
contents: read # to checkout the repo
@@ -37,25 +31,27 @@ jobs:
3731
persist-credentials: false
3832
fetch-depth: 0
3933

40-
- name: Expose caller-provided test secrets and variables
34+
- name: Expose caller-provided test data
4135
shell: pwsh
4236
env:
43-
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
44-
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
37+
PSMODULE_TEST_DATA: ${{ secrets.TestData }}
4538
run: |
46-
function Add-EnvFromJson {
39+
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_DATA)) {
40+
Write-Host 'No test data was provided by the calling workflow.'
41+
return
42+
}
43+
try {
44+
$data = $env:PSMODULE_TEST_DATA | ConvertFrom-Json -ErrorAction Stop
45+
} catch {
46+
throw "The 'TestData' secret must be a JSON object with 'secrets' and/or 'variables' maps. $_"
47+
}
48+
function Add-EnvFromMap {
4749
param(
48-
[string] $Json,
49-
[string] $Source,
50+
[object] $Map,
5051
[switch] $Mask
5152
)
52-
if ([string]::IsNullOrWhiteSpace($Json)) { return }
53-
try {
54-
$items = $Json | ConvertFrom-Json -ErrorAction Stop
55-
} catch {
56-
throw "The '$Source' value must be a JSON object mapping names to values. $_"
57-
}
58-
foreach ($item in $items.PSObject.Properties) {
53+
if (-not $Map) { return }
54+
foreach ($item in $Map.PSObject.Properties) {
5955
$name = $item.Name
6056
$value = [string]$item.Value
6157
if ($Mask) {
@@ -74,12 +70,8 @@ jobs:
7470
}
7571
}
7672
77-
Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
78-
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'
79-
80-
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
81-
Write-Host 'No test secrets or variables were provided by the calling workflow.'
82-
}
73+
Add-EnvFromMap -Map $data.secrets -Mask
74+
Add-EnvFromMap -Map $data.variables
8375
8476
- name: Run BeforeAll Setup Scripts
8577
uses: PSModule/GitHub-Script@1ee97bbc652d19c38ae12f6e1e47e9d9fbd12d0a # v1.8.0

.github/workflows/Test-ModuleLocal.yml

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,17 @@ name: Test-ModuleLocal
33
on:
44
workflow_call:
55
secrets:
6-
TestSecrets:
6+
TestData:
77
description: |
8-
Optional JSON object mapping environment variable names to secret values. Each entry is
9-
exposed as an environment variable that the module's Pester tests read via $env:<name>.
8+
Optional single-line JSON object with 'secrets' and 'variables' maps. Each entry is exposed
9+
as an environment variable the module's Pester tests read via $env:<name>; 'secrets' values
10+
are masked in the logs, 'variables' values are not.
1011
required: false
1112
inputs:
1213
Settings:
1314
type: string
1415
description: The settings object as a JSON string.
1516
required: true
16-
TestVariables:
17-
type: string
18-
description: |
19-
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
20-
environment variables (not masked). The caller builds it from toJSON(vars.<name>).
21-
required: false
22-
default: ''
2317

2418
permissions:
2519
contents: read # to checkout the repo and create releases on the repo
@@ -42,25 +36,27 @@ jobs:
4236
persist-credentials: false
4337
fetch-depth: 0
4438

45-
- name: Expose caller-provided test secrets and variables
39+
- name: Expose caller-provided test data
4640
shell: pwsh
4741
env:
48-
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
49-
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
42+
PSMODULE_TEST_DATA: ${{ secrets.TestData }}
5043
run: |
51-
function Add-EnvFromJson {
44+
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_DATA)) {
45+
Write-Host 'No test data was provided by the calling workflow.'
46+
return
47+
}
48+
try {
49+
$data = $env:PSMODULE_TEST_DATA | ConvertFrom-Json -ErrorAction Stop
50+
} catch {
51+
throw "The 'TestData' secret must be a JSON object with 'secrets' and/or 'variables' maps. $_"
52+
}
53+
function Add-EnvFromMap {
5254
param(
53-
[string] $Json,
54-
[string] $Source,
55+
[object] $Map,
5556
[switch] $Mask
5657
)
57-
if ([string]::IsNullOrWhiteSpace($Json)) { return }
58-
try {
59-
$items = $Json | ConvertFrom-Json -ErrorAction Stop
60-
} catch {
61-
throw "The '$Source' value must be a JSON object mapping names to values. $_"
62-
}
63-
foreach ($item in $items.PSObject.Properties) {
58+
if (-not $Map) { return }
59+
foreach ($item in $Map.PSObject.Properties) {
6460
$name = $item.Name
6561
$value = [string]$item.Value
6662
if ($Mask) {
@@ -79,12 +75,8 @@ jobs:
7975
}
8076
}
8177
82-
Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
83-
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'
84-
85-
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
86-
Write-Host 'No test secrets or variables were provided by the calling workflow.'
87-
}
78+
Add-EnvFromMap -Map $data.secrets -Mask
79+
Add-EnvFromMap -Map $data.variables
8880
8981
- name: Download module artifact
9082
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1

.github/workflows/Workflow-Test-Default.yml

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@ jobs:
2828
uses: ./.github/workflows/workflow.yml
2929
secrets:
3030
APIKey: ${{ secrets.APIKey }}
31-
# Self-test only: two dedicated, NON-SENSITIVE repository secrets (PSMODULE_TEST_*_SECRET) exist
32-
# purely to prove the TestSecrets plumbing end to end - a real GitHub secret is masked, passed
33-
# through, and exposed as $env:<name>. Their known values are asserted (value + length) in
31+
# Self-test only: a dedicated, NON-SENSITIVE repository secret + variable exist purely to prove
32+
# the TestData plumbing end to end - the "secrets" entry is masked and the "variables" entry is
33+
# not, and both are exposed as $env:<name>. Their known values are asserted (value + length) in
3434
# tests/.../Environment.Tests.ps1.
35-
# The folded '>-' block keeps the JSON on a SINGLE line so GitHub registers one mask for the
36-
# blob; a multi-line blob makes every line (incl. braces) its own mask and over-masks the logs.
37-
TestSecrets: >-
38-
{
39-
"PSMODULE_TEST_SINGLELINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET) }},
40-
"PSMODULE_TEST_MULTILINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET) }}
41-
}
35+
# Secrets use the direct "${{ secrets.X }}" form (CodeQL-clean; avoids toJSON(secrets.*)), which
36+
# requires single-line secret values with no embedded quotes or backslashes; variables use
37+
# toJSON(vars.X) so any characters are encoded safely. The folded '>-' scalar keeps the whole blob
38+
# on ONE line so GitHub registers a single mask instead of one per line.
39+
TestData: >-
40+
{ "secrets": { "PSMODULE_TEST_SINGLELINE_SECRET": "${{ secrets.PSMODULE_TEST_SINGLELINE_SECRET }}" },
41+
"variables": { "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} } }
4242
with:
4343
WorkingDirectory: tests/srcTestRepo
44-
# Non-secret configuration flows via TestVariables (built from repo/org variables, not masked).
45-
TestVariables: >-
46-
{ "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} }
4744
ImportantFilePatterns: |
4845
^src/
4946
^README\.md$

.github/workflows/Workflow-Test-WithManifest.yml

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@ jobs:
2828
uses: ./.github/workflows/workflow.yml
2929
secrets:
3030
APIKey: ${{ secrets.APIKey }}
31-
# Self-test only: two dedicated, NON-SENSITIVE repository secrets (PSMODULE_TEST_*_SECRET) exist
32-
# purely to prove the TestSecrets plumbing end to end - a real GitHub secret is masked, passed
33-
# through, and exposed as $env:<name>. Their known values are asserted (value + length) in
31+
# Self-test only: a dedicated, NON-SENSITIVE repository secret + variable exist purely to prove
32+
# the TestData plumbing end to end - the "secrets" entry is masked and the "variables" entry is
33+
# not, and both are exposed as $env:<name>. Their known values are asserted (value + length) in
3434
# tests/.../Environment.Tests.ps1.
35-
# The folded '>-' block keeps the JSON on a SINGLE line so GitHub registers one mask for the
36-
# blob; a multi-line blob makes every line (incl. braces) its own mask and over-masks the logs.
37-
TestSecrets: >-
38-
{
39-
"PSMODULE_TEST_SINGLELINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET) }},
40-
"PSMODULE_TEST_MULTILINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET) }}
41-
}
35+
# Secrets use the direct "${{ secrets.X }}" form (CodeQL-clean; avoids toJSON(secrets.*)), which
36+
# requires single-line secret values with no embedded quotes or backslashes; variables use
37+
# toJSON(vars.X) so any characters are encoded safely. The folded '>-' scalar keeps the whole blob
38+
# on ONE line so GitHub registers a single mask instead of one per line.
39+
TestData: >-
40+
{ "secrets": { "PSMODULE_TEST_SINGLELINE_SECRET": "${{ secrets.PSMODULE_TEST_SINGLELINE_SECRET }}" },
41+
"variables": { "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} } }
4242
with:
4343
WorkingDirectory: tests/srcWithManifestTestRepo
44-
# Non-secret configuration flows via TestVariables (built from repo/org variables, not masked).
45-
TestVariables: >-
46-
{ "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} }
4744
ImportantFilePatterns: |
4845
^src/
4946
^README\.md$

0 commit comments

Comments
 (0)