Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 55 additions & 29 deletions .github/workflows/AfterAll-ModuleLocal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,23 @@ name: AfterAll-ModuleLocal
on:
workflow_call:
secrets:
TEST_APP_ENT_CLIENT_ID:
description: The client ID of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ENT_PRIVATE_KEY:
description: The private key of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ORG_CLIENT_ID:
description: The client ID of an Organization GitHub App for running tests.
required: false
TEST_APP_ORG_PRIVATE_KEY:
description: The private key of an Organization GitHub App for running tests.
required: false
TEST_USER_ORG_FG_PAT:
description: The fine-grained personal access token with org access for running tests.
required: false
TEST_USER_USER_FG_PAT:
description: The fine-grained personal access token with user account access for running tests.
required: false
TEST_USER_PAT:
description: The classic personal access token for running tests.
TestSecrets:
description: |
Optional JSON object mapping environment variable names to secret values. Each entry is
exposed as an environment variable available to the AfterAll teardown script.
required: false
inputs:
Settings:
type: string
description: The complete settings object including test suites.
required: true

env:
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
TestVariables:
type: string
description: |
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
environment variables (not masked) to the AfterAll teardown script. Built from toJSON(vars.<name>).
required: false
default: ''

permissions:
contents: read # to checkout the repo
Expand All @@ -55,6 +37,50 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Expose caller-provided test secrets and variables
shell: pwsh
env:
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
run: |
Comment thread
MariusStorhaug marked this conversation as resolved.
function Add-EnvFromJson {
param(
[string] $Json,
[string] $Source,
[switch] $Mask
)
if ([string]::IsNullOrWhiteSpace($Json)) { return }
try {
$items = $Json | ConvertFrom-Json -ErrorAction Stop
} catch {
throw "The '$Source' value must be a JSON object mapping names to values. $_"
}
foreach ($item in $items.PSObject.Properties) {
$name = $item.Name
$value = [string]$item.Value
if ($Mask) {
foreach ($line in ($value -split "`n")) {
Comment thread
MariusStorhaug marked this conversation as resolved.
Outdated
$line = $line.TrimEnd("`r")
if ($line.Length -gt 0) {
Write-Host "::add-mask::$line"
}
}
}
$delimiter = "GHENV_$([guid]::NewGuid().ToString('N'))"
Add-Content -Path $env:GITHUB_ENV -Value "$name<<$delimiter"
Add-Content -Path $env:GITHUB_ENV -Value $value
Add-Content -Path $env:GITHUB_ENV -Value $delimiter
Write-Host "Exposed [$name] as an environment variable."
}
}

Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'

if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
Write-Host 'No test secrets or variables were provided by the calling workflow.'
}

- name: Run AfterAll Teardown Scripts
if: always()
uses: PSModule/GitHub-Script@1ee97bbc652d19c38ae12f6e1e47e9d9fbd12d0a # v1.8.0
Expand Down
84 changes: 55 additions & 29 deletions .github/workflows/BeforeAll-ModuleLocal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,23 @@ name: BeforeAll-ModuleLocal
on:
workflow_call:
secrets:
TEST_APP_ENT_CLIENT_ID:
description: The client ID of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ENT_PRIVATE_KEY:
description: The private key of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ORG_CLIENT_ID:
description: The client ID of an Organization GitHub App for running tests.
required: false
TEST_APP_ORG_PRIVATE_KEY:
description: The private key of an Organization GitHub App for running tests.
required: false
TEST_USER_ORG_FG_PAT:
description: The fine-grained personal access token with org access for running tests.
required: false
TEST_USER_USER_FG_PAT:
description: The fine-grained personal access token with user account access for running tests.
required: false
TEST_USER_PAT:
description: The classic personal access token for running tests.
TestSecrets:
description: |
Optional JSON object mapping environment variable names to secret values. Each entry is
exposed as an environment variable available to the BeforeAll setup script.
required: false
inputs:
Settings:
type: string
description: The complete settings object including test suites.
required: true

env:
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
TestVariables:
type: string
description: |
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
environment variables (not masked) to the BeforeAll setup script. Built from toJSON(vars.<name>).
required: false
default: ''

