Skip to content

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 07 Sep 21:55
· 38 commits to main since this release
7246015

What's new in v2.2.0

A face for every state, and an audit behind it. The quokka was one image
wearing three names; she now has four, and a search that finds nothing
says so in her own voice. Behind that, six passes over the code found
thirty things worth fixing, including a guard that could miss a
supervisor's respawn and secrets reaching agents through a listener's
child processes.

Changed

  • New artwork, and three moods that are actually different. The mascot
    shipped as one file under three names, so "All quiet: nothing is
    listening" and the guard badge both showed the waving quokka. There is
    now a sleeping one for the empty state, a bust bold enough to read at
    badge size for the guard, and a new one for a search that matches
    nothing. The app icon, the README banner, and every screenshot are
    redrawn to match.
  • scripts/make_artwork.swift keeps an alpha channel the source already
    has. It used to recompute one from whiteness whatever it was given,
    which turned a transparent background opaque black and the white
    pinafore see-through.
  • The banner is a drawn asset rather than one composed by a script, so
    scripts/make_logo.swift and the two generated logo files are gone.
  • The README opens with the problem it solves and carries a nav row;
    docs/ARTWORK.md holds the prompts that draw the character.
  • Destructive buttons ask first. Clear History, both Release buttons,
    and Reset Defaults went straight through while every kill confirms.
  • Empty states tell the truth. A filtered list said "nothing is
    listening" while the header counted every port; the Workbench table had
    no empty or scanning state at all.
  • The detail sheets close properly: a real button with a name for
    VoiceOver, on Escape, instead of a fake traffic light. Ten icon-only
    buttons gained accessibility labels.
  • One vocabulary (Stop watching, Remove guard, Option-click), ":3000" in
    notification titles, and "free" readable in light mode.
  • Fewer wakeups: a successful scan no longer republishes to every view,
    the hidden scan runs at a background priority, and Settings stopped
    asking launchd for its login-item status on every redraw.

Fixed

  • The guard could miss a supervisor's respawn. Watched occupancy
    remembered a process name, so a server restarted under the same name
    looked like nothing had happened and the guard never fired.
  • wait --timeout 0 always said "still in use", because it never
    looked at the port before checking the clock.
  • Attribution walked the wrong chain. With a session pid to follow,
    the CLI stopped before reaching its own parents, so whoami named the
    wrong source and a lease taken by one agent could be refused to that
    same agent. A caller whose agent has no session id of its own now
    borrows its pid, the value exec stamps on what it starts, so a
    detached server and its own session match.
  • Claude Code installed through npm runs as node, matched no
    signature, and its live sessions read as ended, which let anyone stop
    its servers. Servers under a path containing a space (fnm's default)
    were classified Other rather than Node.js, and pm2 under fnm was not
    found.
  • A project name that arrived with the first full scan after a background
    one was not treated as a change, so rows kept a missing project. A CPU
    sample taken milliseconds after another showed a process at 50%.
  • A lease warning meant for people was collected and dropped.
  • A rule file with one PortNanny marker and not its pair was appended
    to, duplicating the block; the next run then deleted the person's own
    text between the two markers. list --mine --orphaned quietly applied
    one of the two. exec --range was dropped when it equalled the default.

Security

  • Command lines of a listener's children went into --json and MCP
    output unredacted, so a worker started with --token=... leaked. The
    redaction also missed digit-bearing names (S3_SECRET_KEY), JSON
    secrets, and header secrets.
  • A lease reason is capped and stripped of control characters, and so are
    process names and command lines: a process could name itself with escape
    sequences that rewrite the terminal reading portnanny list.
  • A tree kill could signal a recycled pid. Each child was checked
    against a name read at kill time, which compares the new process with
    itself and can never fail; the walk now carries the name it saw.
  • Output carries the short session key rather than the full one, so an
    agent cannot copy what it read and pass as another agent's session.
  • Every GitHub Action is pinned to a commit, the release token is scoped
    to the job that publishes, and the Homebrew cask is pinned to the
    checksum the build wrote rather than to a fresh download that could
    hash an error page.

📦 Install

Download PortNanny-2.2.0.dmg below, open it, and drag PortNanny to
Applications. Universal binary: runs natively on Apple Silicon and Intel;
requires macOS 13 (Ventura) or newer.

Not notarized (no Apple Developer account). First launch on macOS 15 or
newer: open it once, then System Settings → Privacy & Security → Open
Anyway
. On macOS 13 and 14: right-click PortNanny.app → Open → Open.
Either way, xattr -dr com.apple.quarantine /Applications/PortNanny.app
skips the dialog. Homebrew (brew install --cask portnanny) does this for you.

What's Changed

  • Full audit: 30 confirmed findings fixed, with tests by @mukes555 in #50
  • Close the last three security findings from the audit by @mukes555 in #51
  • Artwork prompts, and a README with a hook by @mukes555 in #52
  • New quokka artwork, and moods that differ from each other by @mukes555 in #53
  • Release 2.2.0 by @mukes555 in #54

Full Changelog: v2.1.1...v2.2.0