Skip to content

fix(agent-profiles): restrict organization profile changes to managers - #8086

Merged
iscekic merged 21 commits into
mainfrom
drain/org-profile-manage-access
Oct 24, 2026
Merged

iscekic merged 21 commits into
mainfrom
drain/org-profile-manage-access

Conversation

@iscekic

@iscekic iscekic commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Evidence

Evidence: demonstrated — exercised profile views in the Android app and profile requests against the local web API on commit 45e9ffe, using owned test accounts and a disposable local database.

Change

Align organization-owned profile operations and editor controls with organization management permissions. Keep personal profile creation available. Apply destination-specific MCP value handling.

Verification

  • Android: opened the profile list, creation form, and organization-owned profile detail. Created a personal profile and verified its user ownership in the local database. Exercised member and manager editor states; a manager saved the organization profile successfully. Optional app analytics were off.
  • Local web API: member profile update returned 401; owner profile update returned 200.
  • Five focused mobile suites passed: 33 tests. The suites cover list navigation, owner selection, overview, and repository bindings.
  • Mobile typecheck, lint, and changed-file formatting checks passed.
  • The web settings dialog could not finish loading because the local worker reported an entrypoint configuration error. Web visual proof from earlier sessions was not repeated; this run's web proof is the API exercise.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Profile deletion authority. Answer: Managers required. Confidence: 0.80
  2. Question: Organization profile creation authority. Answer: Managers only. Confidence: 0.85
  3. Question: MCP destination updates. Answer: Require fresh values for changed destinations. Confidence: 0.80
  4. Question: Editor scope. Answer: Web and mobile. Confidence: 0.85
  5. Question: Temporary local tooling configuration. Answer: Approved for this session; original configuration restored. Confidence: 0.55
  6. Question: Shared tooling remediation. Answer: Separate remediation authorized. Confidence: 0.55
  7. Question: Separate remediation delivery. Answer: Keep this profile PR focused and preserve the independent tooling diagnosis for follow-up. Confidence: 0.62

Organization-owned profiles are shared content, so their mutations now
require an organization owner or admin role, matching repository binding
and repository-bound deletion. Read access stays available to every
member.

The MCP secret round-trip is bound to an unchanged destination: a stored
header or environment value is reused only while the remote URL or local
command stays the same, and an update that changes the destination must
submit the values again.

The web and mobile profile editors render read-only for non-managers.
@iscekic iscekic added drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening labels Oct 19, 2026
@iscekic

iscekic commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Editor states observed in the local dev stack, with the affected app and a local development organization.

  • Without the manage role, the organization profile editor renders the role note with no add, edit, or delete controls; the MCP tab lists the server without actions.
  • With the manage role, the same profile renders editable, including the delete action and MCP add/edit controls.

Organization profile editor showing the manager-role note and read-only controls

Organization profile editor with the manage role showing edit and delete controls

@iscekic
iscekic force-pushed the drain/org-profile-manage-access branch from 70852e6 to dd6cba5 Compare October 19, 2026 12:10
@kilo-code-bot

kilo-code-bot Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit at 45e9ffe2d resolves the prior warning by keeping the profile-create entry points visible in organization context and routing creation through NewProfileScreen, which hides the organization owner option for members and creates a personal profile; no new issues found in the changed lines.

Assumptions: [INFERENCE] Tests were not executed in this read-only review; conclusions come from the current HEAD source (HEAD 45e9ffe2dce55a96c9fbe14d731fe6565c7bb70b). The earlier profile-mcp-service.ts inline comments remain outdated (line: null) and addressed in their replies, so they are not carried forward.

Files Reviewed (3 files)
  • apps/mobile/src/components/profiles/profiles-list-screen.tsx
  • apps/mobile/src/components/profiles/profiles-list-screen.mounted.test.tsx
  • apps/mobile/src/components/profiles/profiles-list-screen.personal-create.mounted.test.tsx

