Skip to content

feat(cloud): add firewallStatus to Linux health reports#47

Merged
dbfx merged 5 commits intomainfrom
feat/linux-firewall-status
Mar 23, 2026
Merged

feat(cloud): add firewallStatus to Linux health reports#47
dbfx merged 5 commits intomainfrom
feat/linux-firewall-status

Conversation

@dbfx
Copy link
Contributor

@dbfx dbfx commented Mar 23, 2026

Summary

  • Add securityPosture.firewallStatus to the health report payload on Linux, reporting the active firewall tool (ufw, firewalld, nftables, iptables, or none), whether it's enforcing rules, allowed inbound ports (best-effort), and raw rule output (truncated to 3 KB)
  • Detection follows a priority order (ufw → firewalld → nftables → iptables → none), using the first tool found via which
  • Field is null on Windows/macOS (consistent with other server-only fields like fail2ban, auditd, etc.)
  • Also fixes OS release detection on Linux where systeminformation could return the kernel version instead of the distro version

Changed files

  • cloud-agent-types.ts — added firewallStatus type to securityPosture
  • platform/types.ts — added collectLinuxFirewallStatus() to PlatformSecurity interface
  • platform/linux/security.ts — full detection + parsing implementation (~160 lines)
  • platform/win32/security.ts, platform/darwin/security.tsreturn null stubs
  • cloud-agent.ts — wired into collectSecurityPosture(), added to default report object

Test plan

  • Deploy to a Linux server with ufw active — verify firewallStatus.tool === "ufw", active === true, and allowedPorts includes expected ports (e.g. 22, 80, 443)
  • Deploy to a Linux server with firewalld — verify service-to-port mapping works (e.g. ssh → 22)
  • Test on a Linux box with no firewall tools installed — verify tool === "none" and active === false
  • Verify health report on Windows/macOS omits firewallStatus (value is null)
  • Verify the dashboard Firewall tab renders correctly with the new payload

🤖 Generated with Claude Code

Detect the active firewall tool on Linux (ufw, firewalld, nftables,
iptables) and report its state under securityPosture.firewallStatus
in the health report payload. The field is null on Windows/macOS.

Also fixes OS release detection on Linux where systeminformation
could return the kernel version instead of the distro version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

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

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: d1df75d8a8

ℹ️ 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".

…iptables DROP policy

Address three review findings in collectLinuxFirewallStatus():

- Replace `which` + bare command names with `findBinary()` using
  absolute paths (/usr/sbin, /usr/bin, /sbin), matching the pattern
  used by the existing collectFirewallStatus() and other checks
- Detect nftables activity from `nft list ruleset` output (presence
  of tables) instead of relying on systemctl is-active nftables,
  which misses hosts where rules are loaded by boot scripts or
  cloud-init
- Treat a non-ACCEPT iptables INPUT policy (e.g. DROP) as active
  even when no explicit rules are present

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dbfx
Copy link
Contributor Author

dbfx commented Mar 23, 2026

@codex review

Copy link

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

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: 1ab0ba2f20

ℹ️ 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".

… chains

Address three review findings:

- ufw/firewalld: only return early when the front-end is actively
  enforcing. When inactive, fall through to probe nftables/iptables
  backends that may be filtering traffic (Docker, k8s, cloud-init).
- nftables active detection: check for `type filter hook input`
  chains instead of any table presence. NAT-only or dormant tables
  do not mean inbound traffic is being filtered.
- nftables port parsing: split ruleset into per-chain blocks and
  only collect allowed ports from input-hooked filter chains,
  excluding output/forward/nat rules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

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

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: 4a3af09c40

ℹ️ 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".

… iptables

- nftables port parsing now matches both tcp and udp dport rules,
  so UDP services (DNS/53, NTP/123, WireGuard/51820) are reported
- nftables branch only returns early when it found active input
  filter chains; otherwise falls through to the iptables probe so
  hosts that ship nft but enforce via iptables-legacy are detected

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

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

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: 6750511df7

ℹ️ 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".

- iptables: recognize multiport matcher format ("multiport dports
  80,443,8080") in addition to dpt:/dpts: forms
- firewalld: use --list-all-zones to capture interfaces/sources
  bound to non-default zones, falling back to --list-all

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dbfx dbfx merged commit 3eaab1d into main Mar 23, 2026
8 checks passed
@dbfx dbfx deleted the feat/linux-firewall-status branch March 23, 2026 04:16
Copy link

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

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: 57a277f001

ℹ️ 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".

rawRules = stdout.slice(0, RAW_RULES_MAX)

// Parse "ports:" line — e.g. "ports: 8080/tcp 9090/udp"
const portsLine = stdout.match(/^\s*ports:\s*(.+)/m)

Choose a reason for hiding this comment

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

P2 Badge Parse every firewalld zone before deriving allowed ports

Because --list-all-zones emits a separate ports:/services: stanza for each zone, the single stdout.match(...) here only captures the first occurrence. On multi-zone hosts—the exact case this branch is trying to support—any later active zone is ignored, so allowedPorts can miss the ports that are actually exposed.

Useful? React with 👍 / 👎.

const allowedPorts: number[] = []

try {
const { stdout } = await execFileAsync(nftPath, ['list', 'ruleset'], { timeout: CMD_TIMEOUT })

Choose a reason for hiding this comment

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

P2 Badge Invoke nft with -nn before extracting dports

I checked nft's upstream help text, which says -n must be specified twice to show Internet services numerically. Running nft list ruleset without -nn means common rules are printed as names like tcp dport ssh accept or udp dport domain accept, but the regexes below only match digits, so allowedPorts will be empty on many standard nftables configurations.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant