Skip to content

fix(kindle-dedrm): compare firewall rule state against 'True', not truthiness - #3396

Merged
kyle-sexton merged 5 commits into
mainfrom
fix/mh-kindle-firewall-enabled
Aug 27, 2026
Merged

fix(kindle-dedrm): compare firewall rule state against 'True', not truthiness#3396
kyle-sexton merged 5 commits into
mainfrom
fix/mh-kindle-firewall-enabled

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

The issue asked for the premise to be verified on a real Windows machine before anything changed,
because static analysis alone could not tell a genuine enum hazard from a string-conversion
context that happens to behave. The premise is confirmed. Against a live disabled
NetFirewallRule on Windows 11 Pro 10.0.26200, PowerShell 7.6.5:

DisplayName: Network Discovery (UPnP-Out)
Type: Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Enabled
int: 2
bool: True          <- a DISABLED rule is boolean true
not: False          <- so `-not $rule.Enabled` never fires
eqTrue: False
toString: False

Plugin version 0.7.6 -> 0.7.7.

Fix

skills/manage/scripts/firewall.ps1, both branches the issue named:

  • enable (was line 72). if (-not $rule.Enabled) -> if ($rule.Enabled -ne 'True'). The
    old test was always false, so a disabled Kindle-blocking rule was reported
    already enabled, no change and never re-enabled. That is the failure the skill exists to
    prevent: after a sync, enable silently left Kindle for PC free to fetch its auto-update.
  • disable (was line 100). if ($rule.Enabled) -> if ($rule.Enabled -eq 'True'). The
    mirror fault: always true, so Disable-NetFirewallRule was called against rules that were
    already disabled and the already disabled, no change arm was dead.

Compared against the string 'True' rather than the fully-qualified
[...NetSecurity.Enabled]::True type literal, deliberately: the type only resolves once the
Windows-only NetSecurity module is loaded, whereas the string comparison holds for the enum, for
a CIM path that hands the property back already stringified, and for a plain [bool].

Each of the three has a test case, but they are not of equal strength, and the suite says so
in place rather than letting the count imply otherwise. The enum and string cases discriminate the
fix from the defect. The boolean case cannot: with a [bool] on the left, PowerShell converts the
right operand to [bool], and every non-empty string converts to $true, so 'True', 'False',
and any other literal behave identically there. It proves only that the fix did not break a
boolean-valued property, and it is named and commented to claim exactly that. (Raised by review;
the point is correct and the case was relabelled rather than deleted or oversold.)

On the third acceptance box (Show-State, was line 55). Audited under the same suspicion and
deliberately left unchanged. $enabled = $rule.Enabled is a display interpolation, not a
truthiness test, and interpolating the enum renders the member name, so check already printed
Enabled=False for a disabled rule. Two end-to-end tests pin that, and they pass both before and
after the fix, which is the evidence that it was never part of the defect. No truthiness test on
$rule.Enabled remains anywhere in the script.

Verification

New suite: plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1, the plugin's first
Pester file. Run with:

Invoke-Pester -Path plugins/kindle-dedrm/skills/manage/tests -Output Detailed

How the guards are reached without elevation. enable and disable call Test-IsElevated
and exit 2 before reaching the guard, and Test-IsElevated is defined inside the script, so
it shadows any stand-in a test could inject, and its [Security.Principal.WindowsPrincipal] call
is not mockable. Rather than assert on a copy of the source text, the suite lifts the two real
condition expressions out of the script's AST and evaluates them against rule objects. What runs
in the test is the same expression that runs in production, so the test cannot pass against a
source that was fixed only in a comment.

The check action needs no elevation and is driven end to end, in a child pwsh with a
Get-NetFirewallRule stub in its global scope. Child-process rather than in-process because
firewall.ps1 calls exit, which escapes an in-process & $ScriptPath and aborts the entire
Pester run (Pester issue 2669) instead of failing one test. Observed, not assumed: the first
attempt at an in-process invocation produced
InvalidOperationException: A 'break' or 'continue' statement … escaped from your code and zero
results for the whole file.

The comment naming that upstream behavior originally cited it as pester/Pester#2669, which the
comment-hygiene CI lane classifies as a tracker-ref:repo-issue violation inside a code
comment. It is now written in prose; that is the only reason for the third commit on this branch.

Red before green. Against the unfixed firewall.ps1 (test file unchanged): 5 failed / 6
passed
.

  • enable guard / fires for a disabled rule so the rule is re-enabled — FAIL
  • enable guard / is not a bare truthiness test — FAIL
  • disable guard / does not fire for an already-disabled rule — FAIL
  • disable guard / is not a bare truthiness test — FAIL
  • both guards … / reads plain "False"/"True" strings the same way — FAIL

The six that passed against the unfixed script did so correctly, and each is named rather than
counted:

  • the two check end-to-end cases, because Show-State was never part of the defect;
  • the enum cross-check, which is about the fixture, not the script;
  • enable guard / does not fire for an already-enabled rule and disable guard / fires for an enabled rule, because an enabled rule is the case a truthiness test got right by accident;
  • both guards … / does not break when Enabled arrives as a plain boolean, because a genuine
    [bool] is the one representation -not $rule.Enabled handled correctly. That case documents
    the contract; it is explicitly not one of the regression pins.

After the fix: 11 passed / 0 failed.

The enum cross-check compares the suite's locally declared stand-in against the real
NetSecurity type where it is loadable (False is 2, non-zero, renders "False"), and
self-skips where the module is absent, so the suite is not silently testing a fiction.

Gates

  • scripts/affected-tests.sh --explain now selects the new suite for firewall.ps1
    (references firewall.ps1). Before this PR the script's only selection was
    plugins/skill-quality/scripts/check-skill.test.sh (references cleanup.sh), which is the
    unanchored-substring hazard the tool's own header warns about, meaning firewall.ps1 had no
    real coverage at all.
  • scripts/affected-tests.sh selects exactly two suites for this change set: the new Pester file
    and plugins/skill-quality/scripts/check-skill.test.sh. --run executes the shell one and
    reports the Pester one as SELECTED / NOT RUN by design, because the runner will not guess a
    non-shell lane. The shell suite is covered in CI by the plugin-gate lane, which runs
    scripts/run-plugin-tests.sh over the whole corpus; the Pester suite was run directly, 11/11.
  • scripts/validate-plugins.sh — passed.
  • CHECK_SKILL_SKILLS_ROOT=plugins/kindle-dedrm/skills scripts/…/check-skill.sh manage
    PASS, 0 errors, 1 pre-existing warning (no Gotchas surface), unchanged by this PR.
  • scripts/check-changelog-parity.sh --check and --check-bump origin/main — both passed.
  • markdownlint-cli2 on the changelog — 0 issues.
  • scripts/check-shell-portability.sh is not applicable: this change set contains no shell files.

Related

Closes #3368

…uthiness

Get-NetFirewallRule's Enabled property is a NetSecurity enum whose members are
True = 1 and False = 2, so BOTH are non-zero and BOTH coerce to boolean $true.
Confirmed against a live disabled rule on Windows 11 / PowerShell 7.6.5:
[int] is 2 and [bool] is True.

The enable action's `if (-not $rule.Enabled)` was therefore always false: a
disabled Kindle-blocking rule was reported "already enabled" and never
re-enabled, which is exactly the state the skill exists to prevent. The disable
action's `if ($rule.Enabled)` had the mirror fault and called
Disable-NetFirewallRule against rules that were already disabled. Both now
compare against 'True', which holds for the enum, for an already-stringified
property, and for a plain [bool].

Show-State's `$enabled = $rule.Enabled` was audited under the same suspicion and
left alone: it interpolates for display, which renders the member name, so the
check action already printed Enabled=False correctly.

Regression coverage: the plugin's first Pester suite. Both branches sit behind
an elevation gate whose Test-IsElevated is defined inside the script and shadows
any injected stand-in, so the suite lifts the two REAL condition expressions out
of the script's AST and evaluates them against enum-valued, string-valued, and
boolean rule objects. The check action is driven end to end in a child pwsh,
because the script's `exit` escapes an in-process call and aborts the whole
Pester run. 5 of 10 cases fail against the unfixed script; all 10 pass after.

Closes #3368

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 4m 40s —— View job


Code review (/review:code-review)

  • Gather context (PR diff, CLAUDE.md/AGENTS.md, /review:code-review skill instructions)
  • Review firewall.ps1 changes (enable/disable guard fix)
  • Review new Pester test suite firewall.Tests.ps1
  • Review changelog/plugin.json version bump
  • Post findings

Summary

The core fix in firewall.ps1 is sound: comparing $rule.Enabled against the string 'True' (rather than truthiness or a [bool]/$true literal) is the right approach — PowerShell converts a string RHS to the LHS enum by member name, which is why -ne 'True' / -eq 'True' correctly discriminate NetSecurity.Enabled's True=1/False=2 members, while a bare $true literal would not (converts via numeric value instead, a subtlety the PR's own manual-verification transcript actually demonstrates: bool: True but eqTrue: False for a disabled rule). Show-State was correctly left alone, since interpolation there renders the enum member name rather than testing truthiness.

