docs: sync website + README + wizard guide + changelog with new features

docs/index.html (kportal.raczylo.com):
  - Features grid gains Bulk Generate, Sensitive Header Redaction,
    Verified Installer cards; Headless card subtext clarified to
    'logs to stderr'.
  - Keybindings: 'a' -> 'n' for Add (matches real binding).
  - Quick Install card notes SHA-256 + optional cosign verification
    and DRY_RUN / SKIP_COSIGN env vars.
  - New Bulk Generate usage tile with --dry-run hint; Headless tile
    redirects stderr.
  - HTTP Traffic Logging card mentions automatic header redaction
    and the wizard 'h' toggle.

README.md:
  - install.sh note expanded with DRY_RUN/SKIP_COSIGN table.
  - HTTP Traffic Logging section gains 'Toggling per-forward
    logging', 'Header redaction', and 'Advanced configuration'
    examples.
  - Headless mode clarified to log to stderr (2>kportal.log).
  - Troubleshooting note on accepted context-name characters.

WIZARD_USAGE.md:
  - Add binding corrected from 'a' to 'n'; 'e' (edit) row added.
  - 'h' httpLog toggle and Tab focus switch documented.
  - New 'Edit Forward Wizard' section noting same-port allowed and
    advanced httpLog preserved.
  - Esc-cancels-delete behaviour clarified.

CHANGELOG.md: [Unreleased] populated with Added / Changed / Fixed
entries for this session's user-facing work, dated 2026-05-06.

