feat(filter): move edit/export/import/logs onto Filters gRPC service #224

Merged
KofTwentyTwo merged 1 commits from story/m4-filters-grpc-mgmt into dev 2026-07-30 00:37:20 +00:00
KofTwentyTwo commented 2026-07-30 00:33:06 +00:00 (Migrated from github.com)

Summary

Closes the gap left when Filters gRPC was introduced (only CreateRule/ListRules/DeleteRule/ValidateRule/PreviewRule were migrated): the CLI's filter edit/export/import/logs subcommands still read/wrote the CLI process's own throwaway ephemeral local DB, so a rule created via filter create (real gRPC to the daemon's persistent store) never showed up in filter export/filter logs. Pure relocation of already-correct logic — no change to matching/evaluation semantics.

  • Proto (crates/nuncio-proto/proto/nuncio/v1/nuncio.proto): adds 4 RPCs + 9 messages to service Filters, additive within nuncio.v1:
    • UpdateRule (partial name/nsql/priority overrides, preserves id, re-validates, reloads live FilterEngine)
    • ExportRules (renders persisted rules as sql or json)
    • ImportRules (parses content line-by-line, persists valid lines, reports per-line parse errors instead of silently dropping them)
    • GetExecutionLogs (returns the persisted filter execution log ledger)
    • New FilterExecutionLog message mirroring nuncio_filter::FilterExecutionLog field-for-field.
  • Daemon (crates/nunciod/src/grpc.rs): implements the four new RPCs on FiltersGrpcService, reusing reload_engine_from_store/map_filter_rule_to_proto exactly as create_rule/delete_rule do; adds a map_filter_execution_log_to_proto mapper.
  • CLI (crates/nuncio-cli/src/runner.rs): FilterSubcommand::{Edit,Export,Import,Logs} now go through self.connect_filters_client() gRPC calls instead of the ephemeral local db. Import still reads the file locally (std::fs::read_to_string) but forwards the raw content to the daemon for parsing/persistence. Removed the stale "known gap" comment block.
  • Contract-stability golden regenerated: crates/nuncio-proto/proto/nuncio/v1/descriptor.bin rebuilt from the fresh nuncio_v1_descriptor.bin; contract_stability::descriptor_matches_committed_golden passes.

Tests added

  • crates/nunciod/src/grpc.rs: update_rule_applies_partial_overrides_and_reloads_the_live_engine, update_rule_rejects_unknown_id, update_rule_rejects_invalid_nsql_and_persists_nothing, export_rules_renders_sql_and_json, import_rules_reports_partial_failures_and_persists_valid_lines, get_execution_logs_returns_the_persisted_ledger; extended filters_rpcs_reject_missing_bearer_token to cover all 4 new RPCs.
  • crates/nunciod/tests/grpc_auth_test.rs: rejects_calls_to_new_filters_rpcs_without_a_bearer_token (mirrors rejects_calls_without_a_bearer_token), asserting UpdateRule → Code::Unauthenticated.
  • crates/nuncio-cli/src/runner.rs: extended filter_rpcs_round_trip_over_grpc_to_a_stub_daemon with stub coverage + CLI-path assertions for filter edit/export/import/logs, including the not-found edit case and import partial-failure reporting.

Gate output

cargo fmt --all -- --check   -> clean (0 diff)
cargo check-all              -> clippy --all-targets --workspace -D warnings: 0 warnings
cargo test-all                -> 395 passed; 0 failed; 0 ignored (across all crates)
nuncio-proto contract_stability::descriptor_matches_committed_golden -> ok

Refs #192

## Summary Closes the gap left when `Filters` gRPC was introduced (only `CreateRule`/`ListRules`/`DeleteRule`/`ValidateRule`/`PreviewRule` were migrated): the CLI's `filter edit`/`export`/`import`/`logs` subcommands still read/wrote the CLI process's own throwaway ephemeral local DB, so a rule created via `filter create` (real gRPC to the daemon's persistent store) never showed up in `filter export`/`filter logs`. Pure relocation of already-correct logic — no change to matching/evaluation semantics. - **Proto** (`crates/nuncio-proto/proto/nuncio/v1/nuncio.proto`): adds 4 RPCs + 9 messages to `service Filters`, additive within `nuncio.v1`: - `UpdateRule` (partial name/nsql/priority overrides, preserves `id`, re-validates, reloads live `FilterEngine`) - `ExportRules` (renders persisted rules as `sql` or `json`) - `ImportRules` (parses `content` line-by-line, persists valid lines, **reports per-line parse errors** instead of silently dropping them) - `GetExecutionLogs` (returns the persisted filter execution log ledger) - New `FilterExecutionLog` message mirroring `nuncio_filter::FilterExecutionLog` field-for-field. - **Daemon** (`crates/nunciod/src/grpc.rs`): implements the four new RPCs on `FiltersGrpcService`, reusing `reload_engine_from_store`/`map_filter_rule_to_proto` exactly as `create_rule`/`delete_rule` do; adds a `map_filter_execution_log_to_proto` mapper. - **CLI** (`crates/nuncio-cli/src/runner.rs`): `FilterSubcommand::{Edit,Export,Import,Logs}` now go through `self.connect_filters_client()` gRPC calls instead of the ephemeral local `db`. `Import` still reads the file locally (`std::fs::read_to_string`) but forwards the raw content to the daemon for parsing/persistence. Removed the stale "known gap" comment block. - **Contract-stability golden regenerated**: `crates/nuncio-proto/proto/nuncio/v1/descriptor.bin` rebuilt from the fresh `nuncio_v1_descriptor.bin`; `contract_stability::descriptor_matches_committed_golden` passes. ## Tests added - `crates/nunciod/src/grpc.rs`: `update_rule_applies_partial_overrides_and_reloads_the_live_engine`, `update_rule_rejects_unknown_id`, `update_rule_rejects_invalid_nsql_and_persists_nothing`, `export_rules_renders_sql_and_json`, `import_rules_reports_partial_failures_and_persists_valid_lines`, `get_execution_logs_returns_the_persisted_ledger`; extended `filters_rpcs_reject_missing_bearer_token` to cover all 4 new RPCs. - `crates/nunciod/tests/grpc_auth_test.rs`: `rejects_calls_to_new_filters_rpcs_without_a_bearer_token` (mirrors `rejects_calls_without_a_bearer_token`), asserting `UpdateRule` → `Code::Unauthenticated`. - `crates/nuncio-cli/src/runner.rs`: extended `filter_rpcs_round_trip_over_grpc_to_a_stub_daemon` with stub coverage + CLI-path assertions for `filter edit`/`export`/`import`/`logs`, including the not-found edit case and import partial-failure reporting. ## Gate output ``` cargo fmt --all -- --check -> clean (0 diff) cargo check-all -> clippy --all-targets --workspace -D warnings: 0 warnings cargo test-all -> 395 passed; 0 failed; 0 ignored (across all crates) nuncio-proto contract_stability::descriptor_matches_committed_golden -> ok ``` Refs #192
Sign in to join this conversation.