Left two inline findings on the new test file, both about the test suite itself rather than the production fix:

  1. plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1:38Join-Path (Split-Path -Parent $PSScriptRoot) 'scripts\firewall.ps1' uses a literal backslash, which is not a path separator on non-Windows pwsh. Since this repo's PowerShell ecosystem has no automated test-cmd (Pester suites are run manually per plugins/toolchain/reference/ecosystems/powershell.yaml), and pwsh is cross-platform, running this suite from a Mac/Linux box would fail every test that resolves $script:ScriptPath.
  2. plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1:125-138 — the PR description claims all three $rule.Enabled representations (enum, stringified, plain [bool]) are covered by tests, but I only found enum- and string-valued cases in the file; no case sets $rule.Enabled to a raw [bool]. Given the enum/bool conversion subtlety noted above, that path isn't actually proven by this suite.

Both are fixable in a few lines and don't affect the production script's correctness. I did not execute the Pester suite, affected-tests.sh, or check-changelog-parity.sh myself (no PowerShell/Pester runtime available in this environment, and this lane's Bash access is scoped to gh pr * commands only) — the PR body's described local runs/output are author-claimed and unverified by me.

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 24s —— View job


Security review complete

  • Gather context (PR diff, changed files, custom instructions)
  • Run skip-gate checks (PR open, security-relevant surface, no prior applicable review)
  • Review changed files for security issues per /review:security-review criteria
  • Post findings (or a clean-bill statement)

No security issues found.

This PR changes a local, admin-elevation-gated PowerShell utility
(plugins/kindle-dedrm/skills/manage/scripts/firewall.ps1), the plugin manifest version, the
changelog, and a new Pester test file. Reviewed for logic flaws, injection surfaces, and unsafe
handling of credentials/tokens per the security-review criteria:

  • firewall.ps1 lines 77 and 107 — the -ne 'True' / -eq 'True' comparisons operate on a fixed, hardcoded $RuleName (line 34) and a value pulled straight from Get-NetFirewallRule. No user- or network-controlled input reaches these branches, so there's no injection surface introduced by the change. The fallback behavior on an unexpected value (e.g. $null) is fail-safe in both directions: enable would re-enable, disable would leave the rule alone rather than turning off the block.
  • firewall.Tests.ps1 spawns a child pwsh process via a here-string built from $script:ScriptPath, which is derived from $PSScriptRoot (not external/user input), so no command-injection concern there either.
  • No GitHub Actions workflow, permissions, secrets handling, or dependency pins are touched by this PR.

This is a correctness fix to a firewall-state comparison (enum-vs-truthiness bug); it restores the
intended security control (blocking Kindle's outbound auto-update) rather than weakening it, and
introduces no new attack surface.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Last security-reviewed head: 08d750f4a5957af19a5a909a245c2e0ffdadcd08. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

Comment thread plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 Outdated
Comment thread plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 Outdated
@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a0391cb7a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1
The suite exercised the enum and stringified shapes of the Enabled property but
not a plain [bool], which is the third shape the `-eq 'True'` comparison was
chosen to tolerate. The new case passes against the UNFIXED script too, and that
is the point: a genuine boolean is the one representation the old truthiness
test handled correctly, so the case documents the contract rather than pinning
the regression. 11/11 after the fix; the same 5 regression cases fail before it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 41s —— View job


Security review complete

  • Gather context (PR diff, CLAUDE.md/AGENTS.md, /review:security-review skill instructions)
  • Run skip-gate checks (PR open, security-relevant surface, prior applicable review)
  • Review changed files for security issues
  • Post findings

Skip gate: no new review needed.

The only commit since the last security-reviewed head (5a0391cb7a08d0f2272907d775f5d9ef7cbb99e5, per the earlier "Last security-reviewed head" note on this PR) is 2c90e49, which changes exactly one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)

That change adds one more Pester test case ('reads a plain boolean the same way') covering a raw [bool] value for $rule.Enabled against the already-fixed guard expressions, plus an explanatory comment. It touches only test fixtures/assertions — no production code, no CI/workflow files, no dependency or permission changes. This has no security-relevant surface (skip-gate condition 2), and it doesn't alter anything the prior review already assessed on firewall.ps1/firewall.Tests.ps1's runtime behavior (skip-gate condition 3): that review already covered the fixed-string $RuleName, the Get-NetFirewallRule-sourced value with fail-safe fallback behavior, and the child-pwsh here-string built from a non-external $PSScriptRoot-derived path — none of which changed here.

No security issues found, and no new review is warranted for this head per the lane's skip gate.

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 57s —— View job


Code review (/review:code-review)

  • Gather context (PR diff, CLAUDE.md/AGENTS.md, /review:code-review skill instructions)
  • Review firewall.ps1 changes since the last review (unchanged in this push)
  • Review the new commit to firewall.Tests.ps1 (test(kindle-dedrm): cover a plain boolean Enabled in the firewall guards)
  • Post findings

Summary

This push adds one commit on top of the previously-reviewed 5a0391c, touching only
firewall.Tests.ps1 (+19/-1); firewall.ps1, plugin.json, and CHANGELOG.md are unchanged
since the last pass, so the production fix stands as previously assessed (sound: -eq/-ne 'True'
correctly discriminates the enum via PowerShell's RHS-converts-to-LHS-type rule, where a bare
$true/$false literal would not).

The new commit adds a 'reads a plain boolean the same way' case, directly responding to a gap
flagged in the prior review pass (no case exercised a raw [bool] Enabled). Left one new inline
finding on it:

  • plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1:144-155 — the new case doesn't
    actually prove what the PR description claims for the [bool] representation. With
    $rule.Enabled as a raw bool, PowerShell converts the guard's RHS string operand to bool by
    emptiness only — any non-empty string ('True', 'False', anything) converts to $true — so
    the test would pass unchanged even against a broken/inverted comparison, and can't distinguish
    the fix from the pre-fix truthiness test for this input shape. Doesn't affect the production
    fix's correctness (the script never receives a raw bool from Get-NetFirewallRule in practice);
    it's a test-coverage-efficacy note, not a functional bug.

Still outstanding from the prior pass (unchanged by this commit, not re-flagged as a new inline
comment to avoid duplicating the existing thread): the Join-Path (Split-Path -Parent $PSScriptRoot) 'scripts\firewall.ps1'
literal-backslash separator at
firewall.Tests.ps1:38
still won't resolve on non-Windows pwsh.

I did not execute the Pester suite myself (no Pester/PowerShell test runtime invoked in this
environment) — the reasoning above about PowerShell's comparison-operator type coercion is derived
from documented semantics and the same mechanism the PR's own manual-verification transcript
demonstrates for the enum case, not from running the suite.

Comment thread plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 Outdated
…e flags

The comment-hygiene lane classifies an owner/repo#N form inside a code comment
as a tracker-ref:repo-issue violation. The upstream Pester behavior the child
process works around is now named in prose instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 42s —— View job


Security review (/review:security-review)

  • Gather context (PR diff, CLAUDE.md/AGENTS.md, custom instructions)
  • Run skip-gate checks (PR open, security-relevant surface, prior applicable review)
  • Review changed files for security issues
  • Post findings

Skip gate: no new review needed.

The only commit since the last security-reviewed head (2c90e498a481ba9645db86bc8b8887041c5f7582, per the "Last security-reviewed head" note on this PR) is fc92227, which changes exactly one line:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
-        # (pester/Pester#2669). The child gets a Get-NetFirewallRule stub in its
+        # (Pester issue 2669). The child gets a Get-NetFirewallRule stub in its

This edits the text of a code comment only, dropping a cross-repo GitHub issue reference in favor of a plain-text description of the same upstream Pester bug. It touches no production code, no CI/workflow files, no dependency or permission changes, and no logic anywhere in the diff.

This has no security-relevant surface (skip-gate condition 2), and it doesn't change anything the prior reviews already assessed on firewall.ps1 / firewall.Tests.ps1's runtime behavior (skip-gate condition 3): the fixed-string $RuleName, the Get-NetFirewallRule-sourced value with fail-safe fallback behavior, and the child-pwsh here-string built from a non-external $PSScriptRoot-derived path are all unchanged.

No security issues found, and no new review is warranted for this head per the lane's skip gate.
· branch

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 51s —— View job


Code review (/review:code-review)

  • Gather context (PR diff since last reviewed head, CLAUDE.md/AGENTS.md, /review:code-review skill instructions)
  • Determine whether the skip gate applies to this push
  • Post findings

Summary

Skip gate: no new review needed.

The only commit since the last code-review pass on this PR (2c90e49, reviewed above) is fc92227, which touches exactly one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

The change is a single-line comment edit — # (pester/Pester#2669).# (Pester issue 2669). — replacing an owner/repo#N-shaped reference with prose so the repo's comment-hygiene lint doesn't flag it as a cross-repo tracker reference. No executable code, assertion, or test behavior changed. This is a trivial, non-functional edit with no meaningful review surface (skip-gate condition 3).

Two findings from the earlier review pass on this file remain outstanding but are unaffected by this commit and sit on lines this push didn't touch, so per this lane's high-signal bar (pre-existing issues on untouched lines are out of scope) they aren't re-flagged here:

  • The literal-backslash path join at firewall.Tests.ps1:38, which won't resolve on non-Windows pwsh.
  • The raw-[bool] test case added in 2c90e49 (now around firewall.Tests.ps1:144-155), which doesn't actually distinguish the fix from the pre-fix truthiness bug for that input shape.

No new issues found in this push.
·

…ference

The comment-hygiene lane rejects an issue reference in a code comment under two
distinct patterns: `owner/repo#N` as tracker-ref:repo-issue, and the prose form
"issue <N>" as tracker-ref:issue-reference. The comment now quotes the observed
error text, which is what a future reader needs anyway, and cites no tracker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 55s —— View job


Code review (/review:code-review)

  • Gather context (PR diff since last reviewed head, CLAUDE.md/AGENTS.md, /review:code-review skill instructions)
  • Determine whether the skip gate applies to this push
  • Post findings

Summary

Skip gate: no new review needed.

The only commit since the last code-review pass on this PR (fc92227, reviewed above) is e684b00, which touches exactly one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

The change is confined to the comment block above the check action, end to end context (around firewall.Tests.ps1:157-168): it drops the pester/Pester#2669 / Pester issue 2669 tracker-style reference entirely and replaces it with a prose description of the actual observed failure ("A 'break' or 'continue' statement ... escaped from your code"). No executable code, assertion, fixture, or test behavior changed — this is a non-functional comment edit with no meaningful review surface (skip-gate condition 3).

Two findings from earlier review passes remain outstanding but sit on lines this push didn't touch, so they aren't re-flagged as new inline comments here:

  • The literal-backslash path join at firewall.Tests.ps1:38 (Join-Path (Split-Path -Parent $PSScriptRoot) 'scripts\firewall.ps1'), which won't resolve on non-Windows pwsh.
  • The raw-[bool] test case (now around firewall.Tests.ps1:144-155), which doesn't actually distinguish the fix from the pre-fix truthiness bug for that input shape, since a string RHS converts to a bool LHS by emptiness only.

No new issues found in this push.
· branch

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 40s —— View job


Security review (/review:security-review)

  • Gather context (PR diff, CLAUDE.md/AGENTS.md, /review:security-review skill instructions)
  • Run skip-gate checks (PR open, security-relevant surface, prior applicable review)
  • Review changed files for security issues
  • Post findings

Skip gate: no new review needed.

The only commit since the last security-reviewed head (2c90e498a481ba9645db86bc8b8887041c5f7582, per the prior "Last security-reviewed head" note on this PR) is fc92227 followed by e684b00. fc92227 was already covered by the previous skip-gate pass. The new commit at this head, e684b00, touches exactly one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 10 +++++----
1 file changed, 6 insertions(+), 4 deletions(-)
-        # in-process `& $ScriptPath` and aborts the whole Pester run
-        # (Pester issue 2669). The child gets a Get-NetFirewallRule stub in its
-        # global scope, which the script picks up because it defines no function
-        # of that name itself.
+        # in-process `& $ScriptPath` and surfaces as
+        # "A 'break' or 'continue' statement ... escaped from your code",
+        # aborting the WHOLE container with no results rather than failing one
+        # test. The child gets a Get-NetFirewallRule stub in its global scope,
+        # which the script picks up because it defines no function of that name
+        # itself.

This rewords a code comment to quote the observed Pester error text instead of citing an issue number (avoiding the comment-hygiene lane's tracker-ref:issue-reference pattern for prose-form references, the same motivation as the prior fc92227 comment edit). It touches no production code
(firewall.ps1 is unchanged since the last review), no CI/workflow files, no dependency or permission changes, and no test assertion or fixture logic — only a comment string.

This has no security-relevant surface (skip-gate condition 2), and it doesn't change anything the prior reviews already assessed on firewall.ps1 / firewall.Tests.ps1's runtime behavior (skip-gate condition 3): the fixed-string $RuleName, the Get-NetFirewallRule-sourced value with fail-safe fallback behavior, and the child-pwsh here-string built from a non-external $PSScriptRoot-derived path are all unchanged.

No security issues found, and no new review is warranted for this head per the lane's skip gate.
· branch

…he weak case

Two review findings, both correct.

Join-Path does not split a child argument on `\`, so 'scripts\firewall.ps1' as
one segment survives as an ordinary filename on non-Windows pwsh and the whole
suite fails at ParseFile. Passed as separate child segments instead.

The plain-boolean case cannot discriminate the fix from the defect: with a
[bool] on the left, PowerShell converts the right operand to [bool] and every
non-empty string converts to $true, so 'True' and 'False' behave identically
there. It is now named "does not break when Enabled arrives as a plain boolean"
and carries a comment stating the limitation, rather than implying a regression
pin it cannot be.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 52s —— View job


Security review (/review:security-review)

  • Gather context (PR diff since last reviewed head, CLAUDE.md/AGENTS.md, /review:security-review skill instructions)
  • Run skip-gate checks (PR open, security-relevant surface, prior applicable review)
  • Review changed files for security issues
  • Post findings

Skip gate: no new review needed.

The only commit since the last security-reviewed head (e684b004a5a98be1457d15643c8c55751969fb02, per the prior "Last security-reviewed head" note on this PR) is 08d750f, which touches exactly one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 15 +++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)

This resolves the two outstanding code-review findings from earlier passes, both scoped to the test file only:

  • The $script:ScriptPath join at firewall.Tests.ps1:38 now passes 'scripts' and 'firewall.ps1' as separate Join-Path segments instead of one string with a literal backslash, so it resolves on non-Windows pwsh.
  • The raw-[bool] case (now firewall.Tests.ps1:148-160) is renamed from 'reads a plain boolean the same way' to 'does not break when Enabled arrives as a plain boolean' and gets a comment explaining it cannot discriminate the fix from the pre-fix truthiness bug for that input shape (string-to-[bool] coercion is emptiness-only), rather than implying full regression coverage.

No production code (firewall.ps1), CI/workflow files, dependency pins, or permissions are touched. Everything changed is test-fixture naming/path-resolution and an explanatory comment — no assertion logic changed, and no new execution path (e.g. a script-injection surface in the path join) was introduced: both segments passed to Join-Path are still fixed string literals, not derived from external input.

This has no security-relevant surface (skip-gate condition 2), and it doesn't change anything the prior reviews already assessed on firewall.ps1 / firewall.Tests.ps1's runtime behavior (skip-gate condition 3): the fixed-string $RuleName, the Get-NetFirewallRule-sourced value with fail-safe fallback behavior, and the child-pwsh here-string built from a non-external $PSScriptRoot-derived path are all unchanged.

No security issues found, and no new review is warranted for this head per the lane's skip gate.
· branch

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 45s —— View job


Code review (/review:code-review)

  • Gather context (PR diff since last reviewed head, CLAUDE.md/AGENTS.md, /review:code-review skill instructions)
  • Determine whether the skip gate applies to this push
  • Review new commit since last pass
  • Post findings

Summary

Skip gate: does not apply — this push directly resolves both open findings from the previous pass.

The only commit since the last code-review pass on this PR (e684b00) is 08d750f, touching one file:

plugins/kindle-dedrm/skills/manage/tests/firewall.Tests.ps1 | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

Both previously-outstanding findings are fixed exactly as suggested:

  1. Cross-platform path join (firewall.Tests.ps1:42) — Join-Path (Split-Path -Parent $PSScriptRoot) 'scripts\firewall.ps1' (literal backslash, broken on non-Windows pwsh) is now Join-Path (Split-Path -Parent $PSScriptRoot) 'scripts' 'firewall.ps1' (separate segments), with a comment explaining why. Resolves correctly on both Windows and non-Windows pwsh.

  2. Plain-[bool] test case mislabeled as a regression pin (firewall.Tests.ps1:157-168) — renamed from 'reads a plain boolean the same way' to 'does not break when Enabled arrives as a plain boolean', with an 8-line comment explaining exactly why this case can't discriminate the fix from the pre-fix truthiness bug (string→bool conversion is by emptiness only, so 'True'/'False'/anything are equally truthy against a bool LHS). This accurately scopes the claim to "doesn't break" rather than "proves the fix," matching what the assertion actually demonstrates.

I re-read the full test file end to end (lines 30-213) to confirm no regressions were introduced alongside these edits — the AST-lifting helper, the enum cross-check, both guard contexts, the string-representation case, and the end-to-end check tests are all unchanged and consistent with prior passes.

No new issues found in this push. Both inline findings from earlier in this review thread are now resolved; I'm not re-opening them.

I did not execute the Pester suite myself (no Pester/PowerShell test runtime invoked in this environment) — this assessment is based on reading the diff and reasoning about Join-Path segment-splitting and PowerShell's comparison-operator type-coercion semantics, consistent with the reasoning in earlier passes on this thread.
· branch

@kyle-sexton
kyle-sexton merged commit 0c15947 into main Aug 27, 2026
57 checks passed
@kyle-sexton
kyle-sexton deleted the fix/mh-kindle-firewall-enabled branch August 27, 2026 12:03
kyle-sexton added a commit that referenced this pull request Aug 28, 2026
…oss five plugins (#3459)

No linked issue

## Summary

A repo-wide `/improvement:find` scan surfaced seven executable scripts
across five plugins that mapped to **zero** test suites under
`scripts/affected-tests.sh`. The repo contract (AGENTS.md) treats a
zero-suite mapping as an error, and this is the same gap class that let
the kindle-dedrm firewall truthiness defect (#3396) ship undetected:
scripts whose only "coverage" was accidental substring selection of
unrelated suites. Writing the tests also forced out two latent defects
in the instruction-placement eval harness, fixed here.

## Fix

One sibling test suite per unmapped script, plus the two defect fixes:

- **wizard 0.2.4**: new `template.test.sh` (144 assertions) covering the
wizard library's fail-closed prompt gates, `_drain_tty` paste bypass,
`write_env` quoting/atomicity/permissions, `open_url` https-only
dispatch, gh secret/variable helpers (secret never on argv), stage
framing, and the EXIT trap.
- **songwriting 1.4.15**: new `datamuse.test.sh` (93 assertions), fully
offline via a curl PATH-shim stub that fails hard if it does not shadow
real curl. Covers the mode-to-relation table, TSV contract, family
merge/dedupe/re-sort, LIMIT handling, and transport failures.
- **prototype 0.9.6**: sibling suites for the canonical
`detect-ecosystems.sh` and both skill wrappers (91 assertions): marker
detection, glob-order pinning, near-miss plus non-marker manifests (so
widening the marker list fails), symlink/anchoring/`CLAUDE_PROJECT_DIR`
semantics, and wrapper delegation contracts. The scripts themselves are
unchanged.
- **kindle-dedrm 0.7.9**: new `sync-prep.test.sh` (73 assertions)
proving the script is print-only: PATH shims shadow `rm`/`pwsh`/`netsh`
with recording no-ops; "printed the command, ran nothing, deleted
nothing" is asserted over a call log plus tree snapshot; the
dry-run/live guard is tested in both directions (the firewall-bug
class); the printed firewall rule name is checked against
`firewall.ps1`'s actual `$RuleName`.
- **instruction-placement 0.11.11**: new `adherence-experiment.test.sh`
(49 cases via a stub CLI) plus two fixes the tests forced out: the
underscore scoring criterion was a constant (it grepped the whole edited
file, which always contains the seeded `_unitPrice`, so the published
underscore/both columns measured nothing; scoring now scans only the
`InvoiceTotal` body with an under-crediting fallback), and the
`--filler` flag was undocumented. `adherence-results.md` carries a
correction note; the experiment's conclusion is unchanged (it rests on
the correctly-scored `sealed` column).

## Verification

- Every previously-unmapped script now selects its sibling suite under
`scripts/affected-tests.sh --explain` (each was `UNMAPPED`, exit 1,
before), and `--run` over the full diff passes (7 suites).
- shellcheck (repo rcfile), `shfmt -d`, and
`scripts/check-shell-portability.sh` clean on all new suites; changelog
parity (`--check`, `--check-bump`, `--check-preserved`) green;
fixture-git-isolation, silent-skips, discriminating-skips,
orphaned-fixtures, and purged-em-dashes gates green.
- Each plugin's work was reviewed by an independent fresh-context
verifier: diff review, gate re-runs, adversarial assertion audit, and
independent mutation testing with byte-identity restoration proofs
(implementer + verifier mutation batteries: wizard 33+9, songwriting
23+10, prototype 19+10, kindle-dedrm 12+9). All verifier findings,
including one MEDIUM (the family-dedupe assertion could not distinguish
`unique` from `unique_by(.word)`) and several LOW precision gaps, were
closed with mutation-kill confirmation.

## Related

- #3396 (the shipped defect exemplifying this coverage-gap class)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T)_

Co-authored-by: Claude <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Aug 29, 2026
… bootstrap health (#3487)

No linked issue

## Summary

Two independent false signals found by an evidence-first improvement
scan, both of the same shape: a check that reported healthy when it was
not. Each is fixed and each now has a test that fails without the fix.

1. `scripts/affected-tests.sh` claimed coverage a file did not have,
because R3/R4 matched a basename as an unanchored substring. A file with
no suite of its own could select many suites and exit 0, so the repo's
"a changed file that maps to zero suites is an error" contract silently
did not apply. This is the gap class behind the kindle-dedrm firewall
defect (#3396).
2. `.claude/cloud-bootstrap.sh` reported dozens of failures per session
start for a perfectly healthy plugin registry, because `claude plugin
install --scope user -y` already leaves a plugin enabled, so the chain's
tail `plugin enable` exits 1 with "already enabled at user scope" and
the three steps were joined with `&&`. The failure count is the
bootstrap's only health signal, and the false alarms buried it.

## Fix

**Test selection.** A file now names another only when the basename
appears bounded on both sides by a character outside `[A-Za-z0-9_.-]`.
`/` is deliberately outside that class, so path-qualified, prose and
comment mentions all still count; a trailing run of `.` is sentence
punctuation; a basename the rule cannot spell falls back to the old
substring test rather than to zero coverage. Matching stays a basename
rule because the cross-plugin copy fan-out depends on it. Exposing the
false coverage revealed a real gap it had been masking: several Python
files whose only suite is `<dir>/tests/test_<stem>.py` were unreachable
by any name match, since those suites `import <module>` and never spell
the filename, so R2 gained that path arm.

**Bootstrap health.** The three subcommand exit statuses are now
advisory. Verification reads the end state once per run, over every
plugin `enabledPlugins` turns on, and counts a plugin failed only when
it is absent at user scope, present without `enabled: true`, or its own
directory under `plugins/` changed between the recorded `gitCommitSha`
and HEAD. Cases where the snapshot cannot be determined at all (no
resolvable HEAD, no registry, absent or null recorded sha, a commit this
clone lacks) fail closed with a named reason rather than reading as
healthy. An unreadable `plugin list --json` fails the batch in one line
instead of one warning per plugin.

## Verification

Measured, not asserted:

- **Selection hazard, end to end:** an uncovered hook body dropped into
a scratch clone selected **131 suites at exit 0** before; it is now
**UNMAPPED at exit 1**.
- **Sweep over every tracked file (3,455):** 534 files select fewer
suites (15.8% fewer selected-suite slots), 4 previously-UNMAPPED files
became mapped to the suites that genuinely test them, **nothing became
unmapped**. 25 files dropped to an empty selection, every one a markdown
context file whose basename had been landing inside a longer one, and
every one already covered by a class in `affected-tests-no-suite.txt`,
so they report as no-suite at exit 0.
- **Bootstrap, live on a real machine:** `72 enabled, 0 newly installed,
0 refreshed, 0 failed`, where the previous code reported every refresh
as failed.
- Suites: `affected-tests.test.sh` 56 assertions green (47 before); new
`.claude/hooks/cloud-bootstrap-plugins.test.sh` 32 assertions green,
discovered by the existing `find plugins .claude/hooks` roots with no
ci.yml change.

Both changes were reviewed by independent fresh-context verifiers that
re-derived the evidence rather than trusting it. The selector verifier
recomputed the full sweep itself, hand-read all 190 dropped
basename/enclosing-token pairs (only two name the real file, and both
keep their suites through other bounded mentions), proved a
direct-coverage invariant over all 3,455 files with zero missing a suite
that genuinely names it, and killed 8 of its own 10 mutations. The
bootstrap verifier ran 19 fail-open probes (glob and space-bearing ids,
`declare -A` re-entry, duplicate ids, degenerate list JSON and registry
shapes, no-git-repo, `set -u` interaction) without constructing a
fail-open, and its first pass **rejected** an earlier version that still
printed `0 failed` for five bad end states; those five are now pinned by
tests, along with the extraction anchors and the block's exit status,
since a nonzero exit there would abort the whole bootstrap under `set
-e`.

## Related

- #3396 (the shipped defect exemplifying the false-coverage class)
- A third scan candidate, a 43x speedup of the shell-portability scan,
is deliberately **not** in this PR. A verifier found a correctness
regression in it, so it is parked unmerged on
`wip/portability-perf-unverified` with the defect, the reproducer and
the fix shape recorded in its commit message.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kindle-dedrm: firewall.ps1 truthiness checks on $rule.Enabled likely misclassify disabled rules

1 participant