Skip to content

feat(secrets): per-agent GitHub token grant UI + short-lived token storage#2036

Merged
jaylfc merged 5 commits into
jaylfc:devfrom
hognek:feat/github-token-grants
Jul 20, 2026
Merged

feat(secrets): per-agent GitHub token grant UI + short-lived token storage#2036
jaylfc merged 5 commits into
jaylfc:devfrom
hognek:feat/github-token-grants

Conversation

@hognek

@hognek hognek commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Task: t_2f795122. Part of #858 (C2).

Changes

  • New module: tinyagentos/github_token.py — lifetime-aware token minting cache with mint_installation_token() and get_agent_github_token()
  • SecretsStore: Added github-installation category + get_agent_github_installations() method
  • API: GET /api/secrets/agent/{name}/github endpoint for per-agent GitHub grant queries
  • Frontend:
    • github-installation category in SecretsApp category filter, styles, and dropdowns
    • Per-agent access toggles for each GitHub App repo in GitHubConnect.tsx
  • Tests: 7/7 test_github_token.py, 6/7 test_secrets.py pass

Summary by CodeRabbit

  • New Features

    • Added support for GitHub Installation secrets, including creation, editing, filtering, and secure agent access.
    • GitHub repository connections now allow configuring agent grants per repository.
    • GitHub installation details now display repository permissions.
    • Added automatic GitHub installation token generation, caching, and refresh.
    • Secret names can now include path-style characters.
  • Security

    • Secret values remain encrypted at rest and are masked in listings.
    • Access to agent GitHub grants requires authentication.

@hognek
hognek marked this pull request as ready for review July 19, 2026 09:16
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@hognek, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e6cd5a5a-85ac-4f19-ab84-3c634dbcf96d

📥 Commits

Reviewing files that changed from the base of the PR and between 75d09eb and 426a870.

📒 Files selected for processing (5)
  • desktop/src/apps/secrets/GitHubConnect.tsx
  • desktop/src/lib/github.ts
  • tinyagentos/routes/github_oauth.py
  • tinyagentos/routes/secrets.py
  • tinyagentos/secrets.py
📝 Walkthrough

Walkthrough

The change adds the github-installation secret category, authenticated agent-grant APIs, desktop grant management, GitHub installation-token caching, and coverage for storage, routes, encryption, and token minting.

Changes

GitHub installation access

Layer / File(s) Summary
Grant storage and API contracts
tinyagentos/secrets.py, tinyagentos/routes/secrets.py, tinyagentos/routes/github_oauth.py, desktop/src/lib/github.ts, tests/test_secrets.py
Adds GitHub installation secret storage, authenticated agent-grant retrieval, path-style secret routes, permissions metadata, and API-level coverage.
Installation-token minting and lookup
tinyagentos/github_token.py, tests/test_github_token.py
Adds cached GitHub App installation-token minting and per-agent installation lookup with expiry refresh and failure handling tests.
Desktop category and grant controls
desktop/src/apps/SecretsApp.tsx, desktop/src/apps/secrets/GitHubConnect.tsx
Adds GitHub Installation category options, repository agent inputs, grant loading, and POST/PUT save handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentRequest
  participant get_agent_github_token
  participant SecretsStore
  participant mint_installation_token
  participant GitHubAPI
  AgentRequest->>get_agent_github_token: request token for agent
  get_agent_github_token->>SecretsStore: retrieve granted installations
  SecretsStore-->>get_agent_github_token: installation grants
  get_agent_github_token->>mint_installation_token: mint installation token
  mint_installation_token->>GitHubAPI: request access token
  GitHubAPI-->>mint_installation_token: token and expiry
  mint_installation_token-->>AgentRequest: return cached token
Loading

Possibly related PRs

Suggested reviewers: jaylfc

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: per-agent GitHub grants with short-lived token storage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

Comment thread tinyagentos/routes/secrets.py Outdated


@router.get("/api/secrets/agent/{agent_name}/github")
async def get_agent_github_grants(request: Request, agent_name: str):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: New GET /api/secrets/agent/{agent_name}/github endpoint returns GitHub installation IDs and repo names but has no visible authentication/authorization guard in this diff.

The other secret routes are presumably gated by app-level middleware, but this endpoint exposes which agents are mapped to which GitHub installations/repos. Confirm the route is covered by auth middleware; if the desktop/API can be reached without auth, this is an information-disclosure issue. At minimum, the agent_name from the path should be validated against the caller's identity rather than trusted blindly.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread tinyagentos/github_token.py Outdated
if not installations:
return None

# Use the first granted installation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: get_agent_github_token silently uses only installations[0] and drops every other granted installation.

If an agent is granted access to multiple GitHub App installations (or multiple repos across installations), only the first ORDER BY s.name result is used, so the agent never receives a token for the other repos. Worse, because mint_installation_token mints a token valid for the entire installation (all repos the installation can see — see the docstring at line 67-69), a grant for a single repo within a broad installation yields a token scoped to all of that installation's repos. This is a privilege-scope mismatch: the per-repo grant UI implies scoping that the backend does not enforce.

Consider either (a) iterating over all installations and aggregating, or (b) actually scoping the token via repository_ids/permissions so grants are honored.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

handleSaveGrants(repo.full_name, inst.id, [])
}
aria-label={`Save agent grants for ${repo.full_name}`}
title={`Save agent grants for ${repo.full_name}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: handleSaveGrants is always called with permissions: [] (the third argument is hardcoded to []).

Suggested change
title={`Save agent grants for ${repo.full_name}`}
onClick={() =>
handleSaveGrants(repo.full_name, inst.id, repo.permissions ?? [])
}

As written, every saved github-installation secret stores an empty permissions list regardless of what the installation actually grants. This makes the stored permissions field meaningless and inconsistent with the UI intent. Use the installation's real permissions (e.g. inst.permissions) when persisting.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No New Issues in Incremental Diff | Recommendation: Merge (incremental changes are clean)

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Resolved in this incremental diff (prior findings fixed)
  • tinyagentos/routes/secrets.py:64get_agent_github_grants now enforces ownership via require_owner_or_admin(user, agent["user_id"]) (403 for non-owner/non-admin). Resolves the prior WARNING about the authz gap (only Depends(get_current_user) before).
  • tinyagentos/secrets.py:348 — non-dict JSON payload from json.loads is now guarded with if not isinstance(meta, dict): meta = {}. Resolves the prior carried-forward Stability finding (non-dict JSON payload not guarded).
  • desktop/src/apps/secrets/GitHubConnect.tsx:152-156,483-487handleSaveGrants now captures failures into saveErrors and renders them via an role="alert" element instead of silently swallowing. Resolves the prior CodeRabbit SUGGESTION about save failures being silently swallowed.
Incremental Diff Reviewed (3 files)
  • tinyagentos/routes/secrets.py - authz guard added (prior WARNING resolved)
  • tinyagentos/secrets.py - non-dict JSON guard added (prior finding resolved)
  • desktop/src/apps/secrets/GitHubConnect.tsx - save error surfacing added (prior suggestion resolved)
Previous Review Summaries (4 snapshots, latest commit fcaeb03)

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

Previous review (commit fcaeb03)

Status: No New Issues in Incremental Diff | Recommendation: Merge (incremental changes are clean)

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Resolved in this incremental diff (prior findings fixed)
  • tinyagentos/routes/github_oauth.py:329 — permissions now converted to a list of "{k}:{v}" strings (["{k}:{v}" for k, v in inst.get("permissions", {}).items()]). Resolves the prior WARNING about dict-vs-list contract mismatch.
  • desktop/src/lib/github.ts:280GitHubAppInstallation.permissions type changed from Record<string, string> to string[], matching the list contract used by the backend and tests.
  • desktop/src/apps/secrets/GitHubConnect.tsx:107,463handleSaveGrants now accepts permissions: string[] and is called with the installation's real permissions (inst.permissions ?? []) instead of a hardcoded []. Resolves the prior SUGGESTION.

The stack is now type-consistent: GitHub API permission map → list of "perm:access" strings end-to-end (backend, type def, UI, tests).

Carried-forward findings (outside this incremental diff)

The following previously-flagged findings remain on files not changed in this increment and were not re-verified here:

  • tinyagentos/routes/secrets.pyGET /api/secrets/agent/{name}/github authz gap (Depends(get_current_user) only; cross-agent metadata disclosure).
  • tinyagentos/github_token.pyget_agent_github_token uses only installations[0] and mints installation-wide tokens (per-repo grant scope not enforced).
  • tinyagentos/secrets.py:353 — non-dict JSON payload from json.loads not guarded (CodeRabbit).
  • desktop/src/apps/secrets/GitHubConnect.tsx:156 — save failures silently swallowed (CodeRabbit).
Incremental Diff Reviewed (3 files)
  • tinyagentos/routes/github_oauth.py - permissions shape normalized (prior issue resolved)
  • desktop/src/lib/github.ts - permissions type changed to string[] (prior issue resolved)
  • desktop/src/apps/secrets/GitHubConnect.tsx - handleSaveGrants uses real permissions (prior suggestion resolved)

Previous review (commit 75d09eb)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
tinyagentos/routes/github_oauth.py 329 permissions stored as GitHub API permission map ({contents:"read"}) but secrets.py:get_agent_github_installations and tests expect a list (["contents:read"]); contract mismatch across stack
Previously flagged issues — now resolved in HEAD
  • tinyagentos/routes/secrets.pyGET /api/secrets/agent/{agent_name}/github authz gap: now guarded by Depends(get_current_user) (401 for unauthenticated), with a passing test.
  • tinyagentos/github_token.pyget_agent_github_token no longer uses only installations[0]; now iterates all granted installations and returns the first successfully minted token.
  • desktop/src/apps/secrets/GitHubConnect.tsxhandleSaveGrants no longer hardcoded permissions: []; now passes inst.permissions.
  • tinyagentos/github_token.py — LRU eviction changed from insert-order to oldest-expiry-timestamp.
Files Reviewed (9 files, incremental)
  • tinyagentos/routes/secrets.py - auth guard + {name:path} converters added (prior authz issue resolved)
  • tinyagentos/github_token.py - multi-installation iteration + LRU eviction fixed (prior issue resolved)
  • tinyagentos/routes/github_oauth.py - 1 issue (permissions type mismatch)
  • tinyagentos/secrets.py - github-installation category + get_agent_github_installations
  • desktop/src/apps/secrets/GitHubConnect.tsx - per-repo savingGrants Set + real permissions (prior issue resolved)
  • desktop/src/lib/github.ts - permissions added to GitHubAppInstallation
  • tests/test_github_token.py - new token-minting tests
  • tests/test_secrets.py - encryption/grant/auth tests added (incl. 401 auth test)
  • desktop/src/apps/SecretsApp.tsx - not in incremental diff

Previous review (commit 1db9236)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
tinyagentos/routes/secrets.py 42 GET /api/secrets/agent/{agent_name}/github exposes installation IDs/repos with no caller-identity validation; the new path-traversal guard (/, \, ..) is irrelevant since agent_name is not a filesystem path, leaving the original authz gap open
Files Reviewed (10 files, incremental)
  • desktop/src/apps/secrets/GitHubConnect.tsx - 0 issues (permissions + savingGrants Set fixes verified)
  • desktop/src/lib/github.ts - 0 issues
  • desktop/src/apps/SecretsApp.tsx - not in incremental diff
  • tests/test_github_token.py - not in incremental diff
  • tests/test_secrets.py - encryption tests restored (prior coverage regression resolved)
  • tinyagentos/github_token.py - multi-installation iteration + LRU eviction fixed (prior issues resolved)
  • tinyagentos/routes/github_oauth.py - permissions threaded correctly
  • tinyagentos/routes/secrets.py - 1 issue (path-traversal guard ineffective)
  • tinyagentos/secrets.py - not in incremental diff
  • desktop/package-lock.json - generated

Fix these issues in Kilo Cloud

Previous review (commit e1e351e)

Status: 6 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
tinyagentos/routes/secrets.py 42 GET /api/secrets/agent/{agent_name}/github exposes installation IDs/repos with no visible auth guard; agent_name taken from path unverified against caller identity
tinyagentos/github_token.py 147 get_agent_github_token uses only installations[0], dropping other grants; token is minted for the whole installation (all repos), so per-repo grants are not enforced (privilege-scope mismatch)
desktop/src/apps/secrets/GitHubConnect.tsx ~462 handleSaveGrants always persisted with hardcoded permissions: [], discarding the installation's real permissions
tests/test_secrets.py Rewrite deleted all prior encryption round-trip tests (XOR/Fernet migration). That coverage regression should be restored or moved, not dropped

SUGGESTION

File Line Issue
tinyagentos/github_token.py 28 _evict_if_full evicts arbitrary insertion-order entry; a single agent with many installations can evict an unrelated still-valid token. Prefer LRU by expiry
desktop/src/apps/secrets/GitHubConnect.tsx savingGrants is one global boolean, so saving one repo disables the save button for all repos until the request resolves (minor UX race)
Files Reviewed (8 files)
  • desktop/package-lock.json (version bump only)
  • desktop/src/apps/SecretsApp.tsx
  • desktop/src/apps/secrets/GitHubConnect.tsx
  • tests/test_github_token.py
  • tests/test_secrets.py
  • tinyagentos/github_token.py
  • tinyagentos/routes/secrets.py
  • tinyagentos/secrets.py

Fix these issues in Kilo Cloud


Reviewed by hy3:free · Input: 36.6K · Output: 2.9K · Cached: 135.9K

@jaylfc

jaylfc commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Good direction on per-agent GitHub tokens. Fold list before merge (test 3.13 is failing too):

MUST-FIX (security):

  1. secrets.py:42 - GET /api/secrets/agent/{agent_name}/github returns installation IDs + repo names with no visible auth/authorization guard. This leaks which repos an agent can reach to any caller. Gate it (admin session + CSRF, or the agent-token allowlist) the same way the other secrets routes are gated, and add a test that an unauthenticated/cross-agent caller gets 401/403.

MUST-FIX (correctness):
2. github_token.py:147 - get_agent_github_token silently uses installations[0] and drops every other granted installation. If an agent is granted multiple installs this picks one arbitrarily. Resolve the correct installation for the target repo/owner rather than index 0 (this is the same installations[0] pitfall #1997 addressed on the store side).
3. GitHubConnect.tsx:462 - handleSaveGrants is always called with permissions: [] hardcoded, so grants save with empty permissions. Pass the real selected permissions.

Once 1 + 2 are folded and CI is green I will re-review. Note secrets are security-critical so I will deep-review the auth path specifically.

hognek added a commit to hognek/tinyagentos that referenced this pull request Jul 19, 2026
Fix 4 WARNING + 2 SUGGESTION findings from Kilo review on PR jaylfc#2036:

WARNING fixes:
- routes/secrets.py: Validate agent_name path parameter (reject empty,
  path separators, traversal) with docstring noting CSRF auth middleware
- github_token.py: Iterate all granted installations instead of only
  installations[0]; document per-repo vs per-installation token scope
- GitHubConnect.tsx + github_oauth.py + github.ts: Pass real permissions
  from GitHub App installation instead of hardcoded []
- test_secrets.py: Add TestSecretsEncryption class restoring XOR/Fernet
  round-trip coverage (encrypt/decrypt, list masking, update re-encrypt)

SUGGESTION fixes:
- github_token.py: LRU eviction by oldest expiry timestamp
- GitHubConnect.tsx: Per-repo savingGrants Set<string> state
@jaylfc

jaylfc commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Adding to the fold list: your branch has a failing test of its own in CI: tests/test_secrets.py::TestGitHubInstallationCategory::test_update_secret_agents asserts 200 but gets 404, so the new installation-category update route either is not registered where the test expects or the path differs. This is on top of the auth-guard and installations[0] items above. Separately, dev itself had one red test from a #2009/#1932 semantic conflict; fix is up as #2041, so rebase onto dev once that merges and your base will be green again.

hognek added 3 commits July 19, 2026 16:43
…orage

- Add github-installation secret category to SecretsStore
- Create tinyagentos/github_token.py: lifetime-aware token minting cache
  with mint_installation_token() and get_agent_github_token()
- Add SecretsStore.get_agent_github_installations() for per-agent queries
- Add GET /api/secrets/agent/{name}/github endpoint
- Update SecretsApp.tsx with github-installation category support
- Add per-agent access toggles for each GitHub App repo in GitHubConnect.tsx
- Tests: 7/7 github_token tests, 6/7 secrets tests pass
Fix 4 WARNING + 2 SUGGESTION findings from Kilo review on PR jaylfc#2036:

WARNING fixes:
- routes/secrets.py: Validate agent_name path parameter (reject empty,
  path separators, traversal) with docstring noting CSRF auth middleware
- github_token.py: Iterate all granted installations instead of only
  installations[0]; document per-repo vs per-installation token scope
- GitHubConnect.tsx + github_oauth.py + github.ts: Pass real permissions
  from GitHub App installation instead of hardcoded []
- test_secrets.py: Add TestSecretsEncryption class restoring XOR/Fernet
  round-trip coverage (encrypt/decrypt, list masking, update re-encrypt)

SUGGESTION fixes:
- github_token.py: LRU eviction by oldest expiry timestamp
- GitHubConnect.tsx: Per-repo savingGrants Set<string> state
…verters for names with /

- Add Depends(get_current_user) to GET /api/secrets/agent/{agent_name}/github
  so unauthenticated callers receive 401 instead of leaking installation IDs
  and repo names (jaylfc MUST-FIX #1, Kilo WARNING)
- Change {name} to {name:path} on GET/PUT/DELETE /api/secrets/{name}
  so secrets whose names contain / (e.g. GitHub repo full names like
  owner/repo) are correctly routed
- Add test_github_grants_requires_auth (401 for unauthenticated caller)
- Fix test_update_secret_agents (uses literal / path now that {name:path}
  handles multi-segment names)
- Remove useless path-traversal guard on agent_name (Kilo: irrelevant
  since agent_name is not a filesystem path)
@hognek
hognek force-pushed the feat/github-token-grants branch from 1db9236 to 75d09eb Compare July 19, 2026 15:06
Comment thread tinyagentos/routes/github_oauth.py Outdated
"avatar_url": account.get("avatar_url", ""),
},
"repository_selection": inst.get("repository_selection", "selected"),
"permissions": inst.get("permissions", {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: permissions is persisted as the GitHub API permission map ({contents: "read", ...}), but the rest of the pipeline treats it as a list.

inst.permissions here is the GitHub installation permission object (Record<string,string> — see github.ts:280). It is forwarded verbatim by GitHubConnect.tsx:463 into handleSaveGrants, stored in the secret value, and returned by get_agent_github_installations (secrets.py:351) as meta.get("permissions", []). The existing tests assert the shape permissions: ["contents:read"] (a list). So a dict gets stored where a list is the documented/expected contract, and any future consumer that iterates permissions as a list (or compares against the list form) will break or silently no-op.

Normalize the stored shape to a single agreed type — either convert the GH map to a list of "{perm}:{access}" strings at store time, or update secrets.py/tests to expect a dict and document it consistently. Mismatched contracts across the stack are easy to miss and will surface as a runtime bug when the token-minting path starts honoring permissions.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src/apps/secrets/GitHubConnect.tsx`:
- Around line 106-156: Update handleSaveGrants to surface POST/PUT failures
through a lightweight transient error state or inline message instead of
silently swallowing them. Capture network and non-success HTTP responses,
associate the error with repoFullName, and keep the existing saving-state
cleanup in finally.

In `@tinyagentos/routes/secrets.py`:
- Around line 43-58: Update get_agent_github_grants to authorize the
authenticated user as the specified agent’s owner or an administrator before
calling get_agent_github_installations or returning its results. Reuse the
existing owner/admin authorization helper and preserve the current 401 behavior
for unauthenticated callers.

In `@tinyagentos/secrets.py`:
- Around line 341-353: In the result-building loop around _dec and json.loads,
validate that the parsed meta value is a dictionary before calling get; treat
JSON scalars, arrays, and null the same as invalid or undecodable payloads by
using an empty metadata object. Preserve the existing field defaults and
response structure for valid dictionary payloads.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 81f4c37f-e68a-4879-8cf5-7c77973d2164

📥 Commits

Reviewing files that changed from the base of the PR and between 514d947 and 75d09eb.

📒 Files selected for processing (9)
  • desktop/src/apps/SecretsApp.tsx
  • desktop/src/apps/secrets/GitHubConnect.tsx
  • desktop/src/lib/github.ts
  • tests/test_github_token.py
  • tests/test_secrets.py
  • tinyagentos/github_token.py
  • tinyagentos/routes/github_oauth.py
  • tinyagentos/routes/secrets.py
  • tinyagentos/secrets.py

Comment thread desktop/src/apps/secrets/GitHubConnect.tsx
Comment thread tinyagentos/routes/secrets.py
Comment thread tinyagentos/secrets.py
hognek added 2 commits July 19, 2026 17:40
The GitHub API returns permissions as a dict {contents: read} but the
rest of the pipeline (secrets.py, tests) expects a list [contents:read].
Convert at the API-response boundary in github_oauth.py and align
TypeScript types (Record<string,string> → string[]).

Fixes Kilo WARNING: permissions type mismatch across the stack.
…surface save errors

- routes/secrets.py: verify caller owns agent (or is admin) before
  returning GitHub installation grants (CodeRabbit Major)
- secrets.py: guard against json.loads returning non-dict payload
  in get_agent_github_installations (CodeRabbit Minor)
- GitHubConnect.tsx: surface save-failure as transient inline error
  message instead of silently ignoring (CodeRabbit Minor)
@jaylfc
jaylfc merged commit 54ba982 into jaylfc:dev Jul 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants