这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@K-Mistele
Copy link
Contributor

@K-Mistele K-Mistele commented Oct 16, 2025

What problem(s) was I solving?

When users enabled bypass permissions with a timeout (e.g., "bypass for 15 minutes") in the draft launcher UI, the selected timeout value was being discarded. This resulted in:

  1. Security concern: Bypass permissions would remain enabled indefinitely instead of automatically expiring after the selected duration
  2. User expectation mismatch: Users selected a timeout but it had no effect
  3. Broken feature: The timeout selection dialog appeared and functioned correctly, but the selected value never reached the backend

The root cause: The frontend was storing the "bypass permissions enabled" flag in localStorage, but was not storing or sending the associated timeout duration to the backend when launching the draft session.

What user-facing changes did I ship?

User Experience Improvement:

  • Bypass permissions timeout now works as designed in draft launcher
  • When users enable bypass permissions with a timeout (default 15 minutes), the timeout now actually takes effect
  • Sessions launch with bypass permissions enabled and a countdown timer
  • Bypass permissions automatically disable when the timer expires
  • Users can toggle bypass off to reset the timeout to default (15 minutes) on next enable

Verification for end users:

  1. Create a draft session
  2. Press opt+y to enable bypass permissions
  3. In the confirmation dialog, set timeout to 5 minutes
  4. Verify "WILL BYPASS PERMISSIONS ON LAUNCH" indicator appears
  5. Launch the draft with a prompt (e.g., "list files")
  6. Session shows bypass permissions enabled with a timer counting down from 5:00
  7. Tool calls are auto-approved while timer is active
  8. After 5 minutes, bypass permissions automatically disables and tool calls require approval again

How I implemented it

Changes in DraftLauncherForm.tsx:

  1. Added state management for timeout (line 58):

    • const [savedBypassTimeout, setSavedBypassTimeout] = useState<number | null>(15)
    • Tracks the user's selected timeout in minutes (default 15)
    • Uses null to represent "no timeout" (indefinite bypass)
  2. Updated confirmation handler (lines 566-573):

    • Changed signature to accept timeoutMinutes parameter from dialog
    • Now saves the timeout value: setSavedBypassTimeout(timeoutMinutes)
    • Closes dialog after confirming both bypass enabled state and timeout
  3. Clear timeout when disabling (line 560):

    • When user toggles bypass permissions off: setSavedBypassTimeout(null)
    • Ensures fresh default timeout (15 min) is prompted on next enable
  4. Include timeout in launch payload (lines 469-471):

    • Added dangerouslySkipPermissionsTimeoutMs to session update
    • Converts minutes to milliseconds: savedBypassTimeout * 60 * 1000
    • Sends undefined if no timeout (indefinite bypass)
  5. Updated dependencies (line 517):

    • Added savedBypassTimeout to handleLaunchDraft dependencies
    • Ensures hook runs when timeout changes

How the backend uses this:

  • Backend already had correct logic to recalculate expiration time from the stored timeout duration
  • This fix ensures the timeout value actually reaches the backend
  • Backend stores the duration (not absolute time), allowing re-calculation from launch moment
  • Timer automatically expires bypass permissions after the duration passes

Pattern consistency:

  • Follows same pattern as savedAutoAccept for similar timeout handling
  • State-only approach (no localStorage) for timeout - fresh value prompted each time

How to verify it

Automated Testing

  • Format check passed: make -C humanlayer-wui check
  • Lint check passed: make -C humanlayer-wui check
  • Type checking passed: make -C humanlayer-wui check
  • Build succeeded: make -C humanlayer-wui build
  • Rust checks passed

Manual Testing

Test Case 1: Bypass with Timeout (5 minutes)

  1. Start draft launcher with no active session
  2. Press opt+y hotkey
  3. See confirmation dialog with timeout selector
  4. Set timeout to 5 minutes (or less for faster testing)
  5. Confirm
  6. Verify "WILL BYPASS PERMISSIONS ON LAUNCH" indicator appears
  7. Enter a prompt: "list the files in the current directory"
  8. Launch draft
  9. Expected: Session launches with bypass permissions enabled
  10. Expected: Timer shows ~5:00 (or selected time) and counts down
  11. Expected: File listing is auto-approved without user interaction
  12. Wait for timer to reach 0:00
  13. Expected: Bypass permissions automatically disables
  14. Expected: Subsequent tool calls require approval

Test Case 2: Bypass without Timeout (Indefinite)

  1. Press opt+y to enable bypass permissions
  2. Uncheck "Auto-disable after" checkbox (sets timeout to null)
  3. Confirm
  4. Launch draft
  5. Expected: Bypass permissions enabled with no timer
  6. Expected: No automatic expiration

Test Case 3: Toggle Off and On

  1. Enable bypass with 10 minute timeout
  2. Press opt+y again to disable
  3. Verify indicator disappears
  4. Press opt+y to re-enable
  5. Expected: Dialog shows default 15 minutes (not previous 10 minutes)
  6. Expected: Timeout was reset when toggled off