Verification Notes

  • ProfilesListScreen no longer imports useCanManageOrganizationProfiles; the header IconButton and empty-state Button are both rendered unconditionally, restoring the create path for members.
  • NewProfileScreen still derives canOwnOrganization from canManageOrganization(role), so a member sees no owner selector and createOrganizationId yields no organizationId; organization creation remains manager-only on the client and enforced by the router.
  • The renamed profiles-list-screen.personal-create.mounted.test.tsx matches the new behavior (create action and empty-state action present in organization context), and no remaining references to the removed canManageState mock exist in the mounted suite.
  • Both test files still match the src/**/*.mounted.test.tsx include pattern, so the rename does not drop the suite.
Previous Review Summaries (9 snapshots, latest commit 6573052)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 6573052)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental commit correctly carries the organization-manage capability into the mobile repo-pins section, but it also hides the Profiles list create action for members, which removes the only in-app path to personal-profile creation while an organization is active.

Assumptions: [INFERENCE] Tests were not executed in this read-only review; findings come from the current HEAD source and the PR's web counterpart. The earlier inline comments on packages/cloud-agent-profile/src/profile-mcp-service.ts are outdated (line: null) and are marked addressed in their replies, so they are not carried forward.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/profiles/profiles-list-screen.tsx 120 Gating the header and empty-state create actions on the organization manage capability also blocks members from creating personal profiles, though NewProfileScreen and the router still support personal creation and the web list keeps its create button
Files Reviewed (7 files)
  • apps/mobile/src/components/profiles/profiles-list-screen.tsx - 1 issue
  • apps/mobile/src/components/profiles/profiles-list-screen.mounted.test.tsx
  • apps/mobile/src/components/profiles/profiles-list-screen.readonly.mounted.test.tsx
  • apps/mobile/src/components/profiles/profile-overview-screen.tsx
  • apps/mobile/src/components/profiles/profile-overview-screen.readonly.mounted.test.tsx
  • apps/mobile/src/components/profiles/profile-repo-pins-section.tsx
  • apps/mobile/src/components/profiles/profile-repo-pins-section.mounted.test.tsx

Fix these issues in Kilo Cloud

Previous review (commit 13a9dfd)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Since the previous review at 6cdb52fb, the only non-merge PR change is the expo-router mock update in the read-only overview test, which correctly supplies useNavigation().isFocused for the merged usePopWhenFocused helper.

Assumptions: [INFERENCE] No tests were executed in this read-only review; the head commit only extends a test mock, and the PR reports CI green. The larger 6cdb52fb..HEAD diff is dominated by a merge of origin/main (including the usePopWhenFocused addition in apps/mobile/src/lib/navigation/pop-when-focused.ts:15), not by PR changes.

Files Reviewed (1 file)
  • apps/mobile/src/components/profiles/profile-overview-screen.readonly.mounted.test.tsx - mock now returns useNavigation: () => ({ isFocused: () => true }), matching the imperative navigation.isFocused() call in usePopWhenFocused; no issue

Verification Notes

  • git log 6cdb52fb..HEAD --no-merges --first-parent shows only 13a9dfd2c test(mobile): update profile overview router mock; the remaining commits are origin/main merged in 68b6d1215.
  • usePopWhenFocused (apps/mobile/src/lib/navigation/pop-when-focused.ts:16) reads useNavigation and useRouter from expo-router; the updated mock provides both, so the read-only render path resolves.
  • The other overview tests already mock @/lib/navigation/pop-when-focused directly (profile-overview-screen.mounted.test.tsx:60, .offline line 45, .terminal line 49), so no parallel gap was introduced.
  • Targeted re-check of the previously verified guards: MCP masked-value rejection bound to an unchanged destination remains in packages/cloud-agent-profile/src/profile-mcp-service.ts (lines 150-204), and org-profile mutations still call ensureOrganizationManageAccess while list/get keep ensureOrganizationAccess in apps/web/src/routers/agent-profiles-router.ts (lines 38-40, 311-313, 371-372, 391-392, 411-413).

