-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.psa.config.json.template
More file actions
442 lines (419 loc) · 20.9 KB
/
.psa.config.json.template
File metadata and controls
442 lines (419 loc) · 20.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
// =============================================================================
// psa.py configuration file - TEMPLATE
// =============================================================================
//
// File format : JSONC (JSON with C-style line `//` and block `/* */` comments)
// Encoding : UTF-8
// Schema : SPEC.md §5
// Applies to : psa.py latest mainline (see sibling VERSION file)
//
// -----------------------------------------------------------------------------
// What's new in 3.8.0 (compared to 3.7.0 templates)
// -----------------------------------------------------------------------------
//
// - New generic rule : PSA2009 PSCustomObject property assigned without
// prior declaration in the [pscustomobject]@{...}
// initialiser (default ON, Warning).
// Models PowerShell 5.1's sealed-object
// semantic: any `$Var.NewProp = value`
// assignment where `NewProp` was not in
// the initialiser AND was not added later
// via Add-Member raises a runtime
// terminating exception. The rule catches
// this defect at static-analysis time.
//
// Detection runs in four passes (initialiser, Add-Member, hashtable-form
// drop, assignment). Variables that are also assigned with a plain hashtable
// literal (`@{...}` / `[hashtable]@{...}` / `[ordered]@{...}`) anywhere in
// the file are conservatively dropped from tracking to prevent false
// positives on accumulator patterns. Well-known dynamic property bags
// ($_, $Matches, $PSBoundParameters, $Host, $Error, $PSCmdlet, $MyInvocation,
// $args, $input, $this) are exempt.
//
// Inline suppression via `# psa-disable-line PSA2009` works on the
// assignment line.
//
// No other rule semantics changed in 3.8.0.
//
// -----------------------------------------------------------------------------
// What's new in 3.7.0 (compared to 3.6.x templates)
// -----------------------------------------------------------------------------
//
// - New generic rule : PSA7002 PowerShell script has LF-only or mixed
// line endings (default ON, Warning).
// Canonical form for .ps1 is CRLF; mixed
// line endings indicate programmatic
// insertion of LF-only content into a
// CRLF file. Invisible to the PowerShell
// AST parser but observable to signtool,
// diff tooling, and reviewer eyes.
//
// No other rule semantics changed in 3.7.0.
//
// -----------------------------------------------------------------------------
// What's new in 3.6.0 (compared to 3.5.x templates)
// -----------------------------------------------------------------------------
//
// - New generic rule : PSA2007 Parameter name shadows a PowerShell
// automatic variable (default ON, Warning).
// Mirrors PSScriptAnalyzer
// PSAvoidAssignmentToAutomaticVariable.
// - New generic rule : PSA2008 $Script:Foo++/+=/-= without prior
// initialisation (default ON, Info).
// - New generic rule : PSA3006 Deprecated WMI cmdlet usage
// (Get-WmiObject etc.) (default ON, Warning).
// Mirrors PSScriptAnalyzer PSAvoidUsingWMICmdlet.
// - New generic rule : PSA6007 Advanced function lacks [OutputType()]
// (default ON, Info). Mirrors PSScriptAnalyzer
// PSUseOutputTypeCorrectly.
// - New generic rule : PSA6008 Function with attributes but no explicit
// param() block (default ON, Info).
//
// Behavioural broadening:
// - PSA2002 RISKY_SHADOW_VARS expanded from 8 to 38 entries to match the
// PowerShell engine's actual automatic-variable inventory ($Event,
// $Error, $PSCmdlet, $MyInvocation, $Home, $Profile, etc.). Scripts
// that previously passed PSA2002 may emit new warnings if they assign
// to any of these auto-variables. The exempt $null = ... discard
// idiom is preserved.
//
// -----------------------------------------------------------------------------
// What's new in 3.3.0 (compared to 3.2.0 templates)
// -----------------------------------------------------------------------------
//
// - New project rules : PSAP0003 / PSAP0004 (revision-discipline rules,
// default OFF, opt-in)
// PSAP0003 detects inline `# rNN:` revision-tag comments inside
// PowerShell sources; PSAP0004 detects in-script REVISION HISTORY /
// CHANGELOG comment blocks. Both rules enforce the "per-version
// release notes live in CHANGELOG.md, not in script bodies" policy.
//
// No other rule semantics changed in 3.3.0.
//
// -----------------------------------------------------------------------------
// What's new in 3.2.0 (compared to 3.1.x templates)
// -----------------------------------------------------------------------------
//
// - New generic rule : PSA3005 Start-Transcript -Path -> -LiteralPath
// - New generic rule : PSA8001 Function body hash drift across files
// (cross-file consistency, default ON)
// - New generic rule : PSA9001 Long function (default OFF, opt-in)
// - New generic rule : PSA9002 Unchecked $LASTEXITCODE (default OFF)
// - New project rules : PSAP0001 / PSAP0002 (pipeline-convention rules,
// ALL default OFF, opt-in)
// - New tunable : max_function_lines (PSA9001 threshold)
// - New tunable : psa8001_ignore_functions (PSA8001 ignore list)
//
// PSAPxxxx is a rule family introduced in 3.2.0 that holds opinionated,
// project-specific conventions (e.g. phase-function naming, required
// script-identity variables, revision discipline). All PSAPxxxx rules
// are disabled by default and must be explicitly enabled per project.
// See the "PSAPxxxx" section below.
//
// -----------------------------------------------------------------------------
// How to use this template
// -----------------------------------------------------------------------------
//
// 1) Copy this file to .psa.config.json in your repository root:
//
// cp .psa.config.json.template .psa.config.json
//
// 2) Uncomment and edit only the fields you want to override.
// Every field is OPTIONAL - an empty {} is a perfectly valid config.
// Any field you leave commented out falls back to the built-in default
// documented next to it.
//
// 3) psa.py auto-discovers `.psa.config.json` in the current working
// directory when no `--config` flag is given. To use a different file
// or a remote one, pass --config explicitly.
//
// -----------------------------------------------------------------------------
// Remote configuration (HTTPS / GitHub)
// -----------------------------------------------------------------------------
//
// `--config` accepts both local paths and HTTP(S) URLs. For team-wide
// configurations stored in a GitHub repository, use the *raw* URL form:
//
// psa.py --config https://raw.githubusercontent.com/<owner>/<repo>/<branch>/.psa.config.json <script>.ps1
//
// NOT the regular blob URL (https://github.com/<owner>/<repo>/blob/...) -
// that one returns HTML and will not parse as JSON.
//
// Robustness of the remote fetch:
//
// - User-Agent : Chrome 131 + Sec-Ch-Ua client hints, so CDN/WAF
// defaults do not block the request as a bot.
// - TLS : minimum TLS 1.2; maximum auto-negotiated up to TLS 1.3.
// Certificate verification is ALWAYS on.
// - Retries : exponential backoff on 5xx (2^n x 3 s) and on network
// errors (2^n s). 4xx failures are NOT retried.
// - Tuning : env vars PSA_CONFIG_TIMEOUT (default 30s),
// PSA_CONFIG_MAX_RETRIES (default 3 attempts),
// PSA_CONFIG_QUIET (suppress retry-progress messages).
//
// HTTPS is strongly recommended over plain HTTP. Remote configs are
// fetched once per invocation; psa.py does not cache them on disk.
//
// -----------------------------------------------------------------------------
// Precedence (low -> high)
// -----------------------------------------------------------------------------
//
// 1. Built-in defaults baked into psa.py
// 2. Configuration file (this file, when active)
// 3. CLI flags (--enable, --disable, --include, --severity, --max-line-length)
// 4. Inline suppression comments (# psa-disable-line / next-line / file)
//
// =============================================================================
{
// ===========================================================================
// enable: rules to force-ENABLE
// ===========================================================================
//
// Turn ON rules that are disabled by default. Accepts `PSAxxxx` and
// `PSAPxxxx` codes. Unknown codes are silently ignored. Order does
// not matter.
//
// Default-disabled rules in psa.py 3.3.0:
//
// Generic rules (PSAxxxx):
// PSA4003 Long line exceeds max_line_length
// PSA6002 Cmdlet alias used (ls, cd, dir, where, ...)
// PSA9001 Function body exceeds max_function_lines
// PSA9002 External process invocation without $LASTEXITCODE check
//
// Project / pipeline convention rules (PSAPxxxx) - ALL OFF by default:
// PSAP0001 Phase function naming convention
// (Invoke-(Prep|Verify|Inst)PhaseNN_Name)
// PSAP0002 Required script identifier variables
// ($Script:ScriptVersion / ScriptHash / ScriptShortTag)
// PSAP0003 Inline revision-tag comments
// (# rNN:, # rNN+:, # ---- rNN: ----, # (rNN), ...)
// PSAP0004 End-of-file REVISION HISTORY / CHANGELOG comment blocks
//
// Built-in default: []
//
// Example - enable PSAPxxxx rules for a pipeline repository:
//
// "enable": ["PSAP0001", "PSAP0002", "PSAP0003", "PSAP0004"],
//
// Example - enable complexity metrics with a generous threshold:
//
// "enable": ["PSA9001"],
// "max_function_lines": 300,
// ===========================================================================
// disable: rules to force-DISABLE
// ===========================================================================
//
// Turn OFF rules that are enabled by default. Useful when a particular
// check generates too much noise for your codebase, or when a project
// intentionally violates a convention (e.g., plural function nouns).
//
// Built-in default: []
//
// Example - silence the TODO marker check and the plural-noun check:
//
// "disable": ["PSA4001", "PSA6003"],
// ===========================================================================
// PSA7001: PowerShell UTF-8 BOM enforcement
// ===========================================================================
//
// PSA7001 is a file-level rule (severity: warning, default ON) that fires
// when a .ps1 file lacks the UTF-8 BOM at byte offset 0. Required reading
// for ja-JP Windows PowerShell 5.1 environments: see SPEC.md section 4.28.
//
// Disable per project if you ship .ps1 files intended for PowerShell 7.x
// only AND you have a separate enforcement of UTF-8 (no-BOM) via lint
// tooling. For most projects, leave it on.
//
// Example - turn PSA7001 off for a PS 7.x-only project:
//
// "disable": ["PSA7001"],
// ===========================================================================
// PSA7002: Line-ending policy (LF-only / mixed) — NEW in 3.7.0
// ===========================================================================
//
// PSA7002 is a file-level rule (severity: warning, default ON) that fires
// when a .ps1 file contains at least one line terminated by LF without a
// preceding CR. Two message variants:
//
// - "all-LF" : the entire file uses LF-only line endings. Common
// when a file was authored on Linux/macOS without
// newline translation. Easy to fix by bulk-converting.
// - "mixed" : some lines are CRLF, others LF-only. Almost always
// caused by programmatic insertion (Python triple-
// quoted strings, shell heredocs, AI-agent file writes)
// into an otherwise CRLF file. Invisible to PowerShell's
// AST parser; the byte-count equality check is the only
// reliable detector. See SPEC.md section 4.28a.
//
// Disable per project if your .ps1 files are intentionally LF-only
// (e.g., PowerShell 7.x cross-platform-only projects on Linux/macOS)
// AND your downstream tooling (signtool, MSI authoring, PowerShell ISE)
// does NOT require CRLF. For most Windows-targeted projects, leave it
// on.
//
// Example - turn PSA7002 off for an LF-only cross-platform project:
//
// "disable": ["PSA7002"],
// ===========================================================================
// PSA7003: Non-ASCII character in script body (NEW in 4.2.0)
// ===========================================================================
//
// PSA7003 is a file-level rule (severity: warning, default ON) that fires
// when a .ps1 body contains any character above U+007F outside the UTF-8
// BOM. The repository CI source-format gate rejects non-ASCII bytes in
// .ps1 files, so this rule catches the defect locally first. The most
// common offenders are typographic characters introduced by AI/LLM edits
// and Markdown-to-code paste: em/en dashes, the section sign (U+00A7),
// smart quotes, the ellipsis (U+2026), and the no-break space (U+00A0).
// Findings report line, column, code point, and a friendly name.
//
// Example - turn PSA7003 off (NOT recommended; the CI ASCII gate is not
// configurable and will still fail the build):
//
// "disable": ["PSA7003"],
// ===========================================================================
// PSA8001: Function body hash drift across files (NEW in 3.2.0)
// ===========================================================================
//
// PSA8001 fires when psa.py is run over multiple files and a function
// with the same NAME exists in two or more of them with DIFFERENT
// normalized bodies. Use it to enforce that shared helper functions
// (Format-Elapsed, Write-Detail, Start-DebugTrace, ...) stay in sync
// across a family of related scripts.
//
// To silence false positives for functions that are INTENTIONALLY
// different per file (e.g. pipeline phase functions named identically
// but implementing different driver families), list them in
// psa8001_ignore_functions:
//
// "psa8001_ignore_functions": [
// // Exact match (case-insensitive):
// "Invoke-PrepPhase00_Initialize",
// "Show-Help",
// // Regex pattern (prefix with "regex:"):
// "regex:^Invoke-(Prep|Verify|Inst)Phase\\d{2}_"
// ],
//
// Built-in default: [] (no functions ignored)
// ===========================================================================
// PSA9001: Function body exceeds max_function_lines (NEW in 3.2.0)
// ===========================================================================
//
// Default OFF. Add "PSA9001" to "enable" above to opt in.
//
// Threshold (lines per function, inclusive of header and closing brace):
//
// "max_function_lines": 200,
//
// Built-in default: 200
// ===========================================================================
// PSAPxxxx: Project / pipeline convention rules (NEW family in 3.2.0)
// ===========================================================================
//
// PSAPxxxx rules encode OPINIONATED conventions tied to a specific
// pipeline style. They are ALL disabled by default and must be
// enabled explicitly via "enable" when your repository follows that
// convention.
//
// Currently shipped PSAPxxxx rules:
//
// PSAP0001 Phase function naming convention
// Pattern: Invoke-(Prep|Verify|Inst)PhaseNN_DescriptiveName
// Fires on: Invoke-Phase00, Invoke-VerifyHardware, etc.
// OK examples: Invoke-PrepPhase00_Initialize
// Invoke-VerifyPhase06_HardwareImpactAnalysis
// Invoke-InstPhase04_PostInstallVerification
//
// PSAP0002 Required script identifier variables
// Demands all three of:
// $Script:ScriptVersion (e.g., 'chipset-2026.05.17-r60')
// $Script:ScriptHash (e.g., 'a1b2c3d4e5f6')
// $Script:ScriptShortTag (composed of the above two)
//
// PSAP0003 Inline revision-tag comments (new in 3.3.0)
// Detects per-revision history embedded in source comments
// such as `# r42: fixed timezone bug`, `# r56+: ...`,
// `# ---- r42: SECTION NAME ----`, or `# (r42) note`.
// Such tags accumulate as untraceable noise; the canonical
// source of release history is `CHANGELOG.md`.
// Prose mentions ("# in r06 and earlier we did X") are NOT
// matched -- only unambiguous tag forms.
//
// PSAP0004 End-of-file REVISION HISTORY / CHANGELOG / VERSION HISTORY
// comment blocks (new in 3.3.0)
// Detects in-script blocks that duplicate `CHANGELOG.md`
// content. Fires once per matching header line; operator
// should relocate the contents to `CHANGELOG.md`.
//
// Example - Deploy-Drivers-style pipeline repository:
//
// "enable": ["PSAP0001", "PSAP0002", "PSAP0003", "PSAP0004"],
// ===========================================================================
// severity: minimum severity to REPORT
// ===========================================================================
//
// Issues whose severity is BELOW this threshold are filtered out before
// output. This affects what is printed; it does NOT change the exit code
// (the exit code is still 2 if any error was found, 1 if any warning was
// found, 0 otherwise - see SPEC section 9).
//
// Allowed values : "error" | "warning" | "info"
// Built-in default: "info" (i.e., everything is reported)
//
// Example - only show warnings and errors:
//
// "severity": "warning",
// ===========================================================================
// max_line_length: threshold for PSA4003 (long line)
// ===========================================================================
//
// Maximum number of visible characters per line before PSA4003 fires.
// Only takes effect when PSA4003 is enabled (it is disabled by default;
// add "PSA4003" to "enable" above, or pass --enable PSA4003 on the CLI).
//
// Must be a positive integer.
//
// Built-in default: 120
//
// Example - stricter 100-character limit:
//
// "max_line_length": 100
// ===========================================================================
// psap0005_relaxed_mode: PSAP0005 migration-mode flag (boolean, new in 4.0.0)
// ===========================================================================
//
// PSAP0005 is the broader LLM-assisted-maintenance guardrail; it
// detects ANY rNN reference inside a comment body (beyond the structured
// tag forms caught by PSAP0003). The default (strict) mode fires for
// every such occurrence.
//
// When this flag is set to true, four prose exemption patterns are
// applied during PSAP0005 analysis. A comment matching any of them is
// not reported:
//
// A. SECTION header (# SECTION rNN: ...)
// B. SPEC cross-reference ((rNN, SPEC §D.YY) / (rNN, SPEC D.YY))
// C. Added-in-release phrasing ((added|introduced|landed|ported)
// (in|with) (the )? (<script>)? rNN)
// D. Earlier-revisions prose ((earlier|previous|prior)
// (revisions|releases) ... rNN)
//
// Patterns NOT exempt (still fire in relaxed mode):
// - "As of rNN, ..." (forward-looking anchor)
// - "# rNN: ..." and "# (rNN)" (PSAP0003 already owns these lines
// when PSAP0003 is enabled; otherwise PSAP0005 fires)
//
// This flag is intended as a MIGRATION AID for repositories with
// significant pre-existing rNN-anchored prose. The recommended steady-
// state is false (strict), with a migration plan documented in the
// consumer SPEC.
//
// Default: false (strict mode). Repositories migrating from a legacy
// revision-tagging convention typically start with true and ratchet
// it down to false as they clean up.
//
// Example - migration mode:
//
// "psap0005_relaxed_mode": true
}