Repository navigation
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.
fix(dashboard): name every field GET /api/agents ships, instead of spreading the record #8472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
fix(dashboard): name every field GET /api/agents ships, instead of spreading the record #8472
Changes from all commits
2ab8bd6File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
… it cannot show api_kirocrew_agents built each roster row with {"name": name, "scope": ..., **dataclasses.asdict(agent_cfg)}, so the endpoint's response contract was "every field KiroCrewAgentConfig has now, plus every field anyone adds later", automatically. handlers/members.py made the opposite call for GET /api/members and documented why: the response is a network-boundary contract, and a spread ships a future field -- internal bookkeeping, a filesystem path, a credential-shaped one -- to the browser by omission. KEY half: both row sources (the cfg.agents rows and the project-scope rows) now go through one _agent_roster_row allowlist naming 11 keys, so the two cannot drift into different key sets either. Three record fields are withheld, each with no consumer anywhere in website/src: the two per-agent watchdog windows and the deprecated, inert telegram_account. VALUE half, two co-operating halves. Every record value is agent- or package-writable -- an agent can edit config.json, and _do_agents_sync copies description straight off a discovered agent spec -- so a value the redactors would alter, or a non-string the loader let through, is replaced WHOLESALE by _SENSITIVE_MASK, the sentinel _masked_config_dict already uses for the same job on GET /api/config/kirocrew. Benign content is byte-identical. api_kirocrew_agent_update then drops any body field carrying that mask, treating it as unchanged -- the remedy _masked_config_dict's docstring prescribes verbatim. Without it the read half would destroy stored config: the agents page seeds its edit sheet from a roster row and sends every field on every save so that "" can clear a pin. A FIXED sentinel rather than redacting in place is the load-bearing choice. Recomputing the redaction to recognise the view breaks two ways a sentinel does not: a second redaction chain over the same response (#8465) produces a view the predicate no longer matches, and a stored value that changes between the GET and the PUT makes the stale view read as a genuine edit, writing redaction markers into the config. The sentinel depends on neither. Cost, named: a value containing one credential-shaped token is masked entirely rather than partially, the same trade the config endpoint already makes. Masking a non-string rather than coercing it to "" is what lets the write rule PRESERVE it; an echoed "" would read as a genuine edit. name is the single exemption, and only for the owner: it travels in the URL rather than the body so the write rule cannot protect it, and masking it would make /api/agents/{name} unaddressable. An app token cannot reach those owner-gated routes, so name is masked there too. dict[str, str] is now true rather than aspirational. test_agents_roster_contract.py pins the exact key set at the endpoint for both row sources, ratchets the allowlist against dataclasses.fields, and covers both halves over HTTP including the stale-view case and that a genuine edit still writes through. Fixes #8454Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.