Skip to content
This repository was archived by the owner on Jul 16, 2026. It is now read-only.

Commit 001135a

Browse files
Add Import-TestData to the Helpers module
Exposes caller-provided TestData (the PSMODULE_TEST_DATA JSON blob with optional 'secrets' and 'variables' maps) as environment variables for later steps: 'secrets' values are masked via ::add-mask::, 'variables' are not. Ships the logic in the installed Helpers module so every consumer gets it, instead of a caller-shipped .github/scripts/Expose-TestData.ps1.
1 parent 74c7361 commit 001135a

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

src/Helpers/Helpers.psm1

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,3 +1185,164 @@ function Set-GitHubLogGroup {
11851185
Write-Host '::endgroup::'
11861186
}
11871187

1188+
function Import-TestData {
1189+
<#
1190+
.SYNOPSIS
1191+
Exposes caller-provided TestData as environment variables for later steps in the job.
1192+
1193+
.DESCRIPTION
1194+
Reads the `PSMODULE_TEST_DATA` environment variable, which is expected to contain a single-line
1195+
JSON object with optional `secrets` and `variables` maps. Each entry is validated and written to
1196+
the file referenced by `GITHUB_ENV` so it becomes available as `$env:<name>` in subsequent steps
1197+
of the same job. Values under `secrets` are masked in the logs via `::add-mask::`; values under
1198+
`variables` are not. When no test data is provided the function is a no-op.
1199+
1200+
.EXAMPLE
1201+
Import-TestData
1202+
1203+
Reads `$env:PSMODULE_TEST_DATA` and exposes its `secrets` and `variables` entries as environment
1204+
variables for the following steps in the job.
1205+
#>
1206+
[CmdletBinding()]
1207+
param()
1208+
1209+
if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_DATA)) {
1210+
Write-Output 'No test data was provided by the calling workflow.'
1211+
return
1212+
}
1213+
try {
1214+
$data = $env:PSMODULE_TEST_DATA | ConvertFrom-Json -ErrorAction Stop
1215+
} catch {
1216+
throw "The 'TestData' secret must be valid JSON with 'secrets' and/or 'variables' maps."
1217+
}
1218+
if ($null -eq $data -or $data -isnot [pscustomobject]) {
1219+
throw "The 'TestData' secret must be a JSON object with 'secrets' and/or 'variables' maps."
1220+
}
1221+
$allowedTopLevelKeys = @('secrets', 'variables')
1222+
foreach ($propertyName in $data.PSObject.Properties.Name) {
1223+
if ($allowedTopLevelKeys -notcontains $propertyName) {
1224+
throw "The 'TestData' secret only supports 'secrets' and 'variables' maps."
1225+
}
1226+
}
1227+
$reservedNames = @('CI', 'HOME', 'PATH', 'PWD', 'SHELL', 'PSMODULE_TEST_DATA')
1228+
$reservedPrefixes = @('GITHUB_', 'RUNNER_', 'ACTIONS_')
1229+
function Assert-EnvironmentName {
1230+
<#
1231+
.SYNOPSIS
1232+
Validates that a TestData key can safely be written to GITHUB_ENV.
1233+
#>
1234+
param([string] $Name)
1235+
if ($Name -notmatch '^[A-Za-z_][A-Za-z0-9_]*$') {
1236+
throw 'TestData keys must be valid environment variable names.'
1237+
}
1238+
$normalized = $Name.ToUpperInvariant()
1239+
if ($reservedNames -contains $normalized) {
1240+
throw 'TestData keys must not override reserved environment variables.'
1241+
}
1242+
foreach ($prefix in $reservedPrefixes) {
1243+
if ($normalized.StartsWith($prefix)) {
1244+
throw 'TestData keys must not override reserved environment variables.'
1245+
}
1246+
}
1247+
}
1248+
function Assert-Map {
1249+
<#
1250+
.SYNOPSIS
1251+
Validates that a TestData section is a JSON object map.
1252+
#>
1253+
param(
1254+
[object] $Map,
1255+
[string] $Name
1256+
)
1257+
if ($null -eq $Map) { return }
1258+
if ($Map -isnot [pscustomobject]) {
1259+
throw "The 'TestData.$Name' value must be a JSON object."
1260+
}
1261+
}
1262+
function Get-EnvironmentValue {
1263+
<#
1264+
.SYNOPSIS
1265+
Converts a scalar TestData value to an environment variable value.
1266+
#>
1267+
param(
1268+
[object] $Value,
1269+
[string] $Name
1270+
)
1271+
if ($null -eq $Value) { return '' }
1272+
if (
1273+
$Value -is [pscustomobject] -or
1274+
($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string])
1275+
) {
1276+
throw "Values in 'TestData.$Name' must be scalar values."
1277+
}
1278+
return [string]$Value
1279+
}
1280+
function Add-EnvFromMap {
1281+
<#
1282+
.SYNOPSIS
1283+
Writes validated TestData entries to GITHUB_ENV.
1284+
#>
1285+
param(
1286+
[object] $Map,
1287+
[string] $Name,
1288+
[switch] $Mask
1289+
)
1290+
Assert-Map -Map $Map -Name $Name
1291+
if ($null -eq $Map) { return }
1292+
$count = 0
1293+
foreach ($item in $Map.PSObject.Properties) {
1294+
$name = $item.Name
1295+
Assert-EnvironmentName -Name $name
1296+
$value = Get-EnvironmentValue -Value $item.Value -Name $Name
1297+
if ($Mask) {
1298+
foreach ($line in ($value -split "`n")) {
1299+
$line = $line.TrimEnd("`r")
1300+
if ($line.Length -gt 0) {
1301+
Write-Output "::add-mask::$line"
1302+
}
1303+
}
1304+
}
1305+
do {
1306+
$delimiter = "GHENV_$([guid]::NewGuid().ToString('N'))"
1307+
} while ($value.Contains($delimiter))
1308+
Add-Content -Path $env:GITHUB_ENV -Value "$name<<$delimiter" -Encoding utf8
1309+
Add-Content -Path $env:GITHUB_ENV -Value $value -Encoding utf8
1310+
Add-Content -Path $env:GITHUB_ENV -Value $delimiter -Encoding utf8
1311+
$count++
1312+
}
1313+
if ($count -gt 0) {
1314+
if ($Mask) {
1315+
Write-Output "Exposed $count secret value(s) as environment variables."
1316+
} else {
1317+
Write-Output "Exposed $count variable value(s) as environment variables."
1318+
}
1319+
}
1320+
}
1321+
1322+
Assert-Map -Map $data.secrets -Name 'secrets'
1323+
Assert-Map -Map $data.variables -Name 'variables'
1324+
1325+
$secretNames = @()
1326+
if ($null -ne $data.secrets) {
1327+
$secretNames = @($data.secrets.PSObject.Properties.Name)
1328+
}
1329+
$variableNames = @()
1330+
if ($null -ne $data.variables) {
1331+
$variableNames = @($data.variables.PSObject.Properties.Name)
1332+
}
1333+
$secretNameSet = [System.Collections.Generic.HashSet[string]]::new(
1334+
[System.StringComparer]::OrdinalIgnoreCase
1335+
)
1336+
foreach ($secretName in $secretNames) {
1337+
[void] $secretNameSet.Add($secretName)
1338+
}
1339+
foreach ($variableName in $variableNames) {
1340+
if ($secretNameSet.Contains($variableName)) {
1341+
throw 'TestData keys must not be duplicated across secrets and variables.'
1342+
}
1343+
}
1344+
1345+
Add-EnvFromMap -Map $data.secrets -Name 'secrets' -Mask
1346+
Add-EnvFromMap -Map $data.variables -Name 'variables'
1347+
}
1348+

0 commit comments

Comments
 (0)