<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: QuantumCat</title>
    <description>The latest articles on DEV Community by QuantumCat (@quantumcatpy).</description>
    <link>https://dev.to/quantumcatpy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4185720%2F9b538500-bd81-43d6-8873-cfa555e00bf5.png</url>
      <title>DEV Community: QuantumCat</title>
      <link>https://dev.to/quantumcatpy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/quantumcatpy"/>
    <language>en</language>
    <item>
      <title>The Polish Pass — I Rewrote My Three Beginner Scripts to Match the App They Became</title>
      <dc:creator>QuantumCat</dc:creator>
      <pubDate>Thu, 15 Oct 2026 13:52:38 +0000</pubDate>
      <link>https://dev.to/quantumcatpy/the-polish-pass-i-rewrote-my-three-beginner-scripts-to-match-the-app-they-became-3mbb</link>
      <guid>https://dev.to/quantumcatpy/the-polish-pass-i-rewrote-my-three-beginner-scripts-to-match-the-app-they-became-3mbb</guid>
      <description>&lt;p&gt;A few weeks ago I wrote about turning three beginner Python scripts — a connection monitor, a port scanner, and a snapshot reporter — into the &lt;strong&gt;QuantumCat SOC Toolkit&lt;/strong&gt;, a desktop app with a real installer and a local AI analyst.&lt;/p&gt;

&lt;p&gt;There was a loose end, and it itched.&lt;/p&gt;

&lt;p&gt;The app had moved on. The GitHub repos hadn't. Anyone who clicked through from the toolkit to the original scripts still landed on the May 2026 versions: the monitor that didn't run, the scanner that couldn't say "closed," the process check that flagged "sync" for containing "nc." The repos are the front door to the whole project — they should show what the code learned, not just where it started.&lt;/p&gt;

&lt;p&gt;So: a polish pass. All three scripts, upgraded to the same standard as the shipped toolkit. Same repos, same honesty rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  The monitor: 57 lines → 373
&lt;/h2&gt;

&lt;p&gt;The original &lt;code&gt;net_watch.py&lt;/code&gt; polled &lt;code&gt;ss -tun&lt;/code&gt; every 3 seconds and diffed the output. It also had a syntax error on line 19, tagged the &lt;em&gt;local&lt;/em&gt; endpoint instead of the peer, and decided "private" by string prefix — which silently misses the entire 172.16.0.0/12 private range.&lt;/p&gt;

&lt;p&gt;The rewrite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Events are keyed on the peer endpoint&lt;/strong&gt; — the address your machine is actually talking to, which is the only one a watcher cares about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real IP classification&lt;/strong&gt; via the &lt;code&gt;ipaddress&lt;/code&gt; module: full RFC1918 (10/8, 172.16/12, 192.168/16), loopback, link-local, IPv6 ULA, and CGNAT space (100.64/10) — the range that taught me a failing test is a gift.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform collection&lt;/strong&gt; with psutil, because Windows has no &lt;code&gt;ss&lt;/code&gt; and the toolkit's users are mostly on Windows now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A silent baseline on the first poll&lt;/strong&gt;, so startup doesn't dump every existing connection on you as if it were news.&lt;/li&gt;
&lt;li&gt;Proper structure: a &lt;code&gt;ConnectionTracker&lt;/code&gt; that owns the diffing, a top-talkers count, and clean &lt;code&gt;process name (pid)&lt;/code&gt; labels on events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It went from "script I run in a terminal" to the actual engine the Monitor tab runs. Same job, done properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The port scanner: ~21 lines → 253
&lt;/h2&gt;

&lt;p&gt;The original prompted for an IP and walked 11 ports one at a time with a 1-second timeout, printing only the open ones. A full sweep could take eleven seconds of pure waiting, and silence meant… something. Closed and filtered are different answers; the original couldn't give either.&lt;/p&gt;

&lt;p&gt;The rewrite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Threaded&lt;/strong&gt; — 32 workers, so a sweep is a sweep, not a coffee break.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;25 well-known ports with service names&lt;/strong&gt;, because "443" means less to a learner than "443 — HTTPS."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three distinct states&lt;/strong&gt;: open, closed, filtered. All three get reported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional &lt;code&gt;--banner&lt;/code&gt; grab&lt;/strong&gt; — reads what a service volunteers when you connect, nothing more. Passive, and labelled as such.&lt;/li&gt;
&lt;li&gt;Input validation that explains itself instead of tracebacking at you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still standard library only. That was a rule from the start and it survived the rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The snapshot report: ~81 lines → 440
&lt;/h2&gt;