Test Case 4: Multiple Draft Sessions

  1. Enable bypass with 15 minute timeout in draft 1
  2. Launch draft 1
  3. Create new draft
  4. Enable bypass with 5 minute timeout in draft 2
  5. Launch draft 2
  6. Expected: Draft 1 session has independent 15:00 timer
  7. Expected: Draft 2 session has independent 5:00 timer
  8. Expected: Timers count down independently

Description for the changelog

Draft Launcher - Bypass Permissions Timeout Fix

Fixed a security issue where the bypass permissions timeout value selected in the draft launcher UI was being discarded during draft launch. Bypass permissions would remain enabled indefinitely instead of automatically expiring after the selected duration.

The timeout value is now properly stored and sent to the backend during launch, enabling the automatic expiration feature to work as designed. Sessions now correctly show a countdown timer and automatically disable bypass permissions when the timer expires.

Fixes ENG-2299

…uest

When users enabled bypass permissions with a timeout in the draft launcher,
the timeout value was being discarded. This resulted in bypass permissions
staying enabled indefinitely instead of expiring after the selected duration.

Changes:
- Add savedBypassTimeout state to track user's timeout selection
- Update confirmation handler to save timeout value from dialog
- Clear timeout state when bypass permissions is toggled off
- Include dangerouslySkipPermissionsTimeoutMs in session update payload
- Convert timeout from minutes to milliseconds before sending to backend

The backend already had correct logic to recalculate expiration from the
stored timeout duration. This fix ensures the timeout value actually reaches
the backend when launching draft sessions.

Fixes ENG-2299
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 799c5e2 in 2 minutes and 3 seconds. Click for details.
  • Reviewed 58 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 4 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. humanlayer-wui/src/components/internal/SessionDetail/components/DraftLauncherForm.tsx:58
  • Draft comment:
    Initializing 'savedBypassTimeout' with a default value of 15 (minutes) – please confirm this default is intended and document the unit.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 50% <= threshold 50% The comment is asking for confirmation of the default value and documentation of the unit. While asking for confirmation is not allowed, suggesting documentation of the unit is a valid request. The comment is partially useful.
2. humanlayer-wui/src/components/internal/SessionDetail/components/DraftLauncherForm.tsx:470
  • Draft comment:
    Converting 'savedBypassTimeout' from minutes to milliseconds using a truthy check. If 0 is a valid timeout, this will treat 0 as false. Consider an explicit null check.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% While technically correct that 0 would be treated as falsy, examining the codebase shows that: 1. savedBypassTimeout is explicitly typed as number | null, 2. It's initialized to 15, 3. It can only be set to null or a positive number through the UI dialog, 4. A timeout of 0 minutes wouldn't make sense in this context. So while the comment is technically accurate, it's pointing out a theoretical issue that can't actually occur in practice. I could be wrong about the UI constraints - perhaps there is a way to set a 0 timeout that I'm not seeing in the code. Also, even if it's not currently possible, future changes might make it possible. The comment suggests a fix for a problem that can't occur in practice. The type system and UI ensure that savedBypassTimeout is either null or a positive number. Making the code more verbose to handle an impossible case would reduce readability without adding value. Delete this comment. While technically correct, it points out a theoretical edge case that can't occur in practice due to the type system and UI constraints. The current code is more readable and the suggested change would add complexity without benefit.
3. humanlayer-wui/src/components/internal/SessionDetail/components/DraftLauncherForm.tsx:465
  • Draft comment:
    Avoid using 'any' for the update payload. Consider defining a proper type/interface for the payload instead of casting to 'any'.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. humanlayer-wui/src/components/internal/SessionDetail/components/DraftLauncherForm.tsx:571
  • Draft comment:
    The updated 'handleDangerousSkipPermissionsConfirm' now accepts a 'timeoutMinutes' parameter. Although state setters are stable, consider documenting the expected behavior and units for clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While documentation could be helpful, this seems like a straightforward internal callback function where the parameter name timeoutMinutes is self-documenting. The usage is clear from the code - it's used to set a timeout in minutes that gets converted to milliseconds later. The null case is also handled appropriately. This feels like an overly pedantic suggestion that doesn't meaningfully improve code quality. I could be wrong if there are important edge cases or behaviors that aren't obvious from the code. Maybe there are constraints on valid timeout values that should be documented. The parameter name clearly indicates the units (minutes), the type indicates it can be null, and the usage shows exactly how it's used. Additional documentation would be redundant. This comment should be deleted as it suggests documentation that would be redundant with the self-documenting parameter name and clear usage in the code.

Workflow ID: wflow_FP3ovU7IVFW2DEbm

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@K-Mistele K-Mistele merged commit 523c34a into main Oct 16, 2025
6 of 7 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.

3 participants