permissions:
contents: read # to checkout the repo
Expand All @@ -55,6 +37,50 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Expose caller-provided test secrets and variables
shell: pwsh
env:
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
run: |
Comment thread
MariusStorhaug marked this conversation as resolved.
function Add-EnvFromJson {
param(
[string] $Json,
[string] $Source,
[switch] $Mask
)
if ([string]::IsNullOrWhiteSpace($Json)) { return }
try {
$items = $Json | ConvertFrom-Json -ErrorAction Stop
} catch {
throw "The '$Source' value must be a JSON object mapping names to values. $_"
}
foreach ($item in $items.PSObject.Properties) {
$name = $item.Name
$value = [string]$item.Value
if ($Mask) {
foreach ($line in ($value -split "`n")) {
Comment thread
MariusStorhaug marked this conversation as resolved.
Outdated
$line = $line.TrimEnd("`r")
if ($line.Length -gt 0) {
Write-Host "::add-mask::$line"
}
}
}
$delimiter = "GHENV_$([guid]::NewGuid().ToString('N'))"
Add-Content -Path $env:GITHUB_ENV -Value "$name<<$delimiter"
Add-Content -Path $env:GITHUB_ENV -Value $value
Add-Content -Path $env:GITHUB_ENV -Value $delimiter
Write-Host "Exposed [$name] as an environment variable."
}
}

Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'

if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
Write-Host 'No test secrets or variables were provided by the calling workflow.'
}

- name: Run BeforeAll Setup Scripts
uses: PSModule/GitHub-Script@1ee97bbc652d19c38ae12f6e1e47e9d9fbd12d0a # v1.8.0
with:
Expand Down
82 changes: 55 additions & 27 deletions .github/workflows/Test-ModuleLocal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,28 @@ name: Test-ModuleLocal
on:
workflow_call:
secrets:
TEST_APP_ENT_CLIENT_ID:
description: The client ID of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ENT_PRIVATE_KEY:
description: The private key of an Enterprise GitHub App for running tests.
required: false
TEST_APP_ORG_CLIENT_ID:
description: The client ID of an Organization GitHub App for running tests.
required: false
TEST_APP_ORG_PRIVATE_KEY:
description: The private key of an Organization GitHub App for running tests.
required: false
TEST_USER_ORG_FG_PAT:
description: The fine-grained personal access token with org access for running tests.
required: false
TEST_USER_USER_FG_PAT:
description: The fine-grained personal access token with user account access for running tests.
required: false
TEST_USER_PAT:
description: The classic personal access token for running tests.
TestSecrets:
description: |
Optional JSON object mapping environment variable names to secret values. Each entry is
exposed as an environment variable that the module's Pester tests read via $env:<name>.
required: false
inputs:
Settings:
type: string
description: The settings object as a JSON string.
required: true
TestVariables:
type: string
description: |
Optional JSON object mapping environment variable names to NON-SECRET values, exposed as
environment variables (not masked). The caller builds it from toJSON(vars.<name>).
required: false
default: ''

permissions:
contents: read # to checkout the repo and create releases on the repo

env:
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
GITHUB_TOKEN: ${{ github.token }}

jobs:
Expand All @@ -58,6 +42,50 @@ jobs:
persist-credentials: false
fetch-depth: 0

- name: Expose caller-provided test secrets and variables
shell: pwsh
env:
PSMODULE_TEST_SECRETS: ${{ secrets.TestSecrets }}
PSMODULE_TEST_VARIABLES: ${{ inputs.TestVariables }}
run: |
Comment thread
MariusStorhaug marked this conversation as resolved.
function Add-EnvFromJson {
param(
[string] $Json,
[string] $Source,
[switch] $Mask
)
if ([string]::IsNullOrWhiteSpace($Json)) { return }
try {
$items = $Json | ConvertFrom-Json -ErrorAction Stop
} catch {
throw "The '$Source' value must be a JSON object mapping names to values. $_"
}
foreach ($item in $items.PSObject.Properties) {
$name = $item.Name
$value = [string]$item.Value
if ($Mask) {
Comment thread
MariusStorhaug marked this conversation as resolved.
Outdated
foreach ($line in ($value -split "`n")) {
$line = $line.TrimEnd("`r")
if ($line.Length -gt 0) {
Write-Host "::add-mask::$line"
}
}
}
$delimiter = "GHENV_$([guid]::NewGuid().ToString('N'))"
Add-Content -Path $env:GITHUB_ENV -Value "$name<<$delimiter"
Add-Content -Path $env:GITHUB_ENV -Value $value
Add-Content -Path $env:GITHUB_ENV -Value $delimiter
Write-Host "Exposed [$name] as an environment variable."
}
}

