Repository navigation
komodo-mcp (typed, redacted, allowlisted) + names-only change records on Updates - #4
Merged
Merged
Conversation
…Updates Every agent and the operator share one Komodo API key, so an Update's `operator` cannot say which session changed a stack, and seeing what changed meant reading prev_toml/current_toml, which hold every env value in plain text (WI-865). Core now adds two logs to Updates, leaving the Update schema, the API types and the UI untouched: - "Config diff (names only)" on every resource config update: env keys added/removed/changed with values shown as sha256 fingerprints, and values for allowlisted non-secret fields only (default-deny). - "Actor (asserted)" from the X-Komodo-Actor / X-Komodo-Reason headers, carried by a task-local through the write/execute handlers. Asserted by the API key holder, not verified: attribution, not authorization. - "File change (names only)" on WriteStackFileContents: fingerprints and line counts against Komodo's cached copy. The diff logic lives in a new fork-only crate, lib/names_diff, which the komodo-mcp binary shares. The Core hooks are one or two lines each and are marked FORK (WI-865). The one changed upstream line wraps the spawned write task in tdd::propagate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents drove Komodo through 483 raw curl calls. Nine sessions tripped over the body shape (envelope, params.id vs params.stack, method names), GetStack leaked .config.environment into a transcript, and stack file writes that skipped RefreshStackCache deployed stale content (WI-846). bin/mcp is a stdio MCP server built on the fork's typed client: - stack_lookup, get_stack, env_diff, read_stack_file, container_health, container_logs and stack_history are read-only. - write_stack_file runs RefreshStackCache first, skips identical content, refuses .env files and re-reads to verify the write. - deploy_stack polls the Update to completion. It returns pass/fail plus the failing log tail (HTML stripped), or container health on success. - Redaction is default-deny. A stack is projected field by field from Komodo's own types, env is names, fingerprints and [[references]] only, and unclassified fields are withheld. A test fails when upstream adds a field. Every result is also scrubbed of all known env values and common token shapes. - Mutations are read-only by default and allowlisted per stack, matched on the resolved name. Protected stacks (*prod*) need an exact opt-in that a glob never grants. - Mutating calls send X-Komodo-Actor/-Reason, which the previous commit stamps on the Update. stack_history and env_diff (against last_successful_deploy) diff the Update TOMLs client-side using the shared lib/names_diff, so they work against an unpatched Core too. Tests: redaction never emits a fake secret (unit tests plus mock-Core E2E through every tool), allowlist enforcement including id-based bypass, and request bodies checked against Komodo's request types. The binary also ships in the fork's Core image, and CI covers the new crates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements Vogt WI-846 (Komodo MCP) and WI-865 (change attribution and names-only diffs). They are split into two commits.
1.
feat(core): names-only diffs and the asserted actor on Updates (WI-865)lib/names_diff. It does a Komodo-compatible env parse (including multi-line quoted values), producessha256:<12hex>/<len>fingerprints, and diffs resource TOML. Values appear only for an allowlist of non-secret fields (default-deny).bin/core/src/tdd: Core adds logs to Updates without touching the schema, the API types or the UI:Config diff (names only)on every resource config update (resource::update).Actor (asserted)fromX-Komodo-Actor/X-Komodo-Reason, carried through atask_local(router layer on/writeand/execute, pluspropagatearound the spawned write task). The header is asserted, not authenticated, so it serves attribution only.File change (names only)onWriteStackFileContents.FORK (WI-865). The single modified upstream line wraps the writetokio::spawnintdd::propagate. The conflict table indocs/tdd/MAINTENANCE.mdis updated.2.
feat(mcp):bin/mcp/komodo-mcp(WI-846)A stdio MCP server on the typed
komodo_client. Tools:stack_lookup,get_stack,env_diff,read_stack_file,container_health,container_logs,stack_history.write_stack_fileanddeploy_stack.bin/mcp/README.md.every_stack_field_is_classifiedfails when a rebase adds a field. A scrubber is the second layer: it replaces every known env value and common token shape in every result, including logs and error text.KOMODO_MCP_WRITE_STACKS).*prod*is protected and needs an exact name inKOMODO_MCP_ALLOW_PROTECTED. Rules are matched on the resolved stack name, so passing an id cannot bypass them.write_stack_filerunsRefreshStackCachefirst, skips identical content, refuses.envfiles, and re-refreshes afterwards to verify.deploy_stackpolls the Update until it completes and returns pass/fail. On failure it adds the failing stage's tail (HTML stripped, scrubbed); on success it adds container health.stack_historyandenv_diff {last_successful_deploy}diff the Updateprev_toml/current_tomlclient-side, so they work against today's unpatched Core.scripts/tdd/core-only.Dockerfileat/usr/local/bin/komodo-mcp. CI fmt/test now coversnames_diffandkomodo_mcp, pluscargo test -p komodo_core tdd::.Verification
cargo test -p names_diffpasses (11 tests).cargo test -p komodo_mcppasses (26 tests): unit tests, plus mock-Core end-to-end tests through every tool with fake secrets. The mock deserializes each request into Komodo's request types and covers allowlist and id-bypass refusal, write ordering (refresh, write, refresh) and deploy polling.cargo test -p komodo_core tdd::passes (5 tests). The documented checkscargo test -p interpolate -p infisical --lockedandcargo check -p komodo_core -p komodo_periphery --lockedpass.cargo fmtandcargo clippy --all-targetsare clean on the fork crates. Upstream files keep their baseline formatting.stack_history(vogt-prod)shows the 2026-10-02UpdateStackas names only: 5 keys added (MYDEVENV2_ASSISTANT_*,VOGT_IMAGE,VOGT_STACK_IMAGE) andMYDEVENV2_FCM_SERVICE_ACCOUNT_JSONchanged.Not done here
🤖 Generated with Claude Code