Skip to content

Commit 772d65f

Browse files
🩹 [Patch]: Pass TestSecrets as a single-line value to prevent log over-masking
A multi-line secret makes GitHub register every line (including standalone { and } braces) as its own mask, which over-masks unrelated log output (563 masked lines vs 25 on main). Use a folded (>-) block so the source stays readable but the secret value is a single line, registering one mask. Per-value protection is unchanged (the expose step still ::add-mask::es each value).
1 parent fdb8ae5 commit 772d65f

4 files changed

Lines changed: 37 additions & 28 deletions

File tree

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,18 @@ jobs:
3131
# The calling workflow chooses which secrets to expose to the test jobs. Names are
3232
# caller-defined and read by the module's Pester tests via $env:<name>. CUSTOM_TEST_ENV_VAR
3333
# is a plain literal that proves arbitrary, caller-defined names flow through end to end.
34-
TestSecrets: |
34+
# The folded '>-' block with flat indentation produces a SINGLE-LINE secret value; a literal
35+
# '|' multi-line value makes GitHub register every line as its own mask and over-masks logs.
36+
TestSecrets: >-
3537
{
36-
"TEST_APP_ENT_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ENT_CLIENT_ID) }},
37-
"TEST_APP_ENT_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ENT_PRIVATE_KEY) }},
38-
"TEST_APP_ORG_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ORG_CLIENT_ID) }},
39-
"TEST_APP_ORG_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ORG_PRIVATE_KEY) }},
40-
"TEST_USER_ORG_FG_PAT": ${{ toJSON(secrets.TEST_USER_ORG_FG_PAT) }},
41-
"TEST_USER_USER_FG_PAT": ${{ toJSON(secrets.TEST_USER_USER_FG_PAT) }},
42-
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
43-
"CUSTOM_TEST_ENV_VAR": "caller-provided-value"
38+
"TEST_APP_ENT_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ENT_CLIENT_ID) }},
39+
"TEST_APP_ENT_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ENT_PRIVATE_KEY) }},
40+
"TEST_APP_ORG_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ORG_CLIENT_ID) }},
41+
"TEST_APP_ORG_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ORG_PRIVATE_KEY) }},
42+
"TEST_USER_ORG_FG_PAT": ${{ toJSON(secrets.TEST_USER_ORG_FG_PAT) }},
43+
"TEST_USER_USER_FG_PAT": ${{ toJSON(secrets.TEST_USER_USER_FG_PAT) }},
44+
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
45+
"CUSTOM_TEST_ENV_VAR": "caller-provided-value"
4446
}
4547
with:
4648
WorkingDirectory: tests/srcTestRepo

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,18 @@ jobs:
3131
# The calling workflow chooses which secrets to expose to the test jobs. Names are
3232
# caller-defined and read by the module's Pester tests via $env:<name>. CUSTOM_TEST_ENV_VAR
3333
# is a plain literal that proves arbitrary, caller-defined names flow through end to end.
34-
TestSecrets: |
34+
# The folded '>-' block with flat indentation produces a SINGLE-LINE secret value; a literal
35+
# '|' multi-line value makes GitHub register every line as its own mask and over-masks logs.
36+
TestSecrets: >-
3537
{
36-
"TEST_APP_ENT_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ENT_CLIENT_ID) }},
37-
"TEST_APP_ENT_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ENT_PRIVATE_KEY) }},
38-
"TEST_APP_ORG_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ORG_CLIENT_ID) }},
39-
"TEST_APP_ORG_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ORG_PRIVATE_KEY) }},
40-
"TEST_USER_ORG_FG_PAT": ${{ toJSON(secrets.TEST_USER_ORG_FG_PAT) }},
41-
"TEST_USER_USER_FG_PAT": ${{ toJSON(secrets.TEST_USER_USER_FG_PAT) }},
42-
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
43-
"CUSTOM_TEST_ENV_VAR": "caller-provided-value"
38+
"TEST_APP_ENT_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ENT_CLIENT_ID) }},
39+
"TEST_APP_ENT_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ENT_PRIVATE_KEY) }},
40+
"TEST_APP_ORG_CLIENT_ID": ${{ toJSON(secrets.TEST_APP_ORG_CLIENT_ID) }},
41+
"TEST_APP_ORG_PRIVATE_KEY": ${{ toJSON(secrets.TEST_APP_ORG_PRIVATE_KEY) }},
42+
"TEST_USER_ORG_FG_PAT": ${{ toJSON(secrets.TEST_USER_ORG_FG_PAT) }},
43+
"TEST_USER_USER_FG_PAT": ${{ toJSON(secrets.TEST_USER_USER_FG_PAT) }},
44+
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
45+
"CUSTOM_TEST_ENV_VAR": "caller-provided-value"
4446
}
4547
with:
4648
WorkingDirectory: tests/srcWithManifestTestRepo

‎.github/workflows/workflow.yml‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ on:
1010
description: |
1111
Optional JSON object mapping environment variable names to secret values that are exposed to
1212
the module test jobs (BeforeAll-ModuleLocal, Test-ModuleLocal, AfterAll-ModuleLocal).
13-
The calling workflow decides which secrets to provide and builds the JSON using
14-
toJSON(secrets.<name>) so that quoting and multi-line values are encoded correctly. Each
15-
entry is exposed as an environment variable that the module's Pester tests read via
16-
$env:<name>. Values are masked in the logs. Omit it entirely when the module needs no
17-
secrets. See the README for a complete example.
13+
The calling workflow decides which secrets to provide and builds a single-line JSON object
14+
using toJSON(secrets.<name>) so that quoting and multi-line values (such as private keys) are
15+
encoded correctly. Keep the value on a single line: a multi-line secret makes GitHub register
16+
each line as a separate mask, which over-masks unrelated log output. Each entry is exposed as
17+
an environment variable that the module's Pester tests read via $env:<name>. Values are
18+
masked in the logs. Omit it entirely when the module needs no secrets. See the README for a
19+
complete example.
1820
required: false
1921
inputs:
2022
SettingsPath:

‎README.md‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,20 +409,20 @@ credentials that are exposed. `secrets: inherit` is intentionally not required.
409409

410410
`TestSecrets` lets a module expose any number of caller-defined secrets to its test jobs
411411
(`BeforeAll-ModuleLocal`, `Test-ModuleLocal` and `AfterAll-ModuleLocal`) without changing the shared
412-
workflow. The calling workflow decides exactly which secrets are passed by building a JSON object.
412+
workflow. The calling workflow decides exactly which secrets are passed by building a single-line JSON object.
413413
Use `toJSON(secrets.<name>)` so that quoting and multi-line values (such as private keys) are encoded
414-
correctly:
414+
correctly. A folded `>-` block keeps the source readable while producing a single-line value:
415415

416416
```yaml
417417
jobs:
418418
Process-PSModule:
419419
uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5
420420
secrets:
421421
APIKey: ${{ secrets.APIKEY }}
422-
TestSecrets: |
422+
TestSecrets: >-
423423
{
424-
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
425-
"CONFLUENCE_API_KEY": ${{ toJSON(secrets.CONFLUENCE_API_KEY) }}
424+
"TEST_USER_PAT": ${{ toJSON(secrets.TEST_USER_PAT) }},
425+
"CONFLUENCE_API_KEY": ${{ toJSON(secrets.CONFLUENCE_API_KEY) }}
426426
}
427427
```
428428

@@ -438,6 +438,9 @@ Notes:
438438

439439
- The names are entirely caller-defined; no secret names are hard-coded in the shared workflow.
440440
- Every value is masked in the logs (`::add-mask::`).
441+
- Provide the object as a single-line value (the folded `>-` block above does this). Avoid a literal
442+
`|` block: GitHub registers every line of a multi-line secret as its own mask, which over-masks
443+
unrelated log output.
441444
- Omit `TestSecrets` entirely when the module needs no secrets.
442445
- Because `secrets: inherit` is not used, only the secrets you list are ever exposed.
443446
- Organization and repository secrets are supported. Secrets stored in a GitHub *Environment* are not

0 commit comments

Comments
 (0)