&lt;p&gt;The original shelled out through &lt;code&gt;os.popen&lt;/code&gt; and wrote a timestamped triage report. The soul was right — one file you can hand to a human — but the flagged-process check was a substring search, which is how "sync" ended up on a watchlist for containing the letters "nc."&lt;/p&gt;

&lt;p&gt;The rewrite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;psutil-based sections&lt;/strong&gt; throughout, with a &lt;strong&gt;computed connection summary&lt;/strong&gt; instead of raw dumps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The flagged-process check now compares exact process names&lt;/strong&gt; against a short list of known dual-use tools (nc, ncat, socat, nmap, masscan, hydra, tcpdump, and friends). Exact match only. And it's still labelled in plain sight as the basic heuristic it is — a hint to go look, never a detection claim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every section degrades gracefully&lt;/strong&gt;: if a data source isn't available, the report says "(unavailable)" and keeps going instead of dying halfway down the page.&lt;/li&gt;
&lt;li&gt;Reports still land as timestamped files, same as the original — that part never needed fixing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I deliberately did not change
&lt;/h2&gt;

&lt;p&gt;The git history.&lt;/p&gt;

&lt;p&gt;The broken first commits are still there — the missing parenthesis, the misindented &lt;code&gt;if&lt;/code&gt;, all of it. The new code sits on top as new commits, and the READMEs now tell both stories: what the script was in May 2026, and what the polish pass changed and why. Rewriting history to look like I knew what I was doing from day one would be a lie, and it would delete the most useful part for anyone learning behind me: the evidence that the embarrassing version is a normal place to start.&lt;/p&gt;

&lt;p&gt;The READMEs got the same treatment as the code — rewritten to match what the scripts actually do now, bugs described in the past tense, "Updated" sections that say plainly what changed.&lt;/p&gt;

&lt;p&gt;And yes, everything got tested before it got committed: the monitor catching a live loopback connection, the scanner against localhost with a real banner grab, the snapshot flagging an &lt;code&gt;nc&lt;/code&gt;-named process on purpose. Lesson zero from the first article still runs the shop: run the thing you ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother polishing free scripts?
&lt;/h2&gt;

&lt;p&gt;Because the repos are where people decide whether the toolkit is worth twelve dollars. A front door that says "this code is broken and I never fixed it" argues against the app behind it. Now the free scripts and the paid app are the same standard of work — the app just adds the GUI, the analyst, and the installer.&lt;/p&gt;

&lt;p&gt;If you're learning this stuff the way I did: keep your first versions. Commit the broken ones. Then, when you know more, go back and do the polish pass in public. The diff between who you were and who you're becoming is the best documentation you'll ever write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The upgraded scripts: &lt;a href="https://github.com/Quantumcat-py/Network-Monitor" rel="noopener noreferrer"&gt;Network-Monitor&lt;/a&gt; · &lt;a href="https://github.com/Quantumcat-py/Port_scanner" rel="noopener noreferrer"&gt;Port_scanner&lt;/a&gt; · &lt;a href="https://github.com/Quantumcat-py/Snapshot-Report" rel="noopener noreferrer"&gt;Snapshot-Report&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The first article (the build log): &lt;a href="https://dev.to/quantumcatpy/i-turned-three-beginner-python-scripts-into-a-windows-desktop-app-d8o"&gt;I Turned Three Beginner Python Scripts Into a Windows Desktop App&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The finished toolkit — $12, one-time, Windows + Linux, source included, 100% local: &lt;a href="https://quantumcatsoc.gumroad.com/l/quantumcat-soc-toolkit" rel="noopener noreferrer"&gt;https://quantumcatsoc.gumroad.com/l/quantumcat-soc-toolkit&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Turned Three Beginner Python Scripts Into a Windows Desktop App</title>
      <dc:creator>QuantumCat</dc:creator>
      <pubDate>Thu, 15 Oct 2026 01:54:57 +0000</pubDate>
      <link>https://dev.to/quantumcatpy/i-turned-three-beginner-python-scripts-into-a-windows-desktop-app-d8o</link>
      <guid>https://dev.to/quantumcatpy/i-turned-three-beginner-python-scripts-into-a-windows-desktop-app-d8o</guid>
      <description>&lt;h1&gt;
  
  
  I Turned Three Beginner Python Scripts Into a Windows Desktop App
