Skip to content

feat: make /allowlist and /redaction pages for cli#77

Open
aspectrr wants to merge 27 commits intomainfrom
aspectrr/allowlist-redaction-pages
Open

feat: make /allowlist and /redaction pages for cli#77
aspectrr wants to merge 27 commits intomainfrom
aspectrr/allowlist-redaction-pages

Conversation

@aspectrr
Copy link
Copy Markdown
Owner

Description

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code style update (formatting, renaming)
  • Code refactor (no functional changes)
  • Configuration change
  • Test update

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Release Notes

Labels

Copilot AI review requested due to automatic review settings March 15, 2026 20:50
@gitguardian
Copy link
Copy Markdown

gitguardian bot commented Mar 15, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
28773915 Triggered Generic High Entropy Secret b7a4332 fluid-cli/internal/tui/redaction.go View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds dedicated TUI screens for managing read-only command allowlists and log redaction patterns, and exposes subcommand restriction metadata for UI display.

Changes:

  • Introduces /allowlist and /redaction TUI flows (models, views, close messages) with persistence via config save.
  • Removes allowlist/redaction fields from the generic settings screen.
  • Exposes subcommand restriction data from shared/readonly through fluid-cli/internal/readonly, with tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
shared/readonly/validate.go Exposes subcommand restriction metadata to callers.
fluid-cli/internal/readonly/validate.go Adapts shared restriction metadata for the CLI (map → sorted slice).
fluid-cli/internal/readonly/validate_test.go Adds coverage for restriction metadata shape/sorting.
fluid-cli/internal/tui/messages.go Adds close messages for new allowlist/redaction screens.
fluid-cli/internal/tui/model.go Wires /allowlist and /redaction commands and delegates to new sub-models.
fluid-cli/internal/tui/allowlist.go New allowlist editor screen (list/add/delete) backed by config.
fluid-cli/internal/tui/allowlist_test.go Tests allowlist editor behaviors.
fluid-cli/internal/tui/redaction.go New redaction pattern editor with live preview backed by config.
fluid-cli/internal/tui/redaction_test.go Tests redaction editor behaviors.
fluid-cli/internal/tui/settings.go Removes allowlist/redaction fields from settings UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +452 to +454
result := make(map[string]map[string]bool)
for k, v := range subcommandRestrictions {
result[k] = v
Comment on lines +17 to +18
result := make(map[string][]string, len(readonly.SubcommandRestrictions()))
for cmd, subs := range readonly.SubcommandRestrictions() {
Comment on lines +155 to +162
m.addErr = "command already in allowlist"
return m, nil
}
}
m.userCmds = append(m.userCmds, newCmd)
sort.Strings(m.userCmds)
m.cfg.ExtraAllowedCommands = m.userCmds
m.mode = allowlistModeList
Comment on lines +170 to +180
case "d":
if m.mode == allowlistModeList {
totalBuiltins := len(m.builtinCmds)
if m.selected >= totalBuiltins {
idx := m.selected - totalBuiltins
m.userCmds = append(m.userCmds[:idx], m.userCmds[idx+1:]...)
m.cfg.ExtraAllowedCommands = m.userCmds
if m.selected >= len(m.builtinCmds)+len(m.userCmds) && m.selected > 0 {
m.selected--
}
m.ensureVisible()
Comment on lines +171 to +180
case " ":
if m.mode == redactionModeList && m.selected == 0 {
m.cfg.Redact.Enabled = !m.cfg.Redact.Enabled
}
return m, nil

case "e":
if m.mode == redactionModeList && m.selected == 0 {
m.cfg.Redact.Enabled = !m.cfg.Redact.Enabled
}
m.previewBefore = ""
m.previewAfter = ""
m.previewErr = ""
m.selected = 1 + len(m.customPatterns) - 1
Comment on lines +370 to +387
if m.addErr != "" {
b.WriteString(m.styles.error.Render(m.addErr))
b.WriteString("\n")
}

if m.previewBefore != "" && m.previewErr == "" {
b.WriteString("\n")
b.WriteString(m.styles.section.Render("--- Live Preview ---"))
b.WriteString("\n")

b.WriteString(m.styles.dimmed.Render("Before: "))
b.WriteString(m.previewBefore)
b.WriteString("\n")

b.WriteString(m.styles.dimmed.Render("After: "))
b.WriteString(m.previewAfter)
b.WriteString("\n")
}
Comment on lines +493 to +504
func renderHighlighted(text string, style lipgloss.Style) string {
re := regexp.MustCompile(`\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b|` +
`\b[A-Za-z0-9+/]{20,}=*\b|` +
`\bAKIA[0-9A-Z]{16}\b|` +
`-----BEGIN [A-Z ]+PRIVATE KEY-----|` +
`\b(postgres|mysql|mongodb|redis)://[^\s]+`)
locs := re.FindAllStringIndex(text, -1)
if len(locs) == 0 {
return text
}
return renderHighlightedLocs(text, locs, style)
}
Comment on lines +372 to +407
// Handle AllowlistCloseMsg
if closeMsg, ok := msg.(AllowlistCloseMsg); ok {
m.inAllowlist = false
m.state = StateIdle
if closeMsg.Saved {
m.cfg = m.allowlistModel.GetConfig()
if err := m.cfg.Save(m.configPath); err != nil {
m.addSystemMessage(fmt.Sprintf("Failed to save config: %v", err))
} else {
m.addSystemMessage("Allowlist saved.")
}
} else {
m.addSystemMessage("Allowlist cancelled.")
}
m.updateViewportContent(false)
m.textarea.Focus()
return m, nil
}

// Handle RedactionCloseMsg
if closeMsg, ok := msg.(RedactionCloseMsg); ok {
m.inRedaction = false
m.state = StateIdle
if closeMsg.Saved {
m.cfg = m.redactionModel.GetConfig()
if err := m.cfg.Save(m.configPath); err != nil {
m.addSystemMessage(fmt.Sprintf("Failed to save config: %v", err))
} else {
m.addSystemMessage("Redaction patterns saved.")
}
} else {
m.addSystemMessage("Redaction cancelled.")
}
m.updateViewportContent(false)
m.textarea.Focus()
return m, nil
@claude
Copy link
Copy Markdown

claude bot commented Mar 15, 2026

Code Review

Good overall structure — the two new TUI screens are well-organized, follow the existing Bubbletea patterns, and are backed by reasonable test coverage. A few issues worth addressing before merge:


Bugs

1. selected cursor is wrong after adding a custom redaction pattern (redaction.go, enter handler)

m.selected = 1 + len(m.customPatterns) - 1  // = len(m.customPatterns)

Custom patterns start at index 1 + len(builtinPatterns) (6 builtins), so the newly added item is at absolute index 1 + 6 + len(m.customPatterns) - 1. The current formula ignores len(builtinPatterns), so the cursor ends up pointing at an unrelated builtin row. Fix:

m.selected = 1 + len(builtinPatterns) + len(m.customPatterns) - 1

2. Tab and Shift+Tab cycle in the same direction (redaction.go ~line 996-1022)

Both handlers do 0→1 and 1→0 identically. Shift+Tab should go in the opposite direction (or at least one of them should be removed, since with only two fields there's no practical difference, but the duplicate code is confusing).

3. Unused var cmd tea.Cmd declarations in model.go (~lines 690, 698)

if m.inAllowlist {
    var cmd tea.Cmd                               // declared but never used
    allowlistModel, cmd := m.allowlistModel.Update(msg)  // shadows it with :=

The var cmd tea.Cmd line is dead code — Go's := creates a new cmd. This would be flagged by go vet. The fix is just to drop those var declarations.


Design / Correctness Issues

4. Immediate config mutation before Ctrl+S

In both models, m.cfg.ExtraAllowedCommands = m.userCmds (allowlist) and m.cfg.Redact.CustomPatterns = m.customPatterns / m.cfg.Redact.Enabled = !m.cfg.Redact.Enabled (redaction) are written to the config pointer immediately on every add/delete/toggle — before the user presses Ctrl+S.

When the user presses Esc (Saved: false), the disk file isn't written, but the in-memory *config.Config has already been mutated. Since the parent Model holds the same pointer, those changes are silently "live" in the session even when the user chose to cancel. Either:

  • Buffer changes locally and only write to m.cfg on Ctrl+S, or
  • Deep-copy the config on open and discard the copy on cancel.

5. renderHighlighted uses a hardcoded regex disconnected from builtinPatterns (redaction.go ~line 1267)

The highlight regex in renderHighlighted is a static string. If a builtin pattern is ever added or changed, this function won't be updated. Consider building the highlight regex from builtinPatterns at init time so they stay in sync.

6. input == "allowlist" (without slash) in command handlers (model.go ~line 721, 735)

Other slash commands in the codebase only match with the leading /. Allowing bare allowlist or redaction as input means those words can't be sent to the LLM as plain text. This is at minimum inconsistent with the other handlers.


Minor

7. GetConfig() returns the same pointer passed in — the m.cfg = m.allowlistModel.GetConfig() assignment in model.go is a no-op, since it's the same pointer. The save path works correctly because the parent already holds that pointer, but the assignment is misleading. Document or remove it.

8. Section headers always render even when scrolled past them (allowlist.go View()) — when visibleStart > len(m.builtinCmds), the "--- Builtin Commands ---" header still renders with no items under it. Small visual glitch but worth fixing.


What's Good

  • Regex validation before adding custom patterns is solid.
  • Live preview with recomputePreview() is a nice UX touch.
  • Tests cover the happy path, duplicate detection, empty input, builtin-delete no-op, and close/save messages.
  • The settings screen cleanup (removing Redaction/Allowlist fields) is clean and intentional.

aspectrr and others added 5 commits March 21, 2026 11:58
- Add Kafka capture config and sandbox stub REST handlers with tests
- Add kafkastub manager and transport for daemon-side Redpanda simulation
- Add daemon Kafka orchestration and agent client integration
- Add Redpanda e2e integration test and demo setup/reset scripts
- Add customer logo images and LogoMarquee to landing page
- Move original product demo to /product route; update scripted demo colors
- Fix tickerMockStore to implement new Kafka store methods

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused wrapper functions (attachKafkaStubs, kafkaBrokerConfigForRequest, captureStatusToLocal/State)
- Fix unchecked error returns on deferred Close calls throughout daemon, kafkastub, and integration tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude bot commented Apr 7, 2026

Code Review

This PR adds /allowlist and /redaction TUI pages, a Kafka capture/stub system (daemon + API + proto), cloud-init ISO generation, and several daemon improvements. Solid work overall with good test coverage for the TUI components. A few issues worth addressing before merging.


Critical: Nil pointer dereference in three REST handlers

File: api/internal/rest/kafka_handlers.go

The pattern below is repeated in handleGetKafkaCaptureConfig, handleUpdateKafkaCaptureConfig, and handleDeleteKafkaCaptureConfig:

cfg, err := s.store.GetKafkaCaptureConfig(r.Context(), id)
if err != nil || cfg.OrgID != org.ID {   // PANIC if err != nil (cfg is nil)

When GetKafkaCaptureConfig returns an error, cfg is nil. Evaluating cfg.OrgID will panic rather than returning the not-found response. Fix by splitting the check so the error is handled before dereferencing cfg.


Security: AllowAutoTopicCreation in Kafka producer

File: fluid-daemon/internal/kafkastub/transport_kafka_go.go

The Kafka writer has AllowAutoTopicCreation set to true. This will silently create topics on the source Kafka broker if they do not exist. For a capture/replay system that is read-oriented, auto-creating topics on the broker being captured is likely unintended and could cause surprises in production environments. Consider defaulting to false.


Test coverage gaps for REST handlers

File: api/internal/rest/kafka_handlers_test.go

Only 2 of the 9 handlers have tests (handleCreateKafkaCaptureConfig and handleListSandboxKafkaStubs). Missing coverage for:

  • handleGetKafkaCaptureConfig, handleUpdateKafkaCaptureConfig, handleDeleteKafkaCaptureConfig
  • Kafka stub lifecycle: handleGetSandboxKafkaStub, start/stop/restart transitions
  • Error paths (store errors, not-found, org mismatch)

The project CLAUDE.md states every code change needs tests.


Minor: Duplicate newKafkaManager with inconsistent signatures

Two private functions with the same name exist in different packages:

  • fluid-daemon/internal/agent/kafka.go: newKafkaManager(baseDir, logger, store) creates its own redact.New() internally
  • fluid-daemon/internal/daemon/kafka.go: newKafkaManager(baseDir, redactor, logger, store) accepts an injected redactor

The inconsistency means the agent package always uses default redaction with no way to override it for testing. Recommend aligning to the injected pattern used in daemon.


Minor: StatePaused declared but never used

File: fluid-daemon/internal/kafkastub/manager.go

StatePaused = "paused" is declared as a state constant but is never referenced in any transition logic. Either implement pause/resume transitions or remove the constant to avoid dead code.


Minor: Direct sentinel comparison instead of errors.Is

File: fluid-daemon/internal/daemon/kafka.go

The daemon uses err == kafkastub.ErrNotFound (direct comparison) while the REST handlers use errors.Is correctly. Prefer errors.Is(err, kafkastub.ErrNotFound) for consistency and future-proofing if the error is ever wrapped.


Nit: PR scope vs title

The PR title says "make /allowlist and /redaction pages for cli" but the diff also includes Kafka capture/stub infrastructure, cloud-init ISO generation, daemon identity keys, proto changes, and web assets. Consider updating the title or splitting into smaller PRs to make review and bisecting easier.

aspectrr and others added 3 commits April 7, 2026 17:02
- Rename all directories: fluid-cli→deer-cli, fluid-daemon→deer-daemon
- Update all Go module paths to github.com/aspectrr/deer.sh
- Fix proto go_package: fluid.sh/proto/gen/go/fluid/v1;fluidv1 → deer.sh/proto/gen/go/deer/v1;deerv1
- Regenerate all .pb.go files with buf generate (source paths now deer/v1/...)
- Integrate Kafka/Redpanda demo from feature/local-kafka-demo branch:
  - demo/ directory: docker-compose, Logstash pipeline, Kibana setup, weather-producer, prepare-source
  - scripts/demo/start.sh and stop.sh with all fluid→deer replacements
  - Root Makefile with demo-start/stop/reset targets
- Replace all fluid-demo→deer-demo, fluid-daemon→deer-daemon references in demo scripts
- Update CI job names and working-directory paths throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude bot commented Apr 7, 2026

Code Review: feat: make /allowlist and /redaction pages for cli

Good work overall — the two new TUI pages are well-structured, follow the existing Bubble Tea patterns in the codebase, and come with solid test coverage. Here are my findings, ordered by severity.


Critical

1. ExtraAllowedSubcommands / ExtraAllowedSubcommandsMode are never enforced

The TUI in allowlist.go lets users configure per-command subcommand allow/blocklists, and the values are persisted to config, but source/service.go only calls ValidateCommandWithExtra(command, s.cfg.ExtraAllowedCommands) — the new subcommand maps are completely ignored at runtime. Users will configure restrictions and see no effect.

Either wire the new config fields into command validation before merging, or gate the UI behind a "coming soon" notice so users aren't misled.


Major

2. Duplicate/divergent pattern definitions between renderHighlighted and builtinPatterns

redaction.go defines builtinPatterns for actual redaction, but renderHighlighted() (line ~494) contains a second hardcoded regex that approximates — but doesn't match — the builtins. Notably:

  • IPv6 is in builtinPatterns but not in renderHighlighted's pattern
  • builtinPatterns[2] targets sk- API keys, but renderHighlighted uses a broad base64 pattern [A-Za-z0-9+/]{20,}=* that will false-positive on many non-secret strings

Derive renderHighlighted's regex directly from builtinPatterns to keep them in sync, or at minimum extract a shared slice.

3. Live preview shows [REDACTED_N] but real redactor emits [REDACTED]

recomputePreview() uses renderReplaced which substitutes [REDACTED_1], [REDACTED_2], etc. The actual redact package uses [REDACTED]. The preview is misleading about what the user will actually see in tool output.


Minor

4. RedactConfig.Allowlist config field is declared but not surfaced

The field exists in config.go but the redaction TUI provides no way to interact with it. Either surface it or remove it to avoid dead config fields.

5. Tab and Shift+Tab cycle in the same direction

In redactionModeAdd, both Tab and Shift+Tab toggle focus forward between the two inputs. Shift+Tab should cycle backward (i.e., swap the toggle direction). This is a minor UX inconsistency but worth fixing for consistency with standard TUI conventions.

6. AllowlistCloseMsg.Saved test gap

TestAllowlistClose_Save checks that a command is non-nil but doesn't assert the config was actually mutated. Similarly, there's no test for RedactionCloseMsg{Saved: true} verifying that cfg.Redact.Patterns was persisted. These are the most important integration points of both models.


Nit

  • The scroll indicator (#/. ASCII bar) is functional but visually inconsistent with the rest of the Lipgloss-styled UI used elsewhere in the TUI.
  • The detailIsBuiltin map logic in enterDetailMode has a subtle edge case comment worth adding: builtin subs are processed first (setting true), so user subs that share a name with a builtin sub are silently skipped. The behavior is correct but non-obvious.

Summary

The blocking issue is #1 — the subcommand configuration is inert at runtime. #2 and #3 will cause user confusion (highlighted patterns don't match real redaction; preview output format differs). The rest are polish items.

Happy to discuss any of these in more detail.

@claude
Copy link
Copy Markdown

claude bot commented Apr 7, 2026

PR Review: feat: make /allowlist and /redaction pages for cli

Summary

This PR adds two new TUI pages (/allowlist and /redaction) to the CLI, along with a significant brand rename (fluid-cli to deer-cli) and several other bundled features (Kafka/Redpanda integration, microVM networking). Feedback is focused on the stated feature additions.


Bugs / Correctness

[allowlist.go] Mutation before save confirmation

The allowlist model directly mutates cfg.ExtraAllowedCommands, cfg.ExtraAllowedSubcommands, and cfg.ExtraAllowedSubcommandsMode in-place during editing. If the user presses esc to cancel, AllowlistCloseMsg{Saved: false} is emitted, but the config struct has already been modified. The parent only calls cfg.Save() on Saved: true, but the in-memory config is now dirty — subsequent operations in the same session will use the mutated (but unsaved) state.

Fix: deep-copy the relevant config fields on init and restore on cancel, or defer all writes to cfg until ctrl+s.

The same issue applies to redaction.go mutating cfg.Redact.Enabled and cfg.Redact.CustomPatterns.

[redaction.go] Incomplete IPv6 regex

The builtin IPv6 pattern (?i)\b(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}\b only matches full 128-bit addresses in uncompressed form. It misses ::1 (loopback), fe80:: (link-local), any abbreviated :: form, and IPv4-mapped addresses (::ffff:192.0.2.1). This gives users false confidence that IPv6 is being redacted. Either use a more complete pattern or document the limitation clearly.


Code Quality

[config.go] Unclear bool semantics for ExtraAllowedSubcommandsMode

ExtraAllowedSubcommandsMode map[string]bool `yaml:"extra_allowed_subcommands_mode"`

A raw bool does not convey what true vs false means. A named type would be clearer and make the serialized YAML human-readable without requiring source lookup:

type SubcommandMode string
const (
    SubcommandModeAllowlist SubcommandMode = "allowlist"
    SubcommandModeBlocklist SubcommandMode = "blocklist"
)
ExtraAllowedSubcommandsMode map[string]SubcommandMode

[redaction.go] Builtin patterns defined in TUI layer

The 6 builtin redaction patterns are defined inside redaction.go (a view/UI file). Pattern definitions are business logic and belong in a dedicated package (e.g., internal/redact/patterns.go) so they can be reused and tested independently of the TUI.

[redaction.go] API key pattern is vendor-specific

\bsk-[a-zA-Z0-9]{20,}\b matches OpenAI/Anthropic-style secret keys. The label "API Key" implies broader coverage — consider renaming to "OpenAI/Anthropic API Key" or expanding the pattern set.


Test Coverage

Coverage looks solid overall (15 tests for allowlist, 9 for redaction). A few gaps worth addressing:

  • No test for the cancel-leaves-config-dirty bug — the mutation-before-save issue won't be caught without an explicit test that checks config state after esc.
  • No integration tests for the slash commands in model.go — the cfg.Save(configPath) path and system message on success aren't exercised.
  • No test for the live regex preview — the match highlighting/replacement logic is pure business logic that could be unit-tested independently of rendering.

PR Scope

This PR bundles four unrelated changes:

  1. Brand rename (fluid-* to deer-*) — ~881 file renames, bulk of the 57k line diff
  2. New /allowlist and /redaction TUI pages (stated feature)
  3. Kafka/Redpanda integration
  4. MicroVM networking changes

Bundling makes the diff very hard to review and complicates git bisect if any one part causes a regression. The brand rename alone should be a separate PR.


Minor

  • The "delete last subcommand auto-switches to blocklist mode" side effect in allowlist detail view is implicit behavior — worth a comment or a UI hint.
  • RedactConfig.Allowlist []string exists in the config struct but doesn't appear to be editable through the /redaction TUI. Add a TODO if planned but not yet implemented.

What's Good

  • Bubble Tea model/view/update pattern is followed consistently with existing TUI pages.
  • The CloseMsg{Saved bool} pattern is clean and consistent with SettingsCloseMsg.
  • Duplicate regex prevention and regexp.Compile validation before saving are correct.
  • Builtin entries being marked read-only and non-deletable is good UX.

aspectrr added 13 commits April 7, 2026 17:21
- Change default model from claude-opus-4.6 to z-ai/glm-4.7
- Update context window from 1000000 to 203000 tokens
- Change compact model to z-ai/glm-4.5-air:free
- Update system prompt to position Deer as ELK-stack Consultant

💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
- Rename "Fluid" to "Deer" throughout the codebase
- Add comprehensive ELK-stack demo with weather pipeline
- Implement chat logging and history tracking
- Add macOS-native sandbox scripts and improvements
- Update demo scripts and Logstash pipeline configurations
- Add Redpanda caching and setup scripts
- Update proto definitions with simple_kafka_broker support
- Improve TUI and agent interactions
- Add multiple data validation and transformation filters

💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
- Update macOS native demo script
- Regenerate route tree after changes

💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
Fixes linter errors where defer Close() calls weren't checking return values.

💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
…rand

Bug fixes:
- Fix missing SimpleKafkaBroker field in CreateSandboxStream (remote.go)
- Fix unbounded blocking on network approval channel with context cancellation (agent.go)
- Fix SourceVM field missing from error done message (agent.go)
- Fix orchestrator panic on short sandbox IDs (orchestrator.go)
- Fix unary CreateSandbox ignoring snapshot mode (daemon server.go)
- Fix redaction highlight regex diverged from builtin patterns (redaction.go)
- Fix keypress leaking between add/detail inputs in allowlist (allowlist.go)
- Fix missing validation on kafka config update (kafka_handlers.go)
- Fix sandbox ID validation in readiness server (readiness.go)
- Fix product.tsx setTimeout not cleaned up on unmount

Architecture fixes:
- Fix TOCTOU race in gRPC SendAndWait - load stream inside mutex (stream.go)
- Fix goroutine leak in kafkastub manager on rapid config updates (manager.go)
- Fix time.Sleep not respecting context cancellation in IP discovery (ip.go)
- Fix vmHostCache unbounded growth - clear before refresh (helpers.go)
- Fix kafka hooks using context.Background() with no timeout (daemon/kafka.go, agent/kafka.go)
- Fix chatlog logger swallowing errors + expensive fsync on every write (logger.go)

Tests added:
- chatlog/logger_test.go: 12 tests covering all methods + concurrent writes
- kafka_handlers_test.go: 10 tests for GET/UPDATE/DELETE kafka configs

Complete fluid→deer rebrand across all modules:
- cloudinit.go: ~80 in-VM references (systemd units, scripts, paths, logs)
- sourcevm/manager.go, helpers.go: fluid-readonly → deer-readonly SSH user
- readonly/prepare.go, shell.go: fluid-readonly user/shell creation
- sshkeys/manager.go: fluid-readonly principal
- agent/client.go: temp dir name
- config/config.go: variable rename fluidDir → deerDir
- snapshotpull/: snapshot naming prefix
- kafkastub/transport: group ID prefix
- provider/lxc/: user creation and shell commands
- Web docs: install commands, APT keys, bridge names, CA paths
- SECURITY.md, AGENTS.md, RELEASING.md: all references updated

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants