chore(license): enforce licence headers on PowerShell files - #369
Open
siloteemu wants to merge 3 commits into
Open
chore(license): enforce licence headers on PowerShell files#369siloteemu wants to merge 3 commits into
siloteemu wants to merge 3 commits into
Conversation
install.ps1 shipped without the MIT/copyright header that every other source file in the repo carries, because the header check never looked at PowerShell files at all: `licenserc.toml` did not include `**/*.ps1`, and the pre-commit hook's `types_or` list omitted `powershell`. Adding the glob alone is not enough. hawkeye has no built-in comment style for the `ps1` extension, so a file matched by `includes` but with no matching rule is classified `unsupported` and silently skipped while the command still exits 0 — the check would look green without inspecting the file. The explicit `[[rules]]` block mapping `ps1` to the `script` comment style is what makes the file actually get checked. With all three changes, `hawkeye check` reports 230 files, 0 changes, 0 conflicts, 0 unsupported, and `--fail-on-unknown` also passes. Signed-off-by: Teemu Kuusisto <teemu.kuusisto@amd.com>
`licenserc.toml` has enforced headers on `**/*.md` all along, but the pre-commit hook's `types_or` never listed `markdown`, so a commit touching only Markdown skipped the hook entirely and the missing header surfaced only in CI — the same gap that left PowerShell files unchecked. Add the tag so the list covers one identify tag per extension family in `includes`, with a comment recording why the two lists have to stay in step. Signed-off-by: Teemu Kuusisto <teemu.kuusisto@amd.com>
The licence header this branch adds puts a copyright sign in install.ps1, the first non-ASCII byte the file has ever carried, which makes PSScriptAnalyzer's PSUseBOMForUnicodeEncodedFile fire on it. Adding the BOM the rule asks for would be a silent functional regression. The documented install path is `irm ... | iex`, which hands the parser a string rather than a file, so the mark survives into that string and the parser glues it onto the first token. The param() block then stops being the script's first statement and all nine installer parameters disappear -- with zero parse errors to show for it. Measured on the BOM'd file: first char U+FEFF, parse errors 0, ParamBlock present False. So the file stays BOM-less and the rule is suppressed for it alone, via a file-scoped SuppressMessageAttribute on the param() block rather than a global ExcludeRules entry, so the rule keeps guarding any future PowerShell file. The attribute carries a comment explaining why, since the obvious "fix" reintroduces the regression. The remaining cost is cosmetic: Windows PowerShell 5.1 decodes the BOM-less file as the ANSI codepage and renders the copyright sign in that comment as mojibake. Signed-off-by: Teemu Kuusisto <teemu.kuusisto@amd.com>
siloteemu
force-pushed
the
chore/license-header-powershell
branch
from
September 9, 2026 10:07
19b9533 to
72b0311
Compare
siloteemu
marked this pull request as ready for review
September 9, 2026 10:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
install.ps1is the Windows installer — one of the first files anyone reads before runninganything from this project — and it shipped with no copyright or licence header.
The licence-header check did not catch that, and would not have caught any future PowerShell
file either.
hawkeye(run by thelicense-headersCI job and by the prek hook) takes itsfile list from
licenserc.toml'sincludes, which covered only.rs,.py,.shand.md. PowerShell files were invisible to it, so the check was passing because it neverlooked at the file, not because the file complied.
The non-obvious part: adding
**/*.ps1toincludesalone would not have been enough.hawkeye v7.0.0 has no built-in comment-style rule for the
ps1extension, so it classifiessuch files as
unsupported, skips them silently, and still exits 0 — surfaced only under--fail-on-unknown, which neither the CI job nor the hook passes. The explicit[[rules]]entry (
extensions = ["ps1"],style_out = "script") is what makes the check actuallyenforce anything. It is load-bearing, not redundant with
includes, and the config carries acomment saying so, so it is not pruned later as dead weight.
Changes
install.ps1.PSUseBOMForUnicodeEncodedFileforinstall.ps1alone, so the file can stayBOM-less (see below).
licenserc.toml: add**/*.ps1toincludes, plus the matching[[rules]]entry thatgives hawkeye a comment style for the extension.
.pre-commit-config.yaml: addpowershell(a verified realidentifytag) to the hook'stypes_or, so it fires on PowerShell files instead of skipping them..pre-commit-config.yaml: also addmarkdown, in a second commit.licenserc.tomlhasenforced headers on
**/*.mdall along, buttypes_ornever listed the tag, so aMarkdown-only commit skipped the hook entirely and a missing header surfaced only in CI —
the same gap, one line over. The list now carries one
identifytag per extension familyin
includes, with a comment recording why the two have to stay in step.The encoding consequence (third commit). The header's
©is the first non-ASCII byteinstall.ps1has ever carried, which makes PSScriptAnalyzer'sPSUseBOMForUnicodeEncodedFilefire on the file. The rule's remedy — add a UTF-8 BOM — is the wrong trade here, so the file
stays BOM-less and the rule is suppressed for it.
A BOM is incompatible with
irm ... | iex, which is the install command this README, therelease notes and the nightly notes all publish.
Invoke-RestMethodreturns a string, not afile, so the mark survives into it and the parser glues it onto the following token: the
leading
# Copyright ...comment becomes a command named#, and theparam()block is nolonger the script's first statement, so all nine installer parameters silently vanish.
Measured on the BOM'd file: first character
U+FEFF, parse errors 0,ParamBlock present False. Zero parse errors is what makes it dangerous — nothing announces the breakage.Documentation cannot fix that, either: the
irm ... | iexone-liner is already published inrelease notes, bookmarks and runbooks, and those copies keep pointing at
main. Mojibake in acomment is strictly less harmful than a silent functional regression, so the file keeps its
BOM-less encoding.
The suppression is deliberately the narrowest mechanism that works: a file-scoped
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseBOMForUnicodeEncodedFile', '')]onthe script's
param()block, not anExcludeRulesentry inPSScriptAnalyzerSettings.psd1.The rule therefore keeps guarding any future PowerShell file added to the repo. Verified both
ways: with the attribute the analyzer reports no findings on
install.ps1, and a fresh.ps1containing a
©still trips the rule. The attribute carries a comment explaining why the filemust stay BOM-less, so the next person does not "fix" it and reintroduce the regression.
The remaining cost is cosmetic and accepted: Windows PowerShell 5.1 decodes a BOM-less file as
the ANSI codepage, so the
©in that comment renders as mojibake there. The README isunchanged by this PR.
Risk: low — a comment header and check configuration; no product code path changes. No
Gherkin scenario is added: nothing a CLI user can observe changes, so this falls under the
carve-out for purely internal changes.
Test plan
hawkeye check-> exit 0,231 files, 0 changes, 0 conflicts, 0 unsupported.hawkeye check --fail-on-unknown-> exit 0.[[rules]]block removed,install.ps1reverts tounsupportedat exit 0(and exit 1 only under
--fail-on-unknown);hawkeye checkreportsadd install.ps1and exits 1;
prek run --files README.mdskips the hook without themarkdowntag and runs it withthe tag, so that addition is not vacuous either.
prek run --all-files-> all hooks pass, includingPSScriptAnalyzer.install.ps1was inserted byhawkeye formatrather than hand-typed, so itis byte-exact against the configured header text.
Encoding and installer checks (third commit):
Invoke-ScriptAnalyzer -Path install.ps1 -Settings PSScriptAnalyzerSettings.psd1(PSScriptAnalyzer 1.25.0, the version CI pins) -> no findings, exit 0. Not vacuous: a fresh
.ps1carrying a©and no suppression still reportsPSUseBOMForUnicodeEncodedFile, sothe rule is only silenced for this one file.
First 8 bytes of
install.ps1are23 20 43 6f 70 79 72 69— noef bb bf.The regression is checked the way it was found: read the file's bytes, decode to a string
and parse that string (what
irm ... | iexdoes). Result: first characterU+0023, parseerrors 0,
ParamBlock present True,param count 9, and PowerShell binds all nineparameters (
Channel,Repo,InstallDir,DownloadBase,ArchiveExtension,SigningPublicKeyPath,SigningPublicKeyPem,RequireSignature,NoPathUpdate). The sameprobe against a BOM'd copy gives
U+FEFF, parse errors 0,ParamBlock present False.The 5.1 lint leg cannot run off Windows; that half is covered by CI rather than locally.
If this PR fixes a bug, searched
tests/e2e-cucumber/expectations.tomlfor the fixed ticket ID and removed/narrowed any now-stale xfail rows. — Not applicable: this fixes no product bug and involves no xfail rows.