Previous review (commit 6cdb52f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The only change since the previous review is a single deleted blank line in profile-overview-screen.tsx; the merged main history in the branch does not alter the PR's changed behavior, and the previously reported MCP destination-guard and command round-trip findings remain fixed in current code.

Assumptions: [INFERENCE] No test run was performed in this read-only review; the branch since 87cf21e contains only the one-line style commit plus merges of main, so behavior is taken from the diff and the PR's CI report. The four existing inline comments are outdated (line: null) and addressed.

Files Reviewed (1 file)
  • apps/mobile/src/components/profiles/profile-overview-screen.tsx - removed blank line only

Verification Notes

  • git show 6cdb52fb2 confirms the sole non-merge change since the previous review is a deleted empty line between hasUsableMessage and ProfileOverviewScreen; no code behavior changes.
  • packages/cloud-agent-profile/src/profile-mcp-service.ts is unchanged since the previous review, so buildStoredConfig still rejects masked values on transport type, local command array, or remote URL changes.
  • apps/web/src/routers/agent-profiles-router.ts differences since the previous review come from the merged main branch and are outside this PR's diff.

Previous review (commit 87cf21e)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change is a test-only refactor: it inlines the overview suite's icon mock, deletes the now-unused icon helper, and shares the per-test reset through resetOverviewState, matching the reset behavior the suites previously had; the previously reported MCP destination-guard and command round-trip findings are fixed in current code and their comments are outdated.

Assumptions: [INFERENCE] No test run was performed in this read-only review; the head commit is a test refactor with no production code change, so behavior is taken from the diff and the PR's CI report.

Files Reviewed (4 files)
  • apps/mobile/src/components/profiles/profile-overview-screen.mounted.test.tsx - inline icon mock and shared reset helper
  • apps/mobile/src/components/profiles/profile-overview-screen.offline.mounted.test.tsx - offline refetch suite checked against the same helper shape
  • apps/mobile/src/components/profiles/profile-overview-screen.test-helpers.ts - new resetOverviewState helper
  • apps/mobile/src/components/profiles/profile-overview-icons.ts - deleted helper has no remaining importers
  • packages/cloud-agent-profile/src/profile-mcp-service.ts - targeted re-verification of prior destination-guard findings

Verification Notes

  • The inline icon mock lists exactly the eight icons the screen imports, so no icon resolves to undefined.
  • resetOverviewState performs the same assignments the mounted suite did before this commit, and its structural input type accepts the mock shapes in both suites.
  • profile-overview-icons.ts has no remaining references in apps/mobile, so its deletion is complete.
  • buildStoredConfig rejects a masked value when the transport type, local command array, or remote URL differs from the stored config, including a local-to-remote (or reverse) type change.

Previous review (commit d202c1b)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change adds a dedicated read-only mounted suite for the mobile setup-commands screen, and its mocks and expectations match the current screen, helpers, and useCanManageOrganizationProfiles gating; the earlier MCP destination-guard and command-round-trip findings remain fixed in current code.

Assumptions: [INFERENCE] No test run was performed in this read-only review; the new suite's passing status is taken from the PR's CI report.

Files Reviewed (3 files)
  • apps/mobile/src/components/profiles/profile-commands-screen.readonly.mounted.test.tsx - new read-only member suite (add/reorder/delete and empty-state CTA)
  • apps/mobile/src/components/profiles/profile-commands-screen.tsx - targeted check of the canManage gating the new tests assert
  • packages/cloud-agent-profile/src/profile-mcp-service.ts - targeted re-verification of the prior destination-guard finding

Verification Notes

  • useCanManageOrganizationProfiles is mocked to false in the new suite; the screen renders FormField rows with disabled={!canManage}, no Pressable/Button controls, and action={null} on the empty state, matching all assertions.
  • buildStoredConfig still rejects a masked value whenever the transport type, local command array, or remote URL differs from the stored config, so the previously reported type-change bypass stays closed.
  • McpForm still resubmits the stored command array when the command text is unchanged, so an untouched argument containing a space is not re-split.

Previous review (commit a084f7c)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit only adds role-matrix tests around organization profile creation, and those tests match the current router and role constants; the two previously raised MCP findings are verified fixed in current code.

Files Reviewed (3 files)
  • apps/web/src/routers/agent-profiles-router.test.ts (new admin and billing-manager role tests)
  • packages/cloud-agent-profile/src/profile-mcp-service.ts (targeted verification of prior findings)
  • apps/web/src/components/cloud-agent/profile-editor/McpServersTab.tsx (targeted verification of prior findings)

Verification Notes

  • ORGANIZATION_MANAGE_ROLES is ['owner', 'admin'], so the new admin-allow and billing-manager-deny expectations match ensureOrganizationAccess, including its exact error message.
  • The earlier MCP findings remain fixed: buildStoredConfig treats a transport-type mismatch as a destination change and rejects masked values, and the web editor resubmits the stored command array when the command text is unchanged.

Previous review (commit 760dee0)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The new commit only adds router permission-matrix tests for skills, agents, kilo commands, and instructions; the tests are well-scoped and the previously raised MCP destination and command-comparison findings are verified fixed in current code.

Files Reviewed (3 files)
  • apps/web/src/routers/agent-profiles-router.test.ts (new tests since last review)
  • packages/cloud-agent-profile/src/profile-mcp-service.ts (targeted verification of prior findings)
  • apps/web/src/components/cloud-agent/profile-editor/McpServersTab.tsx (targeted verification of prior findings)

Previous review (commit fa5ef5e)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up commit correctly binds MCP stored values to the transport type and preserves unchanged command arrays in the web editor; no new defects found in the changed lines.

Files Reviewed (3 files)
  • apps/web/src/components/cloud-agent/profile-editor/McpServersTab.tsx
  • apps/web/src/routers/agent-profiles-router.test.ts
  • packages/cloud-agent-profile/src/profile-mcp-service.ts

Previous review (commit dd6cba5)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The new MCP destination guard can be bypassed by a server-type change and can falsely block saves of commands the web editor cannot round-trip.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/cloud-agent-profile/src/profile-mcp-service.ts 163 Type changes skip both destination guards and persist the masked placeholder as a literal value
packages/cloud-agent-profile/src/profile-mcp-service.ts 164 Exact command comparison rejects unchanged commands that the web editor re-splits on whitespace
Files Reviewed (33 files)
  • apps/mobile/src/components/profiles/kilo-command-row.tsx - no issues
  • apps/mobile/src/components/profiles/new-profile-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/new-profile-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-agents-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-commands-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/profile-commands-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-mcp-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/profile-mcp-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-overview-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/profile-overview-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-owner-model.ts - no issues
  • apps/mobile/src/components/profiles/profile-skills-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/profile-skills-screen.tsx - no issues
  • apps/mobile/src/components/profiles/profile-variables-rows.tsx - no issues
  • apps/mobile/src/components/profiles/profile-variables-screen.mounted.test.tsx - no issues
  • apps/mobile/src/components/profiles/profile-variables-screen.tsx - no issues
  • apps/mobile/src/lib/hooks/use-can-manage-profiles.ts - no issues
  • apps/web/src/components/cloud-agent/profile-editor/CommandsTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/ImportConfigTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/KiloCommandsTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/McpServersTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/OverviewTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/ProfileAgentsTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/ProfileDetailPane.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/ProfilesManager.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/SkillsTab.tsx - no issues
  • apps/web/src/components/cloud-agent/profile-editor/VarsTab.tsx - no issues
  • apps/web/src/routers/agent-profiles-router.test.ts - no issues
  • apps/web/src/routers/agent-profiles-router.ts - no issues
  • packages/cloud-agent-profile/src/profile-mcp-service.ts - 2 issues
  • packages/cloud-agent-profile/src/profile-service.ts - no issues
  • packages/cloud-agent-profile/src/repo-binding-db.ts - no issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 47.1K · Output: 3.7K · Cached: 405.9K

Review guidance: REVIEW.md from base branch main

A stored value round-trips only when the transport and destination match
the stored server. The web editor keeps the stored command array when its
text is unchanged, so arguments that contain whitespace still round-trip.
@iscekic iscekic added the merge:human Substantive functional risk requires human review. label Oct 19, 2026
@iscekic
iscekic enabled auto-merge October 19, 2026 17:45
@iscekic
iscekic disabled auto-merge October 20, 2026 19:19
…age-access

# Conflicts:
#	apps/mobile/src/components/profiles/profile-agents-screen.tsx
@iscekic iscekic removed merge:human Substantive functional risk requires human review. merge:blocked labels Oct 21, 2026
@iscekic iscekic added merge:blocked merge:human Substantive functional risk requires human review. and removed merge:blocked labels Oct 21, 2026
@iscekic
iscekic enabled auto-merge October 21, 2026 02:24
@iscekic
iscekic disabled auto-merge October 21, 2026 07:08
…age-access

# Conflicts:
#	apps/mobile/src/components/profiles/new-profile-screen.tsx
#	apps/web/src/components/cloud-agent/profile-editor/ProfilesManager.tsx
#	apps/web/src/routers/agent-profiles-router.test.ts
#	apps/web/src/routers/agent-profiles-router.ts
@iscekic iscekic removed merge:human Substantive functional risk requires human review. merge:blocked labels Oct 21, 2026
…age-access

# Conflicts:
#	apps/mobile/src/components/profiles/profile-commands-screen.tsx
@iscekic iscekic added merge:human Substantive functional risk requires human review. intent:ok Janitor change confirmed as a real bug fix, not intended behavior labels Oct 22, 2026
…age-access

# Conflicts:
#	apps/mobile/src/components/profiles/profile-agents-screen.tsx
#	apps/mobile/src/components/profiles/profile-commands-screen.tsx
#	apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx
#	apps/mobile/src/components/profiles/profile-mcp-screen.tsx
#	apps/mobile/src/components/profiles/profile-overview-screen.tsx
#	apps/mobile/src/components/profiles/profile-skills-screen.tsx
#	apps/mobile/src/components/profiles/profile-variables-screen.tsx
#	apps/web/src/routers/agent-profiles-router.ts
@iscekic iscekic removed the merge:human Substantive functional risk requires human review. label Oct 23, 2026
…age-access

# Conflicts:
#	apps/mobile/src/components/profiles/profile-overview-screen.tsx
#	apps/web/src/routers/agent-profiles-router.test.ts
@iscekic

iscekic commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Re-ran the end-to-end check on the merged branch head against a local dev stack with an owned fake organization account.

Exercised:

  • Web profile editor, organization scope: a member without the manage role sees the role note, disabled name and description fields, a disabled default toggle, and no delete action in the overview; their variables tab shows no edit or add controls. A manager sees the same profile with editable fields, the default toggle enabled, the delete action present, and the variables tab offers edit and add. The profile update endpoint answered 401 for the member and 200 for the manager in the same run.
  • Android app, same organization profile: the member's overview disables the name and description fields, save, and the default toggle and has no delete action; the variables screen lists the value with no add or delete controls. The manager's overview enables those controls and shows delete, and the variables screen offers add and delete.

Attachments show the observed states.

Organization profile overview for a member without the manage role

Same profile overview for a manager

Variables tab for the member

Variables tab for the manager

Android profile overview for the member

Android profile overview for the manager

Android variables screen for the member

Android variables screen for the manager

@iscekic iscekic added the merge:human Substantive functional risk requires human review. label Oct 23, 2026
@iscekic iscekic removed the merge:human Substantive functional risk requires human review. label Oct 23, 2026
@iscekic

iscekic commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Android verification on the current head used the local development stack and owned test data. The profile list and profile detail reflected the test account's permissions; analytics remained off.

Organization profile list for a member

Profile details with disabled edit controls

@iscekic

iscekic commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Verified these profile views on Android using the local development stack and owned test fixtures.

Profile creation view

Profile details view

Profile management view

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drain Work item from the findings drain intent:ok Janitor change confirmed as a real bug fix, not intended behavior janitor:trust Janitor finding: trust boundary hardening merge:human Substantive functional risk requires human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants