From c21f297b3759089b018f430ecb13032e4ad9cacf Mon Sep 17 00:00:00 2001 From: Bianca Rosa Date: Mon, 12 Oct 2026 20:24:55 -0300 Subject: [PATCH 1/3] fix: validate dashboard assets instead of removed heading --- Dockerfile | 4 +++- scripts/validate-docker-dashboard.sh | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9512d5c..39c70f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,9 @@ RUN set -eu; \ done; \ test -s /tmp/dashboard.html; \ ! grep -q "Dashboard not embedded" /tmp/dashboard.html; \ - grep -q "HTTP Proxy Dashboard" /tmp/dashboard.html; \ + asset_path="$(grep -o 'src="[^"]*\.js[^"]*"' /tmp/dashboard.html | head -n 1 | cut -d '"' -f 2)"; \ + case "$asset_path" in "${api_prefix}/_next/"*) ;; *) echo "Dashboard JavaScript URL does not match ${dashboard_path}: ${asset_path}" >&2; exit 1;; esac; \ + wget -q -O /dev/null "http://127.0.0.1:13000${asset_path}"; \ wget -q -O /tmp/health.json "http://127.0.0.1:13000${api_prefix}/api/admin/healthz"; \ grep -q '"healthy"' /tmp/health.json diff --git a/scripts/validate-docker-dashboard.sh b/scripts/validate-docker-dashboard.sh index 6301dfa..bcb270c 100755 --- a/scripts/validate-docker-dashboard.sh +++ b/scripts/validate-docker-dashboard.sh @@ -65,11 +65,6 @@ if grep -q "Dashboard not embedded" "$tmp_dashboard"; then exit 1 fi -if ! grep -q "HTTP Proxy Dashboard" "$tmp_dashboard"; then - echo "Docker image did not serve the expected dashboard HTML" >&2 - exit 1 -fi - # HTML alone can pass while a prefix mismatch breaks every browser asset. asset_path="$(grep -o 'src="[^"]*\.js[^"]*"' "$tmp_dashboard" | head -n 1 | cut -d '"' -f 2)" case "$asset_path" in From 29a0c9b818746e9c6854464e7b208c0602613158 Mon Sep 17 00:00:00 2001 From: Bianca Rosa Date: Mon, 12 Oct 2026 20:27:29 -0300 Subject: [PATCH 2/3] test: verify sanitized proxy failures with a local upstream --- dashboard/e2e/dashboard.spec.ts | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/dashboard/e2e/dashboard.spec.ts b/dashboard/e2e/dashboard.spec.ts index c20f681..b223411 100644 --- a/dashboard/e2e/dashboard.spec.ts +++ b/dashboard/e2e/dashboard.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from '@playwright/test'; +import { createServer } from 'node:http'; test.describe('Netkit Dashboard E2E', () => { test.beforeEach(async ({ page }) => { @@ -75,19 +76,20 @@ test.describe('Netkit Dashboard E2E', () => { } }); - test('should handle request errors gracefully', async ({ page }) => { - // Fill in an invalid URL - const urlInput = page.getByPlaceholder(/api.example.com/i); - await urlInput.fill('http://invalid-domain-that-does-not-exist-12345.com'); - - // Click send - await page.getByRole('button', { name: /send/i }).click(); - - // Wait for error to appear - await page.waitForTimeout(5000); - - // Check that some error indication is shown - const errorIndicator = page.locator('text=/error|failed|could not/i').first(); - await expect(errorIndicator).toBeVisible({ timeout: 10000 }); + test('should display proxy failures without exposing raw error bodies', async ({ page }) => { + // Fail a real local upstream exchange without relying on public DNS behavior. + const upstream = createServer((request) => request.socket.destroy()); + await new Promise(resolve => upstream.listen(0, '127.0.0.1', resolve)); + try { + const address = upstream.address(); + if (!address || typeof address === 'string') throw new Error('Missing upstream address'); + await page.getByPlaceholder(/api.example.com/i).fill(`http://127.0.0.1:${address.port}/`); + await page.getByRole('button', { name: /send/i }).click(); + + await expect(page.getByText('502', { exact: true })).toBeVisible(); + await expect(page.getByText('[Body omitted: only complete JSON up to 64 KiB is retained]', { exact: true })).toBeVisible(); + } finally { + await new Promise((resolve, reject) => upstream.close(error => error ? reject(error) : resolve())); + } }); }); From a4bd1b4d4aa0bd04755f56bff49fb4715847f606 Mon Sep 17 00:00:00 2001 From: Bianca Rosa Date: Mon, 12 Oct 2026 20:27:30 -0300 Subject: [PATCH 3/3] chore(release): prepare v0.2.0 changelog --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76b5fe3..b10fb7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.0] - 2026-10-12 + +### ๐Ÿš€ Features +- Inspect HTTPS bodies with a trusted local CA +- Add trustworthy capture and cumulative proxy signals +- Add traffic investigation workspace and scoped overview +- Add focused alerting and durable incident evidence +- Add reproducible local demo and recorded walkthrough + + +### ๐Ÿ› Bug Fixes +- Record HTTPS CONNECT tunnels in request history +- Handle connection cleanup errors for CI lint +- Satisfy inspection lint and keep docs application agnostic +- Allow long polling through HTTPS inspection +- Polish capture status and inspection hierarchy +- Satisfy CI lint checks for incident handlers +- Validate dashboard assets instead of removed heading + + +### ๐Ÿ“š Documentation +- Align dashboard entry points with investigation workflow +- Replace demo video with native resolution recording +- Simplify readme and add screenshots from demo video + + +### ๐Ÿงช Testing +- Build current sources for every end-to-end suite +- Use named HTTP status in unavailable fixture +- Verify sanitized proxy failures with a local upstream + + +### โš™๏ธ Miscellaneous Tasks +- Add platform doctor scan and address platform findings +- Ignore macOS Finder metadata + + ## [0.1.1] - 2026-09-15 ### ๐Ÿš€ Features