&lt;/h1&gt;

&lt;p&gt;In May 2026 I was teaching myself cybersecurity the way a lot of people&lt;br&gt;
do: tutorials, notes, and a vague feeling that I didn't actually&lt;br&gt;
understand what my own computer was doing on the network. So I wrote&lt;br&gt;
three small Python scripts to find out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network-Monitor&lt;/strong&gt; (&lt;code&gt;net_watch.py&lt;/code&gt;, 57 lines) — poll &lt;code&gt;ss -tun&lt;/code&gt; every
3 seconds, diff against the last snapshot, print and log new
connections, tag each peer LOCAL or EXTERNAL, keep a top-talkers count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port_scanner&lt;/strong&gt; (~25 lines) — prompt for an IP, sequential
&lt;code&gt;connect_ex&lt;/code&gt; scan over 11 common ports with a 1-second timeout,
print the open ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot-Report&lt;/strong&gt; (~100 lines of &lt;code&gt;os.popen&lt;/code&gt;) — write a timestamped
triage report of the machine, plus a basic "suspicious process"
check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They were beginner scripts, and I mean that as a precise technical&lt;br&gt;
description.&lt;/p&gt;
&lt;h2&gt;
  
  
  The embarrassing parts (which were the education)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The committed monitor didn't run.&lt;/strong&gt; Line 19 is missing a closing&lt;br&gt;
parenthesis, and an &lt;code&gt;if&lt;/code&gt; further down is misindented. It sat on GitHub,&lt;br&gt;
publicly broken, because I never ran the committed copy. Lesson zero&lt;br&gt;
of shipping anything: run the thing you ship, from a clean checkout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My monitor tagged the wrong endpoint.&lt;/strong&gt; The script grabbed the first&lt;br&gt;
IP-looking token on each line — the &lt;em&gt;local&lt;/em&gt; endpoint, i.e. my own&lt;br&gt;
machine, forever. What a watcher cares about is the peer. It also&lt;br&gt;
classified "private" by string prefix (&lt;code&gt;10.&lt;/code&gt;, &lt;code&gt;192.168.&lt;/code&gt;, &lt;code&gt;127.&lt;/code&gt;),&lt;br&gt;
which silently misses the whole 172.16.0.0/12 private range — and&lt;br&gt;
CPython's &lt;code&gt;ipaddress&lt;/code&gt; module has opinions about CGNAT space&lt;br&gt;
(100.64.0.0/10) that a failing test had to teach me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My port scanner couldn't say "closed."&lt;/strong&gt; Open ports printed;&lt;br&gt;
everything else was silence. Closed (connection refused) and filtered&lt;br&gt;
(timeout) are different answers, and a scanner that can't tell them&lt;br&gt;
apart is only telling you a third of the story. It was also&lt;br&gt;
sequential — up to a second per port of just… waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My suspicious-process detector flagged "sync."&lt;/strong&gt; The check was a&lt;br&gt;
substring search of the &lt;code&gt;ps aux&lt;/code&gt; output for names like &lt;code&gt;nc&lt;/code&gt;. "Sync"&lt;br&gt;
contains "nc". A name heuristic is a hint to go look; it is not&lt;br&gt;
detection, and pretending otherwise sends you chasing ghosts.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rebuild
&lt;/h2&gt;

&lt;p&gt;I rewrote all three properly and combined them into one app, the&lt;br&gt;
&lt;strong&gt;QuantumCat SOC Toolkit&lt;/strong&gt;: a Tkinter GUI (stdlib only — no framework)&lt;br&gt;
with five tabs — Monitor, Port Scanner, Snapshot Report, AI Analyst,&lt;br&gt;
Settings/About.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The monitor parses &lt;code&gt;ss&lt;/code&gt; output into structured records, classifies
IPs properly, and keys events on the peer endpoint with clean
&lt;code&gt;process name (pid)&lt;/code&gt; labels. (On Windows, where there's no &lt;code&gt;ss&lt;/code&gt;, it
uses psutil with a &lt;code&gt;netstat -ano&lt;/code&gt; parser as fallback.)&lt;/li&gt;
&lt;li&gt;The scanner is threaded, covers 25 well-known ports with service
names, reports open/closed/filtered as distinct states, and does an
optional passive banner grab — it reads what a service volunteers,
nothing more.&lt;/li&gt;
&lt;li&gt;The snapshot report keeps the original's soul — one timestamped file
you can hand to someone — but every section degrades to an
"(unavailable)" line instead of crashing, and the flagged-process
check compares actual process names, labelled in the app as the
basic heuristic it is.&lt;/li&gt;
&lt;li&gt;Everything is covered by test suites, because of lesson zero.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The local AI analyst
&lt;/h2&gt;

