Skip to content

feat(invites): 1 hour default TTL + optional per-mint ttl_secs#2072

Merged
jaylfc merged 1 commit into
devfrom
feat/invite-ttl-choice
Jul 20, 2026
Merged

feat(invites): 1 hour default TTL + optional per-mint ttl_secs#2072
jaylfc merged 1 commit into
devfrom
feat/invite-ttl-choice

Conversation

@jaylfc

@jaylfc jaylfc commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Follow-up to #2071, from the same live-test session: both invites expired before they could be redeemed because the TTL was 15 minutes.

Change

  • Default invite TTL 15 minutes to 1 hour.
  • POST /api/projects/{id}/invites accepts optional ttl_secs (60s to 24h, validated); omitted uses the default.
  • ProjectInviteStore.mint takes ttl_secs=None and falls back to the default, so every other call site is unchanged.

Rationale

Handing an invite URL + PIN to a human who then configures an agent is not a 15 minute flow. The PIN (plus the pending cap and single-use redeem) is the actual security control; expiry is hygiene, so an hour by default with an explicit opt-in up to a day is the right balance. 24h is a hard cap so no invite lives indefinitely.

Testing

  • New: default TTL lands at 1 hour, ttl_secs honoured at the 24h bound, over-cap rejected 422.
  • Invite store + route suites: 70 passed.

Follow-up

The mint dialog gets a TTL picker (15m / 1h / 24h) as part of the #2065 rework - the backend contract lands here first so the UI has something to call.

Summary by CodeRabbit

  • New Features
    • Project invites now default to a one-hour expiration.
    • Invite creators can set a custom expiration period from 60 seconds up to 24 hours.
    • Invalid expiration values are rejected with a validation error.

The 15 minute TTL killed invites before a human could hand the link and
PIN to an agent operator: both of the maintainer's live-test invites
expired unredeemed. Default is now 1 hour, and mint accepts an optional
ttl_secs (60s to 24h) so a longer-lived invite is a deliberate choice at
mint time rather than a code change. The PIN remains the security gate;
expiry is hygiene.

Tests: default lands at 1 hour, ttl_secs is honoured, over-cap is 422.
@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 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b583a4a9-a7de-4b86-9aa5-b2e45dfddd19

📥 Commits

Reviewing files that changed from the base of the PR and between 7f37f07 and 2cb2b7f.

📒 Files selected for processing (3)
  • tests/test_routes_project_invites.py
  • tinyagentos/projects/invite_store.py
  • tinyagentos/routes/project_invites.py

📝 Walkthrough

Walkthrough

Project invite minting now supports optional TTL overrides bounded from 60 seconds to 24 hours. The default expiry increased from 15 minutes to one hour, and route tests cover default, custom, and rejected TTL values.

Changes

Project invite TTL

Layer / File(s) Summary
TTL request contract and route wiring
tinyagentos/routes/project_invites.py
MintInviteIn accepts bounded optional ttl_secs values and forwards them to ProjectInviteStore.mint.
Expiry calculation and validation
tinyagentos/projects/invite_store.py, tests/test_routes_project_invites.py
Invite expiry defaults to one hour, accepts positive overrides, and is tested for default, 24-hour, and over-cap behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant mint_invite
  participant ProjectInviteStore
  Client->>mint_invite: Submit optional ttl_secs
  mint_invite->>ProjectInviteStore: mint(ttl_secs)
  ProjectInviteStore-->>mint_invite: Return invite with expires_ts
Loading

Possibly related PRs

  • jaylfc/taOS#1918: Modifies the same project-invite minting pipeline and invite record handling.

Suggested reviewers: hognek

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly summarizes the main change: default invite TTL increased to 1 hour with optional per-mint ttl_secs.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/invite-ttl-choice

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 20, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

expires_ts = now + _EXPIRY_SECS
if ttl_secs is not None and ttl_secs <= 0:
raise ValueError("ttl_secs must be positive")
expires_ts = now + (ttl_secs if ttl_secs is not None else _EXPIRY_SECS)

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: mint only enforces a lower bound on ttl_secs (> 0); the 24-hour hard cap lives solely in the route-layer Pydantic model (le=86400).

mint is a shared boundary called from multiple routes (project mint here, plus the OS-level mint call sites). If any current or future caller passes a ttl_secs that hasn't been route-validated, this line will silently mint an invite that lives far longer than the intended 24h cap — defeating the "no invite lives indefinitely" guarantee described in the PR. Consider clamping/validating the upper bound in the store itself so the invariant holds regardless of caller.


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

@kilo-code-bot

kilo-code-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Optional - consider before merge

Overview

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

SUGGESTION

File Line Issue
tinyagentos/projects/invite_store.py 186 mint enforces only a lower bound on ttl_secs; the 24h hard cap lives only in the route layer, so other/future callers of this shared store method could bypass it.

The change is small, focused, and well-tested. The default TTL bump (15m -> 1h), the optional ttl_secs field with route-level bounds (ge=60, le=86400), and the store's ttl_secs=None fallback are all correct and backward-compatible with existing mint call sites. No critical or high-severity issues found.

Files Reviewed (3 files)
  • tinyagentos/projects/invite_store.py - 1 issue
  • tinyagentos/routes/project_invites.py - 0 issues
  • tests/test_routes_project_invites.py - 0 issues

Fix these issues in Kilo Cloud


Reviewed by hy3:free · Input: 70.6K · Output: 7.9K · Cached: 435.9K

@jaylfc
jaylfc merged commit 37fb4b3 into dev Jul 20, 2026
11 checks passed
@jaylfc
jaylfc deleted the feat/invite-ttl-choice branch July 20, 2026 23:18
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.

1 participant