Add-EnvFromJson -Json $env:PSMODULE_TEST_SECRETS -Source 'TestSecrets' -Mask
Add-EnvFromJson -Json $env:PSMODULE_TEST_VARIABLES -Source 'TestVariables'

if ([string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_SECRETS) -and [string]::IsNullOrWhiteSpace($env:PSMODULE_TEST_VARIABLES)) {
Write-Host 'No test secrets or variables were provided by the calling workflow.'
}

- name: Download module artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
Expand Down
21 changes: 14 additions & 7 deletions .github/workflows/Workflow-Test-Default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,22 @@
uses: ./.github/workflows/workflow.yml
secrets:
APIKey: ${{ secrets.APIKey }}
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
# Self-test only: two dedicated, NON-SENSITIVE repository secrets (PSMODULE_TEST_*_SECRET) exist
# purely to prove the TestSecrets plumbing end to end - a real GitHub secret is masked, passed
# through, and exposed as $env:<name>. Their known values are asserted (value + length) in
# tests/.../Environment.Tests.ps1.
# The folded '>-' block keeps the JSON on a SINGLE line so GitHub registers one mask for the
# blob; a multi-line blob makes every line (incl. braces) its own mask and over-masks the logs.
TestSecrets: >-
{
"PSMODULE_TEST_SINGLELINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET) }},
"PSMODULE_TEST_MULTILINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET) }}
}

Check warning

Code scanning / CodeQL

Excessive Secrets Exposure Medium

All organization and repository secrets are passed to the workflow runner in
toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET)

All organization and repository secrets are passed to the workflow runner in
toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET)
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment thread
MariusStorhaug marked this conversation as resolved.
Outdated
with:
WorkingDirectory: tests/srcTestRepo
# Non-secret configuration flows via TestVariables (built from repo/org variables, not masked).
TestVariables: >-
{ "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} }
ImportantFilePatterns: |
^src/
^README\.md$
Expand Down
21 changes: 14 additions & 7 deletions .github/workflows/Workflow-Test-WithManifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,22 @@
uses: ./.github/workflows/workflow.yml
secrets:
APIKey: ${{ secrets.APIKey }}
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
# Self-test only: two dedicated, NON-SENSITIVE repository secrets (PSMODULE_TEST_*_SECRET) exist
# purely to prove the TestSecrets plumbing end to end - a real GitHub secret is masked, passed
# through, and exposed as $env:<name>. Their known values are asserted (value + length) in
# tests/.../Environment.Tests.ps1.
# The folded '>-' block keeps the JSON on a SINGLE line so GitHub registers one mask for the
# blob; a multi-line blob makes every line (incl. braces) its own mask and over-masks the logs.
TestSecrets: >-
{
"PSMODULE_TEST_SINGLELINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET) }},
"PSMODULE_TEST_MULTILINE_SECRET": ${{ toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET) }}
}

Check warning

Code scanning / CodeQL

Excessive Secrets Exposure Medium

All organization and repository secrets are passed to the workflow runner in
toJSON(secrets.PSMODULE_TEST_SINGLELINE_SECRET)

All organization and repository secrets are passed to the workflow runner in
toJSON(secrets.PSMODULE_TEST_MULTILINE_SECRET)
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
with:
WorkingDirectory: tests/srcWithManifestTestRepo
# Non-secret configuration flows via TestVariables (built from repo/org variables, not masked).
TestVariables: >-
{ "PSMODULE_TEST_VARIABLE": ${{ toJSON(vars.PSMODULE_TEST_VARIABLE) }} }
ImportantFilePatterns: |
^src/
^README\.md$
Expand Down
Loading
Loading