Skip to content

fix(codex): surface app permission requests as approvable - #7861

Open
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/codex-apps-permission-request-type
Open

fix(codex): surface app permission requests as approvable#7861
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/codex-apps-permission-request-type

Conversation

@Exotic209093

@Exotic209093 Exotic209093 commented Aug 22, 2026

Copy link
Copy Markdown

Problem

Codex Apps (connectors) request extra permissions over JSON-RPC via item/permissions/requestApproval. The Codex adapter had no handler or request-type mapping for that method, so the request fell through to methodNotFound and the tool call stalled with no approval UI in any mode except Auto (where approvalsReviewer: "auto_review" answers it server-side).

Fixes #7825

How I fixed it

  • Added permission_approval to the canonical request types (packages/contracts/src/providerRuntime.ts) and a matching "permission" kind to ProviderRequestKind (packages/contracts/src/orchestration.ts).
  • Registered an item/permissions/requestApproval handler in CodexSessionRuntime.ts: it parks a pending approval, emits a canonical request event, and translates the user decision into the protocol response — accept grants the requested permission profile (acceptForSession sets scope to session), decline answers with an empty grant.
  • Mapped the method and kind in CodexAdapter.ts (toRequestTypeFromMethod, toRequestTypeFromKind) plus detail extraction from the request's reason.
  • Threaded the new kind through ProviderRuntimeIngestion.ts (activity summaries/payloads) and both client folds — web session-logic.ts / ComposerPendingApprovalPanel.tsx and mobile threadActivity.ts / thread-work-log.tsx (new lock icon) — so the approval card renders with allow/deny on every surface.
  • Added a focused adapter test asserting the method maps to a request.opened event with requestType: "permission_approval".

Verification

  • vp test run on CodexAdapter.test.ts (28 tests incl. the new one), CodexSessionRuntime.test.ts, ProviderRuntimeIngestion tests, web session-logic/ComposerPendingApprovalPanel/MessagesTimeline.logic tests — all pass.
  • Targeted typecheck (contracts, effect-codex-app-server, server, web, mobile) and lint on changed files — clean.

Notes

The teardown-settlement gap suggested in the issue did not reproduce: Codex's runtime already settles pending approvals as cancelled in its close path (settlePendingApprovals("cancel")), mirroring the Cursor/Grok pattern, so no change was needed there.

ox-alpha via opencode


Note

Medium Risk
Touches the Codex approval path that can grant app permissions (e.g. network). Also changes interrupt handling so pending user-input prompts are auto-cancelled.

Overview
Codex app connectors can now request extra permissions (item/permissions/requestApproval) through the same allow/deny approval UI as commands and file changes, instead of stalling with methodNotFound.

Adds a permission request kind and permission_approval type, handles the JSON-RPC method in the Codex session runtime (accept grants the requested profile; decline returns an empty grant; acceptForSession scopes to the session), and threads it through ingestion plus web/mobile pending-approval cards (lock icon on mobile).

Separately, interrupting a turn now closes leftover user-input prompts with a cancelled user-input.resolved activity, because some providers drop those callbacks without a matching event.

Reviewed by Cursor Bugbot for commit dbd0869. Configure here.

Note

Add app permission approval as first-class approvable request kind

  • Adds permission to ProviderRequestKind and permission_approval to CanonicalRequestType in orchestration.ts and providerRuntime.ts
  • Maps the Codex provider method item/permissions/requestApproval through the adapter and session runtime in CodexAdapter.ts and CodexSessionRuntime.ts, emitting request.opened events and awaiting a decision before responding with granted permissions
  • Surfaces pending permission approvals in the web approval panel (ComposerPendingApprovalPanel.tsx, session-logic.ts) and mobile work log (threadActivity.ts, thread-work-log.tsx) with a lock icon and dedicated labels
  • Behavioral Change: requestKindFromRequestType and requestKindFromCanonicalRequestType now return a new permission value for permission_approval; any out-of-tree consumers of these unions must handle the new literal

Macroscope summarized 0fe0748.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb7643bf-1987-4436-b855-2242c05213d2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 22, 2026
threadId: event.payload.threadId,
requestId,
turnId,
createdAt: event.payload.createdAt,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/ProviderCommandReactor.ts:1272