&lt;p&gt;The fourth tab is the new idea. It collects what the other tabs found&lt;br&gt;
and produces a plain-English assessment in a fixed template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VERDICT: one line
What looks normal
What deserves a second look
Suggested next steps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs on a &lt;strong&gt;local model via Ollama&lt;/strong&gt; — plain HTTP to &lt;code&gt;localhost&lt;/code&gt;,&lt;br&gt;
the only network destination in the app besides your own scans. A&lt;br&gt;
security tool that phones your data home to a cloud AI would be a bad&lt;br&gt;
joke, so there is no cloud anything: no accounts, no telemetry, no&lt;br&gt;
analytics. And if you don't have Ollama, a built-in rule engine&lt;br&gt;
produces the same template from the same findings, so the app works&lt;br&gt;
out of the box either way. Ollama just writes smarter explanations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The packaging lesson (the biggest one)
&lt;/h2&gt;

&lt;p&gt;My first instinct was to ship the way my scripts lived: Linux, a&lt;br&gt;
folder, run it from a terminal. Two problems. The actual user machine&lt;br&gt;
was &lt;strong&gt;Windows&lt;/strong&gt;. And "works if you know the incantation" is not&lt;br&gt;
"works."&lt;/p&gt;

&lt;p&gt;An earlier build proved it: extract a ZIP, the executable bit gets&lt;br&gt;
dropped, and the file manager asks "open with what?" — dead on&lt;br&gt;
arrival for a normal person. So the standard became a rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It should feel like installing Wireshark, not like adopting a&lt;br&gt;
project.&lt;/strong&gt; Double-click, install, desktop shortcut, click the cat,&lt;br&gt;
app opens.&lt;/p&gt;

&lt;p&gt;What shipped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A real Windows &lt;strong&gt;&lt;code&gt;.msi&lt;/code&gt; installer&lt;/strong&gt; — per-user, no admin prompt,
Desktop and Start Menu shortcuts with the cat icon, clean uninstall
through Windows Settings.&lt;/li&gt;
&lt;li&gt;A Linux &lt;strong&gt;&lt;code&gt;.deb&lt;/code&gt;&lt;/strong&gt; for the Debian/Ubuntu family and a portable
&lt;strong&gt;&lt;code&gt;.tar.gz&lt;/code&gt;&lt;/strong&gt; (tar preserves the exec bits the ZIP lost).&lt;/li&gt;
&lt;li&gt;The full Python source included in the download, for transparency
and for anything the packaged builds don't cover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No terminal gymnastics on either platform. The only add-on is Ollama,&lt;br&gt;
and the included &lt;code&gt;Start_Here&lt;/code&gt; guide walks through installing it and&lt;br&gt;
pulling a model step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This is a learning and triage tool built by a self-taught developer.&lt;br&gt;
It is not a replacement for professional security software, and it is&lt;br&gt;
not a packet analyzer — Wireshark is still king there. This toolkit's&lt;br&gt;
job is watching, summarising, and explaining: what is my machine&lt;br&gt;
talking to, what's listening on it, and what does that probably mean,&lt;br&gt;
in words a person can act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The original scripts (flaws and all):
&lt;a href="https://github.com/Quantumcat-py/Network-Monitor" rel="noopener noreferrer"&gt;Network-Monitor&lt;/a&gt; ·
&lt;a href="https://github.com/Quantumcat-py/Port_scanner" rel="noopener noreferrer"&gt;Port_scanner&lt;/a&gt; ·
&lt;a href="https://github.com/Quantumcat-py/Snapshot-Report" rel="noopener noreferrer"&gt;Snapshot-Report&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The finished toolkit ($12, one-time, Windows + Linux, source
included):
&lt;a href="https://quantumcatsoc.gumroad.com/l/quantumcat-soc-toolkit" rel="noopener noreferrer"&gt;https://quantumcatsoc.gumroad.com/l/quantumcat-soc-toolkit&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're early in learning this stuff: build the bad tool. Then fix&lt;br&gt;
it in public. The fixing is where the understanding lives.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>ollama</category>
    </item>
  </channel>
</rss>
