mqgov-cli 0.1.0 → 0.3.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.
- package/README.md +97 -15
- 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, produce, reset offsets, 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
|
[](https://www.npmjs.com/package/mqgov-cli)
|
|
10
10
|
[](https://github.com/JiangHe12/mqgov-cli/actions/workflows/ci.yml)
|
|
@@ -25,7 +25,7 @@ Message brokers — **Kafka**, **RabbitMQ**, **Pulsar**, **RocketMQ** — are th
|
|
|
25
25
|
|
|
26
26
|
- 🔎 **Shows you the blast radius first** — `--dry-run` / `--plan` print the exact per-partition impact (how many messages an offset reset will replay or skip) before anything happens.
|
|
27
27
|
- 🛡️ **Refuses to do something dangerous without explicit sign-off** — risky commands need a confirmation flag, a change ticket, and an explicit `--allow-*` for the operation.
|
|
28
|
-
- 👀 **Peeks without consuming** — inspecting
|
|
28
|
+
- 👀 **Peeks/tails without consuming** — inspecting or streaming message fingerprints never advances a consumer's position or drains a queue.
|
|
29
29
|
- 📜 **Records everything in a tamper-evident audit log** — sha256 fingerprints and counts only, **never your message bodies**.
|
|
30
30
|
- 🤖 **Is safe to hand to an AI agent** — the agent can read and preview freely, but **cannot** invent the human approvals required for dangerous actions.
|
|
31
31
|
|
|
@@ -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** | topics: list · describe · create · alter · delete · purge. consumer groups: list · lag · reset-offset. messages: non-destructive peek · produce. |
|
|
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 · produce. DLQs: list · peek · redrive · purge through native broker models. ACLs: list · grant · revoke where supported. Schemas: list · describe · check 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** | inspect messages as fingerprints without consuming them or moving any cursor (Pulsar Reader, RabbitMQ get+requeue). Where a broker can't guarantee this,
|
|
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. |
|
|
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. |
|
|
@@ -54,11 +54,17 @@ It's built on the shared [`opskit-core`](https://github.com/JiangHe12/opskit-cor
|
|
|
54
54
|
| topic list / describe / create / delete | ✅ | ✅ | ✅ | ✅ |
|
|
55
55
|
| produce | ✅ | ✅ | ✅ | ✅ |
|
|
56
56
|
| **non-destructive peek** | ✅ | ✅ (Reader) | ✅ (get+requeue) | ❌ `NOT_IMPLEMENTED`¹ |
|
|
57
|
+
| **non-destructive tail** | ✅ | ✅ (Reader) | ❌ `NOT_IMPLEMENTED`² | ❌ `NOT_IMPLEMENTED`¹ |
|
|
57
58
|
| **offset lag / reset** | ✅ | ✅ (cursor) | ❌ (no offsets) | ❌ |
|
|
58
59
|
| alter partitions | ✅ | ✅ | ❌ | ❌ |
|
|
59
60
|
| purge | ✅ | ✅ | ✅ | ❌ |
|
|
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** | ✅ Confluent Schema Registry | ✅ built-in admin schema API | ❌ `NOT_IMPLEMENTED` | ❌ `NOT_IMPLEMENTED` |
|
|
60
64
|
|
|
61
|
-
¹ RocketMQ's Go v2 `PullConsumer` enters the consumer-group lifecycle and commits offsets, so it cannot guarantee
|
|
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.
|
|
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.
|
|
62
68
|
|
|
63
69
|
---
|
|
64
70
|
|
|
@@ -100,6 +106,7 @@ mqgov ctx test # ping the broker through the context
|
|
|
100
106
|
mqgov topic list -o json
|
|
101
107
|
mqgov topic describe orders -o json
|
|
102
108
|
mqgov message peek orders --count 5 -o json # fingerprints only, nothing consumed
|
|
109
|
+
mqgov message tail orders --max-messages 10 -o json
|
|
103
110
|
|
|
104
111
|
# 3. Preview the blast radius of a dangerous op — nothing is changed yet
|
|
105
112
|
mqgov group reset-offset billing orders --to latest --dry-run -o json # shows per-partition delta
|
|
@@ -121,19 +128,19 @@ Every command is sorted into one of four **risk tiers** by the fail-closed `mqcl
|
|
|
121
128
|
|
|
122
129
|
| Tier | What it covers | What you must provide |
|
|
123
130
|
|:---:|---|---|
|
|
124
|
-
| **R0** | Reads & previews (`topic list/describe`, `group list/lag`, `message peek`, `*-dry-run`, `audit query/verify`, `doctor`) | Nothing — but it's still audited |
|
|
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 |
|
|
125
132
|
| **R1** | Ordinary writes (`message produce`, `topic create`) | `--yes` (or an interactive confirmation) |
|
|
126
|
-
| **R2** | Elevated mutations (`topic alter`, `group create/delete`, produce to a **protected** topic) | `--yes` **and** a non-empty `--ticket` |
|
|
127
|
-
| **R3** | Destructive / irreversible (`group reset-offset`, `topic purge`, `topic delete`, produce to an **internal/system** topic) | The above **plus** the exact `--allow-*` flag |
|
|
133
|
+
| **R2** | Elevated mutations (`topic alter`, `group create/delete`, `acl grant`, produce to a **protected** topic) | `--yes` **and** a non-empty `--ticket` |
|
|
134
|
+
| **R3** | Destructive / irreversible (`group reset-offset`, `topic purge`, `topic delete`, `dlq redrive`, `dlq purge`, broad `acl grant`, `acl revoke`, produce to an **internal/system** topic) | The above **plus** the exact `--allow-*` flag |
|
|
128
135
|
|
|
129
|
-
The R3 allow flags: `--allow-offset-reset`, `--allow-topic-purge`, `--allow-topic-delete`, `--allow-internal-produce`.
|
|
136
|
+
The R3 allow flags: `--allow-offset-reset`, `--allow-topic-purge`, `--allow-topic-delete`, `--allow-destructive-acl`, `--allow-internal-produce`.
|
|
130
137
|
|
|
131
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`.
|
|
132
139
|
|
|
133
140
|
Three rules keep this safe — especially for automation:
|
|
134
141
|
|
|
135
142
|
1. **Blast radius comes from the tool, not a guess.** Use `--dry-run` / `--plan` to see the exact per-partition impact. Never estimate it by reasoning.
|
|
136
|
-
2. **`mqclass` is fail-closed and structure-aware.** All offset changes, purge,
|
|
143
|
+
2. **`mqclass` is fail-closed and structure-aware.** All offset changes, purge, topic delete, ACL revoke, and broad ACL grants are pinned R3; wildcard/glob targets escalate; an unknown operation fails closed to the highest tier — it never falls to R0.
|
|
137
144
|
3. **🤖 AI agents must never invent `--ticket`, `--allow-*`, or a high-risk `--yes`.** Those are *human* authorization inputs. An agent should surface "this needs approval X" to its operator and stop.
|
|
138
145
|
|
|
139
146
|
---
|
|
@@ -179,14 +186,89 @@ Offsets are a Kafka and Pulsar concept. On RabbitMQ and RocketMQ, `group lag` /
|
|
|
179
186
|
</details>
|
|
180
187
|
|
|
181
188
|
<details>
|
|
182
|
-
<summary><b>message</b> — peek & produce</summary>
|
|
189
|
+
<summary><b>message</b> — peek, tail & produce</summary>
|
|
183
190
|
|
|
184
191
|
```bash
|
|
185
192
|
mqgov message peek <topic> [--partition N] [--offset N] [--count N] -o json # R0, non-destructive, fingerprints only
|
|
193
|
+
mqgov message tail <topic> [--partition N] [--from earliest|latest|offset:N] [--follow] [--max-messages N] [--timeout 30s] -o json
|
|
186
194
|
mqgov message produce <topic> [--key <k>] [--body <text>] --yes # R1 (R3 + --allow-internal-produce for internal topics)
|
|
187
195
|
```
|
|
188
196
|
|
|
189
|
-
`peek` never
|
|
197
|
+
`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.
|
|
198
|
+
</details>
|
|
199
|
+
|
|
200
|
+
<details>
|
|
201
|
+
<summary><b>dlq</b> — dead-letter queue governance</summary>
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
mqgov dlq list [--topic <source-or-dlq>] [--group <group-or-sub>] [--pattern <name|glob>] -o json # R0
|
|
205
|
+
mqgov dlq peek <dlq> [--topic <source>] [--group <group-or-sub>] [--count N] -o json # R0, fingerprints only
|
|
206
|
+
mqgov dlq redrive <dlq> --target <live-topic> [--count N] --dry-run -o json # R0 preview
|
|
207
|
+
mqgov dlq redrive <dlq> --target <live-topic> [--count N] --yes --ticket <t> --allow-internal-produce # R3
|
|
208
|
+
mqgov dlq purge <dlq> --dry-run -o json # R0 preview
|
|
209
|
+
mqgov dlq purge <dlq> --yes --ticket <t> --allow-topic-purge # R3
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
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`.
|
|
213
|
+
|
|
214
|
+
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.
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
<details>
|
|
218
|
+
<summary><b>schema</b> — schema registry</summary>
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
mqgov schema list [--pattern <subject>] -o json
|
|
222
|
+
mqgov schema describe <subject-or-topic> [--version latest|N] -o json
|
|
223
|
+
mqgov schema check <subject-or-topic> --schema-file ./next.avsc --schema-type AVRO [--version latest] -o json
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`schema list`, `schema describe`, and `schema check` are R0 and audited. `check` uses read-only compatibility endpoints and never registers, deletes, or evolves a schema. Kafka maps to Confluent Schema Registry (`GET /subjects`, `GET /subjects/{subject}/versions`, `GET /subjects/{subject}/versions/{version|latest}`, and `POST /compatibility/subjects/{subject}/versions/{version}`). Pulsar maps to its built-in admin schema endpoints under `/admin/v2/schemas/{tenant}/{namespace}/{topic}`. RabbitMQ and RocketMQ fail closed with `NOT_IMPLEMENTED`. Audit stores only subject/version metadata and schema hashes, never schema text or registry credentials.
|
|
227
|
+
</details>
|
|
228
|
+
|
|
229
|
+
<details>
|
|
230
|
+
<summary><b>fleet</b> — cross-context read-only views</summary>
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
mqgov fleet status --all -o json
|
|
234
|
+
mqgov fleet topics --contexts dev,staging --pattern orders -o json
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`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.
|
|
238
|
+
</details>
|
|
239
|
+
|
|
240
|
+
<details>
|
|
241
|
+
<summary><b>acl</b> — broker access control</summary>
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
mqgov acl list [--principal <P>] [--resource-type <T>] [--resource-name <N>] -o json
|
|
245
|
+
|
|
246
|
+
# Kafka broker ACLs
|
|
247
|
+
mqgov acl grant --principal User:svc --resource-type topic --resource-name orders \
|
|
248
|
+
--pattern literal --operation read --permission allow --yes --ticket <t>
|
|
249
|
+
|
|
250
|
+
mqgov acl revoke --principal User:svc --resource-type topic --resource-name orders \
|
|
251
|
+
--pattern literal --operation read --permission allow \
|
|
252
|
+
--yes --ticket <t> --allow-destructive-acl
|
|
253
|
+
|
|
254
|
+
# RabbitMQ native user-vhost permissions
|
|
255
|
+
mqgov acl grant --principal svc --vhost / --resource-type vhost --resource-name '^orders$' \
|
|
256
|
+
--pattern regex --operation read --permission allow --yes --ticket <t>
|
|
257
|
+
|
|
258
|
+
mqgov acl revoke --principal svc --vhost / --resource-type vhost --resource-name '^orders$' \
|
|
259
|
+
--pattern regex --operation read --permission allow \
|
|
260
|
+
--yes --ticket <t> --allow-destructive-acl
|
|
261
|
+
|
|
262
|
+
# Pulsar native namespace/topic permissions
|
|
263
|
+
mqgov acl grant --principal app-role --resource-type namespace --resource-name public/default \
|
|
264
|
+
--pattern literal --operation produce --permission allow --yes --ticket <t>
|
|
265
|
+
|
|
266
|
+
mqgov acl revoke --principal app-role --resource-type topic --resource-name orders \
|
|
267
|
+
--pattern literal --operation consume --permission allow \
|
|
268
|
+
--yes --ticket <t> --allow-destructive-acl
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`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.
|
|
190
272
|
</details>
|
|
191
273
|
|
|
192
274
|
<details>
|
|
@@ -194,12 +276,12 @@ mqgov message produce <topic> [--key <k>] [--body <text>] --yes
|
|
|
194
276
|
|
|
195
277
|
```bash
|
|
196
278
|
# Backend-bound contexts (credentials go through credstore, never plaintext)
|
|
197
|
-
mqgov ctx set <name> --backend kafka --brokers <h:p,h:p> [--sasl-mechanism PLAIN] [--tls --ca-cert <f>] [--protected]
|
|
279
|
+
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]
|
|
198
280
|
mqgov ctx set <name> --backend rabbitmq (--amqp-url <url> | --host <h> --port <p> --vhost </>) --management-url <url>
|
|
199
281
|
mqgov ctx set <name> --backend pulsar --service-url pulsar://<h:p> --admin-url http://<h:p> [--tenant public] [--pulsar-namespace default]
|
|
200
282
|
mqgov ctx set <name> --backend rocketmq --nameservers <h:p,h:p> [--broker-addr <h:p>]
|
|
201
283
|
mqgov ctx use|list|current|delete|test
|
|
202
|
-
# secrets: --password <pw|token|secretKey> --credential-backend <encrypted-file|keychain|...> (a non-plain backend is required)
|
|
284
|
+
# secrets: --password <pw|token|secretKey> and --schema-registry-password <pw> go through --credential-backend <encrypted-file|keychain|...> (a non-plain backend is required)
|
|
203
285
|
|
|
204
286
|
# Audit (tamper-evident, fingerprint-only)
|
|
205
287
|
mqgov audit query [--since 24h] [--type <t>] [--operator <o>] [--status <s>] [--limit 100] -o json
|
|
@@ -220,7 +302,7 @@ mqgov version
|
|
|
220
302
|
|
|
221
303
|
mqgov-cli is designed to be driven by autonomous agents safely:
|
|
222
304
|
|
|
223
|
-
- Run `mqgov capabilities -o json` first to discover what the bound backend supports — brokers differ, don't assume (e.g. RabbitMQ/RocketMQ have no offsets; RocketMQ has no peek).
|
|
305
|
+
- 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.
|
|
224
306
|
- Use `-o json` everywhere; every command returns a stable, versioned envelope.
|
|
225
307
|
- Get blast radius from `--dry-run` / `--plan`, never from your own reasoning.
|
|
226
308
|
- **Never self-fill `--ticket`, `--allow-*`, or a high-risk `--yes`.** Surface the required human approval and stop.
|