.kportal.yaml example: inline 'httpLog: true' comment on one
forward as a usage hint.
This commit is contained in:
2026-05-06 15:03:35 +01:00
parent 0c11838326
commit 62483f9475
5 changed files with 136 additions and 14 deletions
+1
View File
@@ -34,6 +34,7 @@ contexts:
port: 8080
localPort: 8080
alias: prod-api
httpLog: true # Enable HTTP traffic logging for this forward (press 'l' in the TUI)
# Forward to PostgreSQL database
- resource: service/postgres
+18 -1
View File
@@ -5,7 +5,24 @@ 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).
## [Unreleased]
## [Unreleased] - 2026-05-06
### Added
- `kportal generate --context=NAME [--config=PATH] [--dry-run]` subcommand for interactive bulk-add of forwards from a cluster. Walks namespace multi-select, service multi-select, and starting-port input; assigns consecutive local ports; emits one forward per port for multi-port services. Non-TCP ports are skipped and already-configured services are greyed out.
- HTTP log toggle in the add/edit wizard. Pressing `h` on the confirmation step toggles `httpLog: true/false` for the forward being added or edited. Advanced `httpLog` configuration set in YAML (`logFile`, `includeHeaders`, `maxBodySize`, `filterPath`) is preserved across edits.
- HTTP log header redaction. When `httpLog.includeHeaders: true`, sensitive headers (`Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, `X-Auth-Token`, `X-Csrf-Token`, `Proxy-Authorization`, `X-Access-Token`, plus any header whose name contains `token`/`secret`/`password`/`apikey`) have their values replaced with `[REDACTED]`. The header name is preserved. Always on, no opt-out.
- `install.sh` SHA-256 checksum verification. Every install verifies the downloaded archive against the release's `checksums.txt`. If `cosign` is on `PATH`, the checksums file's keyless cosign signature is also verified against the shared-actions reusable workflow identity. Set `DRY_RUN=1` to preview, `SKIP_COSIGN=1` to bypass cosign.
### Changed
- Headless mode (`kportal -headless`) now sends both structured and stdlib logs to stderr by default instead of `io.Discard`. `-v` still controls level (debug vs info), not destination.
- Context-name validator now permits common kubeconfig identifiers containing `@`, `.`, `:`, or `/` (e.g. `admin@home`, `user@cluster.example.com`, GKE dotted names, EKS ARNs).
- Edit-mode wizard now allows keeping the same local port. The port-availability check no longer rejects a forward's own port when editing it.
### Fixed
- `Esc` in the delete-confirmation dialog now cancels instead of confirming deletion (previously a data-loss bug).
- `Manager.Stop()` is now idempotent. Sequential or concurrent double-Stop no longer panics.
- Cosign cert-identity is now pinned to the actual signing workflow (`lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@refs/heads/main`); previously cosign verification always failed.
- Internal concurrency races in the forward manager (`currentConfig` access under lock, `rest.Config` copied before mutation, `ForwardWorker.Stop` wrapped in `sync.Once`, `Reload` no longer kills the health checker). No user-visible flag, but resolves panics some users hit.
## [0.1.5] - 2025-11-23
+46 -2
View File
@@ -71,7 +71,12 @@ brew install --cask lukaszraczylo/taps/kportal
curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
```
The installer downloads `kportal-<version>-checksums.txt` from the same release and verifies the archive's SHA-256 before installing. If [`cosign`](https://github.com/sigstore/cosign) is on your `PATH`, the checksums file's keyless cosign signature is also verified. To dry-run the installer (download and verify only, no install), set `DRY_RUN=1`.
The installer downloads `kportal-<version>-checksums.txt` from the same release and verifies the archive's SHA-256 before installing. If [`cosign`](https://github.com/sigstore/cosign) is on your `PATH`, the checksums file's keyless cosign signature is also verified against the shared-actions reusable workflow identity.
| Variable | Effect |
|----------|--------|
| `DRY_RUN=1` | Download and verify only; do not install |
| `SKIP_COSIGN=1` | Skip cosign signature verification (SHA-256 is still enforced) |
### Manual Download
@@ -255,10 +260,14 @@ Run without TUI for scripting and automation:
kportal -headless
```
Headless mode emits both structured and standard-library logs to stderr by default
(suitable for redirecting to a log file or systemd journal). The `-v` flag controls
log level (debug vs info), not destination.
Combines well with verbose mode for background operation:
```bash
kportal -headless -v &
kportal -headless -v 2>kportal.log &
```
### Validate Configuration
@@ -361,6 +370,37 @@ Press `Enter` on any entry to see full request/response details including:
- **Non-2xx** - Hide successful (2xx) responses
- **Errors** - Show only 4xx and 5xx responses
**Toggling per-forward logging:**
In the add/edit wizard, press `h` on the confirmation step to toggle `httpLog` on or
off for the current forward. The wizard preserves any advanced `httpLog` keys
(`logFile`, `includeHeaders`, `maxBodySize`, `filterPath`) you set in YAML.
**Header redaction:**
When `httpLog.includeHeaders: true` is set, sensitive header values are
automatically replaced with `[REDACTED]`. The header name is preserved so you can
see that an `Authorization` header was present without exposing its value. Redacted
headers include `Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`,
`X-Auth-Token`, `X-Csrf-Token`, `Proxy-Authorization`, `X-Access-Token`, and any
header whose name contains `token`, `secret`, `password`, or `apikey`. This is
always on and cannot be disabled.
**Advanced configuration:**
```yaml
forwards:
- resource: service/api
port: 8080
localPort: 8080
httpLog:
enabled: true
includeHeaders: true # values of sensitive headers are redacted
maxBodySize: 65536 # bytes; 0 = unlimited
filterPath: "/api/" # only log paths matching this substring
logFile: "api.log" # append entries to a file in addition to the in-memory ring
```
### Connection Benchmarking
Press `b` in the TUI to benchmark a selected forward. Configure:
@@ -425,6 +465,10 @@ kill <pid>
kubectl config get-contexts
```
Context names containing `@`, `.`, `:`, or `/` (e.g. `admin@home`,
`user@cluster.example.com`, GKE dotted names, EKS ARNs) are accepted by the
config validator.
## 🔧 Development
### Prerequisites
+16 -5
View File
@@ -1,17 +1,18 @@
# Interactive Wizards
kportal includes wizards for adding and removing port forwards from the running UI.
kportal includes wizards for adding, editing, and removing port forwards from the running UI.
## ⌨️ Quick Reference
| Key | Action |
|-----|--------|
| `a` | Add new forward |
| `n` | Add new forward |
| `e` | Edit selected forward |
| `d` | Delete forwards |
## Add Forward Wizard
Press `a` from the main view to start the wizard.
Press `n` from the main view to start the wizard.
### Steps
@@ -21,7 +22,7 @@ Press `a` from the main view to start the wizard.
4. **Resource** - Enter prefix, selector, or select service
5. **Remote Port** - Enter port on the resource
6. **Local Port** - Enter local port (validates availability)
7. **Confirm** - Review and optionally add an alias
7. **Confirm** - Review, optionally add an alias, and toggle HTTP logging
### Navigation
@@ -31,6 +32,16 @@ Press `a` from the main view to start the wizard.
| `Enter` | Confirm and proceed |
| `Esc` | Go back / Cancel |
| `Ctrl+C` | Cancel immediately |
| `h` | Toggle HTTP traffic logging (confirmation step, when alias not focused) |
| `Tab` | Switch focus between alias field and buttons (confirmation step) |
## ✏️ Edit Forward Wizard
Press `e` on a selected row to edit it. The wizard reuses the add flow with values
pre-filled. The local-port availability check skips the forward being edited, so
keeping the same local port is always allowed. Advanced `httpLog` settings
(`logFile`, `includeHeaders`, `maxBodySize`, `filterPath`) defined in YAML are
preserved when toggling `httpLog` with `h`.
## 🗑️ Delete Forward Wizard
@@ -45,7 +56,7 @@ Press `d` from the main view.
| `a` | Select all |
| `n` | Deselect all |
| `Enter` | Confirm deletion |
| `Esc` | Cancel |
| `Esc` | Cancel (does not confirm deletion) |
## 🎯 Resource Selection
+55 -6
View File
@@ -297,7 +297,40 @@
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">Headless Mode</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">Background operation for scripting and automation</p>
<p class="text-sm text-gray-600 dark:text-gray-400">Background operation for scripting and automation, logs to stderr</p>
</div>
</div>
</div>
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
<div class="flex items-start gap-4">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-violet-500 to-violet-600 flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300">
<i class="fas fa-magic-wand-sparkles text-white"></i>
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">Bulk Generate</h3>
<p class="text-sm text-gray-600 dark:text-gray-400"><code class="text-xs">kportal generate</code> discovers cluster services and bulk-adds forwards with consecutive ports</p>
</div>
</div>
</div>
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
<div class="flex items-start gap-4">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-fuchsia-500 to-fuchsia-600 flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300">
<i class="fas fa-user-secret text-white"></i>
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">Sensitive Header Redaction</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">HTTP log header values for <code class="text-xs">Authorization</code>, <code class="text-xs">Cookie</code>, tokens and similar are redacted automatically</p>
</div>
</div>
</div>
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
<div class="flex items-start gap-4">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-lime-500 to-lime-600 flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300">
<i class="fas fa-shield-halved text-white"></i>
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">Verified Installer</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">SHA-256 checksum verification on every install, with optional cosign signature check</p>
</div>
</div>
</div>
@@ -576,6 +609,7 @@
<code class="block whitespace-nowrap font-mono">curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash</code>
<div class="absolute top-3 right-3"><i class="fas fa-copy text-gray-500 group-hover:text-green-400 transition-colors duration-300"></i></div>
</div>
<p class="mt-3 text-xs sm:text-sm text-gray-600 dark:text-gray-400"><i class="fas fa-shield-halved text-green-500 mr-1"></i>Verifies SHA-256 against the release checksums file. If <code class="text-xs">cosign</code> is on <code class="text-xs">PATH</code>, the keyless cosign signature is verified too. Set <code class="text-xs">DRY_RUN=1</code> to preview, <code class="text-xs">SKIP_COSIGN=1</code> to bypass cosign.</p>
</div>
<div class="glass p-6 sm:p-8 rounded-xl shadow-modern hover:shadow-xl transition-all duration-300">
<div class="flex items-center mb-4">
@@ -635,11 +669,19 @@
</div>
<div class="glass p-4 sm:p-6 rounded-xl">
<h3 class="text-base sm:text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3 sm:mb-4"><i class="fas fa-server text-slate-500 mr-2"></i>Headless Mode</h3>
<div onclick="copyToClipboard('kportal -headless -v &', this)" class="relative bg-gradient-to-br from-gray-900 to-gray-800 text-gray-100 p-4 rounded-lg text-sm cursor-pointer group border border-gray-700 hover:border-slate-500 transition-all duration-300 mb-3">
<code class="font-mono">kportal -headless -v &</code>
<div onclick="copyToClipboard('kportal -headless -v 2>kportal.log &', this)" class="relative bg-gradient-to-br from-gray-900 to-gray-800 text-gray-100 p-4 rounded-lg text-sm cursor-pointer group border border-gray-700 hover:border-slate-500 transition-all duration-300 mb-3">
<code class="font-mono">kportal -headless -v 2&gt;kportal.log &amp;</code>
<div class="absolute top-3 right-3"><i class="fas fa-copy text-gray-500 group-hover:text-slate-400 transition-colors"></i></div>
</div>
<p class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Run without TUI for scripting and background operation.</p>
<p class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Run without TUI for scripting; logs are emitted on stderr.</p>
</div>
<div class="glass p-4 sm:p-6 rounded-xl">
<h3 class="text-base sm:text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3 sm:mb-4"><i class="fas fa-magic-wand-sparkles text-violet-500 mr-2"></i>Bulk Generate</h3>
<div onclick="copyToClipboard('kportal generate --context=my-cluster', this)" class="relative bg-gradient-to-br from-gray-900 to-gray-800 text-gray-100 p-4 rounded-lg text-sm cursor-pointer group border border-gray-700 hover:border-violet-500 transition-all duration-300 mb-3">
<code class="font-mono">kportal generate --context=my-cluster</code>
<div class="absolute top-3 right-3"><i class="fas fa-copy text-gray-500 group-hover:text-violet-400 transition-colors"></i></div>
</div>
<p class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Discover services in a cluster and bulk-add forwards with consecutive local ports. Add <code class="text-xs">--dry-run</code> to preview.</p>
</div>
</div>
@@ -656,7 +698,7 @@
<span class="text-xs sm:text-sm text-gray-700 dark:text-gray-300">Toggle</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 p-2 sm:p-3 bg-white dark:bg-gray-800 rounded-lg">
<kbd class="px-2 sm:px-3 py-1 sm:py-1.5 bg-gray-100 dark:bg-gray-700 rounded text-xs sm:text-sm font-mono font-semibold">a</kbd>
<kbd class="px-2 sm:px-3 py-1 sm:py-1.5 bg-gray-100 dark:bg-gray-700 rounded text-xs sm:text-sm font-mono font-semibold">n</kbd>
<span class="text-xs sm:text-sm text-gray-700 dark:text-gray-300">Add</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 p-2 sm:p-3 bg-white dark:bg-gray-800 rounded-lg">
@@ -747,7 +789,8 @@
- resource: pod/nginx
protocol: tcp
port: 80
localPort: 8080</code></pre>
localPort: 8080
httpLog: true # log HTTP traffic</code></pre>
</div>
</div>
@@ -913,6 +956,12 @@ contexts:
<div class="text-gray-500 dark:text-gray-500 text-xs mt-1">
<i class="fas fa-magic mr-1"></i>JSON highlighting, gzip decompression, binary detection
</div>
<div class="text-gray-500 dark:text-gray-500 text-xs">
<i class="fas fa-user-secret mr-1"></i>Sensitive header values (auth, cookies, tokens) redacted automatically
</div>
<div class="text-gray-500 dark:text-gray-500 text-xs">
<i class="fas fa-keyboard mr-1"></i>Press <kbd class="px-1 py-0.5 bg-gray-200 dark:bg-gray-700 rounded text-xs">h</kbd> in the add/edit wizard to toggle <code class="text-xs">httpLog</code>
</div>
</div>
</div>