allthingssecurity opened a new pull request, #28788: URL: https://github.com/apache/camel/pull/28788
# Description [CAMEL-26436](https://issues.apache.org/jira/browse/CAMEL-26436) (related to CAMEL-26330 and CAMEL-26418): live control of `camel-chaos` from the Camel CLI, step 3 of "Order of work" in `design/chaos.adoc`, on top of #28716 and #28754. Until now a rule could only come from `camel.chaos.rules` at startup or from Java (`ChaosManager`). - **A `chaos` dev console** (camel-chaos), read only. JSON: `enabled`, the current rules (`id`, `version`, `state`, `rule`, `hooks`, `matches`, `fired`, `skipped`, `endsIn`, `expectation`) and the whole report (verdict, `final`, seed, every version of every rule, counts per route). Text: the report as `toText()` gives it. When chaos is off it says why (off without profile `dev` or `camel.chaos.enabled=true`; stays off with profile `prod`). It has no option that changes anything, so over HTTP (`/q/dev/chaos`) chaos only lists and reports, as the design says. - **A `chaos` action of the CLI connector**: `add`, `change`, `remove`, `clear` through `ChaosManager`. A rule goes through the same parser as `camel.chaos.rules`; a rule that is not valid comes back as an error with the reason (`Invalid chaos rule [...]: rate=2 is not a probability above 0 and at most 1`), an unknown id (change or remove) as "not found" (exit code 3 in the CLI). - **`camel cmd chaos-add | chaos-change | chaos-remove | chaos-clear`** and **`camel get chaos [--report] [--json]`**, the flat verb-noun shape of `stop-route` / `camel get circuit-breaker`. The id of a rule only means something in one integration, so `chaos-add`, `chaos-change` and `chaos-remove` need the name or pid of exactly one (as `camel cmd sql`). `chaos-clear` without one acts on all integrations whose status says chaos is on (as `stop-route` acts on all), so an integration without camel-chaos is not asked. `camel get chaos` reads the console from the status file of each integration (the CLI connector now adds it, as it does for the circuit breakers). The report shows why an expectation is pending: time left, or "not decided" when its rule was removed or changed first. - **`camel run --chaos`** adds `camel:chaos`, as `--observe` adds `camel:observability-services`: in process, with `--background`, and with `--runtime=main` (also for an existing Maven project). Chaos then switches itself on with profile `dev`, the default of `camel run`. With `--runtime=spring-boot` or `quarkus` it is refused for now: the run would have to add camel-chaos to the exported project and give it Camel profile `dev`; I can open a follow-up JIRA for that. `design/chaos.adoc` ("Getting it") says so. Only `camel run` (and `camel dev` / `camel debug`, which extend it) gets it; it is not an export option. - Docs: "Control while it runs" on the chaos page, "Chaos rules" in the CLI managing page, the generated command pages, the security model and its YAML index (see below), and `design/chaos.adoc` brought in line with what #28716 and #28754 built (suggestion 1 of the #28754 review: the poll strategy is wrapped once before the consumer starts, the counts come from the route policy, and netty-http `status=` is CAMEL-26432). ``` $ camel run orders.camel.yaml --chaos $ camel cmd chaos-add orders --rule='endpoint=kafka:orders* error exception=java.net.ConnectException rate=0.3 until=1m' Added chaos rule r1 $ camel cmd chaos-change orders --id=r1 --rule='endpoint=kafka:orders* delay duration=2s rate=0.5 until=1m' Changed chaos rule r1 (version 2) $ camel get chaos $ camel get chaos orders --report ``` ## Safety: the CLI cannot switch chaos on - The action works only when the context has a `ChaosManager`, which only the plugin creates, only with profile `dev` or `camel.chaos.enabled=true`, never with `prod`. The action never creates one: with profile `prod` (also with `camel.chaos.enabled=true`), with no profile, or without the JAR, it answers with an error and nothing is installed (`LocalCliConnectorChaosActionTest.refusedWithProfileProd`, `refusedWhenChaosIsOff`, `refusedWithoutCamelChaos`). - The console only reads, whatever options it gets (`ChaosDevConsoleTest.optionsDoNotAddChangeOrRemoveRules`). - `exception=` instantiates any public `Throwable` class on the classpath with a public `String` or no-argument constructor. That is now written on the chaos page and in the security model (a new row under "Per-option opt-ins": a development tool, rules only from the developer, `camel.chaos.rules` is `insecure:dev`). `camel ask` reaches the commands only through its `camel` command tool, which already asks the user before a `camel cmd` (a test pins it for `chaos-*`; `camel get chaos` runs without asking). camel-cli-connector does not get a dependency on camel-chaos: with `camel run`, the camel-chaos JAR comes with `--chaos` / `--dep` into the class loader of the integration, while camel-cli-connector is on the class path of the CLI, so it cannot link against `ChaosManager`. The action finds the manager by class name through the class resolver of the context and calls its public methods by reflection (`ChaosAction`: `addRule`, `changeRule`, `hasRule`, `removeRule`, `clearRules`; `getMethod` only, no `setAccessible`). camel-chaos is a test dependency only. ## Split: the MCP tool group is the next PR This PR has the dev console, the CLI action, the commands and `camel run --chaos` (step 3 of the design). The MCP tool group (`camel_runtime_chaos_add/change/remove/clear/list/report` in `RuntimeTools` and the shared `ToolRegistry`, the `chaos` group in `camel_runtime_tool_groups`, and the TUI/`camel ask` confirmations) is its own step in the design, and comes next. As agreed in the review of #28716, `chaos_add` and `chaos_change` will be `destructiveHint=true` and in `ToolConfirms`, and the tools will key report entries by id plus version (the `version` that #28754 added, which this PR's console and `camel get chaos` already show). ## API change in camel-chaos (not released yet) `ChaosManager.changeRule(id, rule)` returns the version of the new rule (was `void`), so the CLI can print it, and `ChaosManager.hasRule(id)` is new, so the CLI can tell an unknown id ("not found") from a rule that is not valid. `ChaosReport.rulesJson(boolean)` (package-private) gives the console the current rules from the same report. ## Tests New test classes (each run 20 times in its own JVM, all passed): - `ChaosDevConsoleTest` (camel-chaos, 7): found by id as the console registry finds it; read only; the current rules with id, version 2 after a change, state, matches, fired, `endsIn`; the report with every version (`r1 v2 active`, `r1 v1 replaced`, `r2 v1 removed`) and the route counts; text; an ended rule; off without a profile (with `camel.chaos.rules` set) and with profile `prod`; `hasRule`. `optionsDoNotAddChangeOrRemoveRules` is a control (the console has no write path to call). - `LocalCliConnectorChaosActionTest` (camel-cli-connector, 10, `@Isolated`): add, change (version 2), remove, clear through `CliActionOutcome.dispatch` (the code both transports use) and once through the action file; a rule that is not valid (reason reported, not thrown); an unknown id for change and remove (not-found); missing arguments and an unknown command; refused with profile `prod` (also with `camel.chaos.enabled=true`; nothing is installed), with chaos off, and without the JAR (a class resolver that does not find `ChaosManager`); the status has the console, or why chaos is off. - `CamelChaosActionTest` (camel-jbang-core, 13): the action and options each command sends, quotes in a rule, what it prints, a refused rule and chaos off as errors with the integration's reason (exit 1), an unknown id (exit 3), add, change and remove need one integration (picocli refuses without a name; no match is exit 3), `chaos-clear` without a name skips integrations whose status says chaos is off. - `ListChaosTest` (camel-jbang-core, 8): rules as a table and as JSON (with `hooks` and `expectation`), the report as text (verdict, seed, lost, FAIL reasons, every version, the route counts, "not decided" / time left for pending expectations) and as JSON, chaos off (reason on stderr), and an integration without camel-chaos. Added to existing tests: `ProjectRunnerTest.aCamelMainRunWithChaosAddsCamelChaos` and `anExistingCamelMainProjectRunsWithChaos` (camel-jbang-run), `CommandInputErrorsTest.runWithChaosOnSpringBootOrQuarkus`, the golden cases `chaos` (run) and `maven-main-chaos` in `RunExportGoldenTest`, and `ToolConfirmsTest.aChaosRuleFromCamelAskIsAsked` (a control: `camel ask` already asks before any `camel cmd`; it pins that for `chaos-*`, and that `camel get chaos` runs without asking). Negative controls: 21 mutants of the new code, each compiled into the module and run against its test class; every one makes a test fail. Among them: the console listing all rules instead of the current ones, `enabled` always true, the prod reason; `changeRule` returning 1, `hasRule` always true; the action without its "chaos is off" check (the prod case), without its "no JAR" check, not-found reported as a plain error, change of an unknown id not checked, a refused rule thrown instead of reported, the status without the console; the commands dropping the rule or the id, not printing the error, asking integrations with chaos off; `camel get chaos` taking an off integration as on, listing the report's rules, hiding "not decided" or the JSON expectation; `camel run --chaos` not adding camel-chaos for `--runtime=main` or for a Maven project. Offline runs: the camel-chaos suite (261 tests), the camel-cli-connector `LocalCliConnector*Test` classes, `ActionCommandsTest`, `ExitCodeContractTest`, `CamelJBangMainOnlyCommandTest`, `ProjectRunnerTest` and the run cases of `RunExportGoldenTest` pass. Its export cases (and `maven-main-mixed`) fail in this offline build for reasons outside this change: they do not use `--chaos`, and the errors come from older snapshot jars here (no Java/XML routes loader, catalog differences in the expected files); CI runs them. ## Your note on #28754 (abandoned expectations and `isFinal()`) Now that a tool reads the report: the behaviour stays as the design says (an expectation whose rule was removed or changed, or whose context stopped, stays pending, and the report is not final). The JSON already marks those entries `notDecided`; `camel get chaos --report` now shows "not decided" next to them (and the time left next to the others), and the text of the report names "changed" too. So a "not final" PASS always shows which expectation keeps it open. ## Open questions - Reflection in the CLI connector, instead of a dependency: is that acceptable, or would you prefer a small SPI (for example a context plugin the connector knows) for module-provided CLI actions? - `chaos-remove` needs the name of one integration, as add and change do, where the design said "the others may omit it and then act on all": ids are per integration, so `r1` may be a different rule in each. The design's Control section is updated. OK? _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
