mqgov-cli 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +66 -15
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Governed message-broker operations for humans _and_ AI agents.**
6
6
 
7
- One safe command line for **Kafka**, **RabbitMQ**, **Pulsar**, and **RocketMQ** — list, describe, peek, tail, produce, reset offsets, inspect ACLs, purge, and delete topics without ever fat-fingering production or silently draining a queue.
7
+ One safe command line for **Kafka**, **RabbitMQ**, **Pulsar**, and **RocketMQ** — list, describe, peek, tail, produce, govern DLQs, reset offsets, inspect ACLs and schemas, purge, and delete topics without ever fat-fingering production or silently draining a queue.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/mqgov-cli.svg)](https://www.npmjs.com/package/mqgov-cli)
10
10
  [![CI](https://github.com/JiangHe12/mqgov-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/JiangHe12/mqgov-cli/actions/workflows/ci.yml)
@@ -38,10 +38,10 @@ It's built on the shared [`opskit-core`](https://github.com/JiangHe12/opskit-cor
38
38
  | | |
39
39
  |---|---|
40
40
  | 📨 **Four brokers** | **Kafka** (franz-go), **RabbitMQ** (AMQP + management API), **Pulsar** (client + admin REST), **RocketMQ** (rocketmq-client-go/v2). One backend-agnostic governance model; pick per context or override per command. |
41
- | 🧱 **topic / group / message / acl** | topics: list · describe · create · alter · delete · purge. consumer groups: list · lag · reset-offset. messages: non-destructive peek · tail · produce. ACLs: list · grant · revoke where supported. |
41
+ | 🧱 **topic / group / message / dlq / acl / schema / fleet** | topics: list · describe · create · alter · delete · purge. consumer groups: list · lag · reset-offset. messages: non-destructive peek · tail · bounded mirror · produce. DLQs: list · peek · redrive · purge through native broker models. ACLs: list · grant · revoke where supported. Schemas: list · describe · check · register · delete where native schema registry support exists. Fleet: read-only status and topic inventory across configured contexts. |
42
42
  | 🔐 **R0–R3 governance** | every operation is risk-classified by the fail-closed `mqclass` engine; protected contexts and internal/system topics escalate one tier; AI callers can never self-authorize. |
43
43
  | 🎯 **Real blast-radius preview** | `reset-offset --dry-run` and `purge --dry-run` compute the actual per-partition message delta from the live broker — no guessing. The preview is read-only and never mutates. |
44
- | 👀 **Non-destructive peek/tail** | inspect or stream messages as fingerprints without consuming them or moving any cursor (Kafka direct partition reads, Pulsar Reader, RabbitMQ get+requeue for peek only). Where a broker can't guarantee this, the operation fails closed rather than silently consuming. |
44
+ | 👀 **Non-destructive peek/tail/mirror source** | inspect, stream, or bounded-copy messages without consuming them or moving any cursor where the broker can guarantee it (Kafka direct reads, Pulsar Reader). Where a broker can't guarantee this, the operation fails closed rather than silently consuming. |
45
45
  | 🧭 **Honest capabilities** | brokers differ — mqgov reports what each one actually supports (`capabilities -o json`) and **fails closed with `NOT_IMPLEMENTED`** for the rest, never faking it. |
46
46
  | 📜 **Tamper-evident audit** | hash-chained log of every action (sha256 fingerprints + counts, **no message bodies/keys/headers**); `audit verify` detects tampering. |
47
47
  | 🩺 **Ops & DX** | backend-bound `ctx` contexts with credstore-backed secrets, `doctor` diagnostics, shell `completion`, OpenTelemetry traces/metrics, JSON output everywhere. |
@@ -58,10 +58,14 @@ It's built on the shared [`opskit-core`](https://github.com/JiangHe12/opskit-cor
58
58
  | **offset lag / reset** | ✅ | ✅ (cursor) | ❌ (no offsets) | ❌ |
59
59
  | alter partitions | ✅ | ✅ | ❌ | ❌ |
60
60
  | purge | ✅ | ✅ | ✅ | ❌ |
61
- | **ACL list / grant / revoke** | ✅ | ✅ namespace/topic permissions | ✅ user-vhost permissions | ❌ `NOT_IMPLEMENTED` |
61
+ | **DLQ list / peek / redrive / purge** | list ❌; explicit topic peek/redrive/purge ✅ | ✅ `{topic}-{subscription}-DLQ` | ✅ DLX queues | list ✅ `%DLQ%group`; others ❌ |
62
+ | **ACL list / grant / revoke** | ✅ | ✅ namespace/topic permissions | ✅ user-vhost permissions | ❌ `NOT_IMPLEMENTED`³ |
63
+ | **schema list / describe / check / register / delete** | ✅ Confluent Schema Registry | ✅ built-in admin schema API | ❌ `NOT_IMPLEMENTED` | ❌ `NOT_IMPLEMENTED` |
62
64
 
63
65
  ¹ RocketMQ's Go v2 `PullConsumer` enters the consumer-group lifecycle and commits offsets, so it cannot guarantee non-destructive peek/tail — mqgov fails closed instead of silently advancing offsets. ² RabbitMQ has no forward non-destructive tail because reads are consume/requeue oriented. Unsupported operations always return `NOT_IMPLEMENTED` (exit 12), never a fake success.
64
66
 
67
+ ³ RocketMQ broker ACLs live in broker-side `plain_acl.yml`, but `rocketmq-client-go/v2` does not expose a public, cgo-free admin API for reading or changing that config. mqgov does not shell out to the Java `mqadmin` tool and does not hand-roll remoting commands; manage RocketMQ ACLs out of band with broker configuration or official mqadmin until the Go client exposes a clean API.
68
+
65
69
  ---
66
70
 
67
71
  ## 📦 Install
@@ -124,12 +128,12 @@ Every command is sorted into one of four **risk tiers** by the fail-closed `mqcl
124
128
 
125
129
  | Tier | What it covers | What you must provide |
126
130
  |:---:|---|---|
127
- | **R0** | Reads & previews (`topic list/describe`, `group list/lag`, `message peek`, `message tail`, `acl list`, `*-dry-run`, `audit query/verify`, `doctor`) | Nothing — but it's still audited |
128
- | **R1** | Ordinary writes (`message produce`, `topic create`) | `--yes` (or an interactive confirmation) |
129
- | **R2** | Elevated mutations (`topic alter`, `group create/delete`, `acl grant`, produce to a **protected** topic) | `--yes` **and** a non-empty `--ticket` |
130
- | **R3** | Destructive / irreversible (`group reset-offset`, `topic purge`, `topic delete`, broad `acl grant`, `acl revoke`, produce to an **internal/system** topic) | The above **plus** the exact `--allow-*` flag |
131
+ | **R0** | Reads & previews (`topic list/describe`, `group list/lag`, `message peek`, `message tail`, `dlq list/peek`, `acl list`, `schema list/describe/check`, `fleet status/topics`, `*-dry-run`, `audit query/verify`, `doctor`) | Nothing — but it's still audited |
132
+ | **R1** | Ordinary writes (`message produce`, target side of `message mirror`, `topic create`, `schema register` for a new subject) | `--yes` (or an interactive confirmation) |
133
+ | **R2** | Elevated mutations (`topic alter`, `group create/delete`, `acl grant`, `schema register` for an existing subject, produce/mirror to a **protected** topic) | `--yes` **and** a non-empty `--ticket` |
134
+ | **R3** | Destructive / irreversible (`group reset-offset`, `topic purge`, `topic delete`, `schema delete`, `dlq redrive`, `dlq purge`, broad `acl grant`, `acl revoke`, produce/mirror to an **internal/system** topic) | The above **plus** the exact `--allow-*` flag |
131
135
 
132
- The R3 allow flags: `--allow-offset-reset`, `--allow-topic-purge`, `--allow-topic-delete`, `--allow-destructive-acl`, `--allow-internal-produce`.
136
+ The R3 allow flags: `--allow-offset-reset`, `--allow-topic-purge`, `--allow-topic-delete`, `--allow-destructive-acl`, `--allow-internal-produce`, `--allow-schema-delete`.
133
137
 
134
138
  **Protected contexts, protected topics, and internal/system topics raise the tier by one.** For example, producing to `__consumer_offsets` is treated as a destructive R3 operation and needs `--allow-internal-produce`.
135
139
 
@@ -182,15 +186,62 @@ Offsets are a Kafka and Pulsar concept. On RabbitMQ and RocketMQ, `group lag` /
182
186
  </details>
183
187
 
184
188
  <details>
185
- <summary><b>message</b> — peek, tail & produce</summary>
189
+ <summary><b>message</b> — peek, tail, mirror & produce</summary>
186
190
 
187
191
  ```bash
188
192
  mqgov message peek <topic> [--partition N] [--offset N] [--count N] -o json # R0, non-destructive, fingerprints only
189
193
  mqgov message tail <topic> [--partition N] [--from earliest|latest|offset:N] [--follow] [--max-messages N] [--timeout 30s] -o json
194
+ mqgov message mirror <source-topic> --to-context <ctx> --to-topic <topic> --limit 100 --dry-run -o json
195
+ mqgov message mirror <source-topic> --to-context <ctx> --to-topic <topic> --limit 100 --yes -o json
190
196
  mqgov message produce <topic> [--key <k>] [--body <text>] --yes # R1 (R3 + --allow-internal-produce for internal topics)
191
197
  ```
192
198
 
193
- `peek` and `tail` never consume a message or move a cursor, and return only sha256 fingerprints (`keySha256`, `bodySha256`, size, optional timestamp) — never the body. `tail` is bounded by `--max-messages` and `--timeout`; `--follow` streams new messages only until those bounds or cancellation. Tail is supported by Kafka and Pulsar. On RabbitMQ and RocketMQ, `tail` fails closed (`NOT_IMPLEMENTED`); on RocketMQ, `peek` also fails closed.
199
+ `peek` and `tail` never consume a message or move a cursor, and return only sha256 fingerprints (`keySha256`, `bodySha256`, size, optional timestamp) — never the body. `tail` is bounded by `--max-messages` and `--timeout`; `--follow` streams new messages only until those bounds or cancellation.
200
+
201
+ `message mirror` is a bounded one-shot copy, never a daemon. It performs two independent authorizations: a source-side non-destructive read against the source context, then a target-side produce against `--to-context`. `--dry-run` / `--plan` is an R0 preview that reads/counts but does not produce. Kafka and Pulsar can be mirror sources; RabbitMQ and RocketMQ source mirroring fail closed with `NOT_IMPLEMENTED` because their available read APIs cannot guarantee non-destructive full-message reads. Keys, bodies, and headers flow only in process memory; audit records source/target/count and body sha256 aggregation only. Kafka supports `--from earliest|latest|offset:N|timestamp:<RFC3339>` and `--partition`; Pulsar supports `earliest|latest|timestamp:<RFC3339>` and all-partition reads. Headers are copied where both backends can express string/byte headers; unsupported source concepts are not fabricated.
202
+ </details>
203
+
204
+ <details>
205
+ <summary><b>dlq</b> — dead-letter queue governance</summary>
206
+
207
+ ```bash
208
+ mqgov dlq list [--topic <source-or-dlq>] [--group <group-or-sub>] [--pattern <name|glob>] -o json # R0
209
+ mqgov dlq peek <dlq> [--topic <source>] [--group <group-or-sub>] [--count N] -o json # R0, fingerprints only
210
+ mqgov dlq redrive <dlq> --target <live-topic> [--count N] --dry-run -o json # R0 preview
211
+ mqgov dlq redrive <dlq> --target <live-topic> [--count N] --yes --ticket <t> --allow-internal-produce # R3
212
+ mqgov dlq purge <dlq> --dry-run -o json # R0 preview
213
+ mqgov dlq purge <dlq> --yes --ticket <t> --allow-topic-purge # R3
214
+ ```
215
+
216
+ DLQ mapping is backend-native and honest: RocketMQ lists `%DLQ%{consumerGroup}` topics only; RabbitMQ treats DLQs as ordinary queues fed by a dead-letter exchange; Kafka has no native DLQ and never auto-discovers one, so use an explicit DLQ topic for peek/redrive/purge; Pulsar uses `{topic}-{subscription}-DLQ`. Unsupported verbs return `NOT_IMPLEMENTED`.
217
+
218
+ Redrive is governed as internal produce: dry-run is a read-only preview and real execution requires `--allow-internal-produce`. Audit remains fingerprint/count-only and never stores message body, key, or headers.
219
+ </details>
220
+
221
+ <details>
222
+ <summary><b>schema</b> — schema registry</summary>
223
+
224
+ ```bash
225
+ mqgov schema list [--pattern <subject>] -o json
226
+ mqgov schema describe <subject-or-topic> [--version latest|N] -o json
227
+ mqgov schema check <subject-or-topic> --schema-file ./next.avsc --schema-type AVRO [--version latest] -o json
228
+ mqgov schema register <subject-or-topic> --schema-file ./next.avsc --schema-type AVRO --yes -o json
229
+ mqgov schema register <subject-or-topic> --schema-file ./next.avsc --schema-type AVRO --yes --ticket <t> -o json
230
+ mqgov schema delete <subject-or-topic> [--version N] [--permanent] --yes --ticket <t> --allow-schema-delete -o json
231
+ ```
232
+
233
+ `schema list`, `schema describe`, and `schema check` are R0 and audited. `schema register` is R1 for a new subject and R2 when the subject already exists; registering a new version is the evolution path. Existing subjects first run the backend compatibility check and incompatible schemas are rejected before registration. `schema delete` is R3 and requires `--allow-schema-delete`. Kafka maps to Confluent Schema Registry, including soft delete and hard delete with `--permanent`. Pulsar maps to its built-in admin schema endpoints; because Pulsar has no soft/hard split, this backend only accepts permanent subject deletion and returns `NOT_IMPLEMENTED` for soft or version delete. RabbitMQ and RocketMQ fail closed with `NOT_IMPLEMENTED`. Audit stores only subject/version metadata and schema hashes, never schema text or registry credentials.
234
+ </details>
235
+
236
+ <details>
237
+ <summary><b>fleet</b> — cross-context read-only views</summary>
238
+
239
+ ```bash
240
+ mqgov fleet status --all -o json
241
+ mqgov fleet topics --contexts dev,staging --pattern orders -o json
242
+ ```
243
+
244
+ `fleet status` fans out `Ping`, `Describe`, and `Capabilities` across selected contexts. `fleet topics` fans out topic listing and tags every row with its source context. Select contexts with exactly one of `--all` or `--contexts a,b,c`. Fleet is R0 only: each per-context read still runs through the same R0 classification and authorization path as a single-context command, using that context's own stored credentials. Partial failures are reported per context as `denied`, `unreachable`, or `error` data and the command still exits 0.
194
245
  </details>
195
246
 
196
247
  <details>
@@ -224,7 +275,7 @@ mqgov acl revoke --principal app-role --resource-type topic --resource-name orde
224
275
  --yes --ticket <t> --allow-destructive-acl
225
276
  ```
226
277
 
227
- `acl list` is R0 and audited. Normal `acl grant` is R2. Broad grants (Kafka prefixed pattern, wildcard principal, wildcard resource, cluster resource, `all`, `alter`, cluster-action style operations, broad RabbitMQ regexes such as `.*`, `.+`, `.`, and `orders.*`, or Pulsar `functions`/`sources`/`sinks`/`packages`) and every `acl revoke` are R3 and require `--allow-destructive-acl`. Kafka implements broker ACLs with `literal`/`prefixed` patterns. RabbitMQ maps ACLs to native per-user, per-vhost permission regexes (`configure`, `write`, `read`) and only supports `--permission allow` with `--pattern regex`. Pulsar maps ACLs to native role permissions on namespaces or topics with actions `produce`, `consume`, `functions`, `sources`, `sinks`, and `packages`; it is allow-only and uses `--pattern literal`. RocketMQ fails closed with `NOT_IMPLEMENTED`.
278
+ `acl list` is R0 and audited. Normal `acl grant` is R2. Broad grants (Kafka prefixed pattern, wildcard principal, wildcard resource, cluster resource, `all`, `alter`, cluster-action style operations, broad RabbitMQ regexes such as `.*`, `.+`, `.`, and `orders.*`, or Pulsar `functions`/`sources`/`sinks`/`packages`) and every `acl revoke` are R3 and require `--allow-destructive-acl`. Kafka implements broker ACLs with `literal`/`prefixed` patterns. RabbitMQ maps ACLs to native per-user, per-vhost permission regexes (`configure`, `write`, `read`) and only supports `--permission allow` with `--pattern regex`. Pulsar maps ACLs to native role permissions on namespaces or topics with actions `produce`, `consume`, `functions`, `sources`, `sinks`, and `packages`; it is allow-only and uses `--pattern literal`. RocketMQ fails closed with `NOT_IMPLEMENTED`: broker ACLs are managed through broker-side `plain_acl.yml` or the official Java `mqadmin`, because `rocketmq-client-go/v2` exposes no clean public ACL admin API.
228
279
  </details>
229
280
 
230
281
  <details>
@@ -232,12 +283,12 @@ mqgov acl revoke --principal app-role --resource-type topic --resource-name orde
232
283
 
233
284
  ```bash
234
285
  # Backend-bound contexts (credentials go through credstore, never plaintext)
235
- mqgov ctx set <name> --backend kafka --brokers <h:p,h:p> [--sasl-mechanism PLAIN] [--tls --ca-cert <f>] [--protected]
286
+ mqgov ctx set <name> --backend kafka --brokers <h:p,h:p> [--sasl-mechanism PLAIN] [--tls --ca-cert <f>] [--schema-registry-url <url>] [--schema-registry-username <u>] [--schema-registry-password <p>] [--protected]
236
287
  mqgov ctx set <name> --backend rabbitmq (--amqp-url <url> | --host <h> --port <p> --vhost </>) --management-url <url>
237
288
  mqgov ctx set <name> --backend pulsar --service-url pulsar://<h:p> --admin-url http://<h:p> [--tenant public] [--pulsar-namespace default]
238
289
  mqgov ctx set <name> --backend rocketmq --nameservers <h:p,h:p> [--broker-addr <h:p>]
239
290
  mqgov ctx use|list|current|delete|test
240
- # secrets: --password <pw|token|secretKey> --credential-backend <encrypted-file|keychain|...> (a non-plain backend is required)
291
+ # secrets: --password <pw|token|secretKey> and --schema-registry-password <pw> go through --credential-backend <encrypted-file|keychain|...> (a non-plain backend is required)
241
292
 
242
293
  # Audit (tamper-evident, fingerprint-only)
243
294
  mqgov audit query [--since 24h] [--type <t>] [--operator <o>] [--status <s>] [--limit 100] -o json
@@ -258,7 +309,7 @@ mqgov version
258
309
 
259
310
  mqgov-cli is designed to be driven by autonomous agents safely:
260
311
 
261
- - Run `mqgov capabilities -o json` first to discover what the bound backend supports — brokers differ, don't assume (e.g. Kafka, RabbitMQ, and Pulsar support `acl` with different native models; RabbitMQ/RocketMQ have no offsets; RabbitMQ/RocketMQ have no tail; RocketMQ has no peek).
312
+ - Run `mqgov capabilities -o json` first to discover what the bound backend supports — brokers differ, don't assume (e.g. Kafka, RabbitMQ, and Pulsar support `acl` with different native models; Kafka and Pulsar support `schema`; RabbitMQ/RocketMQ have no offsets, schema registry, or tail; RocketMQ has no peek). Use `fleet status --all -o json` for a read-only cross-context dashboard.
262
313
  - Use `-o json` everywhere; every command returns a stable, versioned envelope.
263
314
  - Get blast radius from `--dry-run` / `--plan`, never from your own reasoning.
264
315
  - **Never self-fill `--ticket`, `--allow-*`, or a high-risk `--yes`.** Surface the required human approval and stop.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mqgov-cli",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Governed message-broker operations CLI for AI agents (Kafka, RabbitMQ, Pulsar, RocketMQ)",
5
5
  "bin": {
6
6
  "mqgov": "bin/mqgov-cli.js",