The synthetic user-input.resolved activity can be ordered before its user-input.requested activity, leaving the request pending and causing a spurious “User input cancelled” resolution later. pendingUserInputRequests sorts by createdAt and then activity ID, but this uses the interrupt's client timestamp, which may precede the provider request or tie and sort before it. Use a server-side timestamp guaranteed to follow the request, or make resolution ordering independent of timestamps.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/Layers/ProviderCommandReactor.ts around line 1272:

The synthetic `user-input.resolved` activity can be ordered before its `user-input.requested` activity, leaving the request pending and causing a spurious “User input cancelled” resolution later. `pendingUserInputRequests` sorts by `createdAt` and then activity ID, but this uses the interrupt's client timestamp, which may precede the provider request or tie and sort before it. Use a server-side timestamp guaranteed to follow the request, or make resolution ordering independent of timestamps.

yield* providerService.interruptTurn({ threadId: event.payload.threadId });
// Some providers discard their callbacks without emitting a matching
// resolution event. Close those requests after the interrupt succeeds.
yield* Effect.forEach(pendingUserInputRequests(thread.activities), ({ requestId, turnId }) =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/ProviderCommandReactor.ts:1267

processTurnInterruptRequested can append a synthetic user-input.resolved with cancelled: true after the provider has already emitted a real resolution for the same request, causing the activity feed and downstream folds to report an answered prompt as cancelled. pendingUserInputRequests(thread.activities) uses the pre-interrupt snapshot, so re-read the thread after interruptTurn before appending cancellations (or make the append idempotent by request ID).

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/Layers/ProviderCommandReactor.ts around line 1267:

`processTurnInterruptRequested` can append a synthetic `user-input.resolved` with `cancelled: true` after the provider has already emitted a real resolution for the same request, causing the activity feed and downstream folds to report an answered prompt as cancelled. `pendingUserInputRequests(thread.activities)` uses the pre-interrupt snapshot, so re-read the thread after `interruptTurn` before appending cancellations (or make the append idempotent by request ID).

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd0869b8e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +826 to +831
case "item/permissions/requestApproval": {
const payload = readPayload(
EffectCodexSchema.ServerRequest__PermissionsRequestApprovalParams,
event.payload,
);
return payload?.reason ?? undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Show the permissions being granted

When reason is absent—which the protocol schema explicitly permits—or does not enumerate the requested capabilities, this returns no useful detail. runtimeEventToActivities subsequently drops the request's args, so web and mobile only show a generic “App permission approval” card even though approving may grant filesystem or network access, potentially for the entire session. Summarize payload.permissions into the canonical request detail or carry a structured canonical permission field so users can review what they are granting without adding Codex-specific parsing to each client.

AGENTS.md reference: AGENTS.md:L146-L146

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit dbd0869. Configure here.

turnId,
createdAt: event.payload.createdAt,
}),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Interrupt leaves permission approvals open

Medium Severity

After interrupt succeeds, this path only synthesizes cancelled user-input.resolved activities. Pending permission approvals (and other approval kinds) are left open: Codex interruptTurn does not settle pendingApprovalsRef, and no matching approval.resolved is appended. The new app-permission card can stay visible after Stop, and a late allow/deny may answer a request the interrupted turn already abandoned.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit dbd0869. Configure here.

@macroscopeapp

macroscopeapp Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a new capability - permission approval requests - with new runtime logic and user-facing UI. There are also unresolved Medium-severity findings about interrupt not settling pending permission approvals, which warrants human attention.

Not approved because:

  • 2 blocking correctness issues found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

Codex Apps ask for extra permissions via the JSON-RPC method
item/permissions/requestApproval. The Codex adapter had no handler or
request-type mapping for it, so the request fell through to
methodNotFound and the tool call stalled with no approval UI outside
Auto mode.

Add a permission_approval canonical request type and a matching
permission request kind, handle the method in CodexSessionRuntime
(approve grants the requested profile, deny answers an empty grant),
map it in CodexAdapter, and thread the kind through ingestion plus the
web and mobile approval folds so the card renders everywhere.

ox-alpha via opencode
@Exotic209093
Exotic209093 force-pushed the fix/codex-apps-permission-request-type branch from dbd0869 to 0fe0748 Compare August 22, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex "Apps" permission requests map to requestType unknown outside Auto mode, hiding the approval UI

1 participant