chore(release): staging to production - 2026.01.21 - #873
Conversation
Update AppDrawer chat link to navigate to user's default chatflow when available, falling back to /chat if not set. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add fallback handling for agent avatar images that fail to load from the API. When the node-icon API endpoint returns an error (404 or other), the component now gracefully falls back to static PNG images based on the agent type (supervisor vs worker). Changes: - Import fallback images (multiagent_supervisor.png, multiagent_worker.png) - Add useState for tracking icon source and error state - Add onError handler to img element for graceful fallback - Use useCallback to prevent unnecessary re-renders
…e merge - Create aai/routes/credentials-refresh.ts with Google and Atlassian OAuth refresh routes - Mount AAI credentials router before Flowise router to intercept refresh requests - Add invalid_grant error handling with user-friendly re-auth message - Return 401 instead of 500 for re-authentication required errors - Add OAuth Token Refresh documentation to AUTHORIZATION.md Routes: - POST /credentials/refresh-token (Google OAuth) - POST /credentials/refresh-atlassian-token (Atlassian OAuth) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security fix addressing PR review feedback: - Add workspaceId validation in controllers before calling service - Add workspaceId filter to credential queries (prevents cross-tenant access) - Use InternalFlowiseError for consistent error handling - Remove Spanish comments and commented code - Keep REAUTH_REQUIRED error handling for 401 responses Prevents cross-tenant authorization bypass where attacker could refresh another organization's credentials by guessing UUID. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR review fixes:
- Add enforceAbility('Credential') middleware for organization isolation
- Fix response format to use direct res.json(apiResponse) for consistency
Routes now use both middlewares per .claude/rules/api-routes.md:
1. enforceAbility('Credential') - organization isolation
2. checkPermission('credentials:update') - permission check
Response format now matches other credential endpoints.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…r tab calls Addresses PR #824 review feedback from Max Techera. The original fix added credential state management to NodeInputHandler.jsx, but didn't handle the recursive rendering scenario when GoogleDrivePicker is inside tabs. Changes: - Accept credential props (selectedCredential, selectedCredentialData, handleCredentialDataChange) in component signature - Use props with fallback to local state for nested component support - Forward credential props in recursive tab rendering call - Add PropTypes for new props - Notify parent via callback when credential data changes This ensures GoogleDrivePicker works correctly in both direct usage and when nested inside tabs in Canvas/Chatflow views. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…n route - Change client.js 401 handler to always redirect to /api/auth/login - Fix account/index.jsx to use Auth0 login path - Add logging for 401 responses in getCachedSession for debugging Fixes critical issue where unauthenticated users saw 404 on /login page instead of being redirected to Auth0 authentication. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…-404-redirect fix(AGENT-626): redirect to Auth0 login instead of non-existent /login route
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…nputhandler-credential-props fix(AGENT-617): forward credential props in recursive NodeInputHandler tab calls
Pull Request Review: Staging to Production Release (2026.01.21)OverviewThis PR contains two bug fixes ready for production deployment:
✅ Strengths1. Authentication Fix (AGENT-626)
2. Credential Prop Forwarding (AGENT-617)
3. Logging Improvements
🔍 Code Quality AssessmentAGENT-626: Auth0 Login RedirectFiles Changed:
Analysis: AGENT-617: NodeInputHandler Credential PropsFile Changed: packages/ui/src/views/canvas/NodeInputHandler.jsx Analysis: 🔒 Security ReviewNo Security Concerns Found ✅ Authentication redirects handled safely - no open redirects Verification:
⚡ Performance Review✅ No performance impact - Changes are straightforward redirects and prop passing 🧪 Testing ConsiderationsAGENT-626 (Auth Fix):
AGENT-617 (Credential Props):
📋 Best Practices Adherence✅ Follows CLAUDE.md conventions
|
Changed queryVectorStore to filter by workspaceId instead of userId+organizationId for consistency with other document store methods.
…ore-workspace-filter fix(AGENT-639): use workspaceId filter in queryVectorStore
…ck-document-store-chunks-missing fix(SUPPORT-12): Restore AAI credential refresh routes lost in Flowise merge
🔍 Pull Request ReviewThis release PR contains three targeted bug fixes. Overall, the changes are solid and follow repository conventions. Here's my detailed analysis: ✅ Strengths1. AGENT-639: workspaceId Filter Fix ✨Files: What changed:
Why this is good:
2. AGENT-626: Auth0 Login Redirect Fix 🔐Files: What changed:
Why this is good:
3. AGENT-617: Credential Props Forwarding 📋File: What changed:
Why this is good:
4. Session Handling Improvement 🔧File: What changed:
Why this is good:
|
🔍 Security & Multi-Tenancy Analysis✅ Security Checklist
✅ Multi-Tenancy ComplianceThe workspaceId change is exactly the right approach for multi-tenancy: // OLD: Required separate filtering by userId + organizationId
where: { id: data.storeId, userId, organizationId }
// NEW: Single workspace filter (workspace already scopes to org + user)
where: { id: data.storeId, workspaceId }This is more aligned with the repository's workspace-based isolation model. 💡 Suggestions (Optional Improvements)1. Consider Adding Metrics (Low Priority)The 2. Error Message Enhancement (Nitpick)In 🧪 Testing RecommendationsBefore merging to production:
|
📊 Overall Assessment
✅ RecommendationAPPROVED - This PR is ready to merge after successful CI/CD checks and smoke testing. The changes are well-structured, follow repository conventions from Great work on maintaining code quality and security standards! 🎉 |
…images fix(AGENT-612): fix broken agent avatar images in canvas chat
Pull Request Review: Staging to ProductionOverviewThis release contains 6 bug fixes. Code quality is good with proper security patterns. Critical Issues (Must Fix)1. Response Format InconsistencyLocation: packages/server/src/controllers/credentials/index.ts:129 Current returns raw credential, but AUTHORIZATION.md documents response as success/message/data object. Impact: Breaking change for UI components. 2. Missing Ownership CheckPer .claude/rules/api-routes.md, controllers must use checkOwnership(). While workspaceId filtering exists, explicit check is missing. Strengths
Medium Priority
Test CoverageNo tests added. Should add:
SecurityStrengths: enforceAbility, RBAC, encryption, multi-tenancy Verdict: APPROVED WITH REQUIRED CHANGESFix 2 critical issues before production merge:
See detailed review at packages/server/src/controllers/credentials/index.ts:129 and packages/server/src/aai/routes/credentials-refresh.ts |
Detailed FindingsCritical Issue 1: Response FormatCurrent code (line 129): return res.json(apiResponse)Should be: return res.json({
success: true,
message: 'Token refreshed successfully',
data: apiResponse
})Same issue in updateAndRefreshAtlassianToken (line 151). Critical Issue 2: Missing checkOwnership()Add to controller after line 120: const credential = await credentialsService.getCredentialById(req.body.credentialId)
if (req.user && !(await checkOwnership(credential, req.user, req))) {
throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Unauthorized')
}Error Message FixLines 236 and 240 in services/credentials/index.ts: Test RecommendationsCreate packages/server/test/api/credentials-refresh.spec.ts:
|
Additional ContextWhy These Changes Are ImportantMulti-Tenancy (AGENT-639, SUPPORT-12): OAuth Refresh Architecture: Error Handling (refreshGoogleAccessToken.ts): Security AnalysisThe enforceAbility + checkPermission combination is strong:
Adding checkOwnership() completes the defense-in-depth strategy. Performance NotesDatabase query optimization opportunity: Documentation QualityAUTHORIZATION.md is exceptional:
This will significantly reduce support burden. |
Review SummaryFiles Reviewed: 12
Issues Summary
Security Score: 8/10Strong patterns throughout. -1 for missing checkOwnership(), -1 for no rate limiting. Code Quality Score: 8/10Clean code, good patterns. -1 for error message inconsistency, -1 for React state sync issue. Documentation Score: 10/10Exceptional AUTHORIZATION.md documentation. Action Items for MergeBefore Production:
After Merge: Estimated Fix TimeCritical issues: ~15 minutes Total: ~3 hours to production-ready state |
🔍 PR Review: Staging to Production Release✅ Overall AssessmentThis release looks solid! The changes are well-structured, follow repository conventions, and address important bug fixes across authentication, multi-tenancy, and credential management. The PR targets production which is appropriate for a release from staging. 📊 Summary
🎯 Code Quality & Best Practices✅ Strengths
🐛 Potential Issues & Concerns🟡 Minor Concerns
🔒 Security Analysis✅ Security Strengths
🟢 No Security Concerns IdentifiedAll changes follow security best practices from CLAUDE.md and AUTHORIZATION.md. 🚀 Performance Considerations✅ Performance Impacts
🧪 Test Coverage
|
| // Google OAuth refresh (used by GoogleDrivePicker, GmailLabelPicker) | ||
| router.post( | ||
| '/refresh-token', | ||
| enforceAbility('Credential'), |
Check failure
Code scanning / CodeQL
Missing rate limiting High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 7 months ago
In general, the fix is to ensure that HTTP handlers performing expensive token/credential refresh operations are protected by a rate‑limiting middleware. In an Express application, this is commonly done with a library like express-rate-limit, configuring a sensible window and maximum request count, and inserting that middleware in the route definition before the actual controller handler.
For this specific file, the least invasive fix is to: (1) import express-rate-limit, (2) define a limiter instance dedicated to credential refresh operations (e.g., restricting each IP to a certain number of refreshes per time window), and (3) plug that limiter into both /refresh-token and /refresh-atlassian-token routes between the authentication/authorization middlewares and the controller. This avoids changing existing business logic while adding the required protection. Concretely, in packages/server/src/aai/routes/credentials-refresh.ts, add an import for express-rate-limit at the top, define const credentialsRefreshLimiter = rateLimit({ ... }) near the router creation, and then pass credentialsRefreshLimiter as an additional middleware argument in both router.post calls, before credentialsController.updateAndRefreshToken / updateAndRefreshAtlassianToken.
| @@ -2,7 +2,7 @@ | ||
| import credentialsController from '../../controllers/credentials' | ||
| import enforceAbility from '../../middlewares/authentication/enforceAbility' | ||
| import { checkPermission } from '../../enterprise/rbac/PermissionCheck' | ||
|
|
||
| import rateLimit from 'express-rate-limit' | ||
| /** | ||
| * Creates AAI-specific credential refresh routes | ||
| * | ||
| @@ -19,11 +19,19 @@ | ||
| export function createCredentialsRefreshRouter(): Router { | ||
| const router = express.Router() | ||
|
|
||
| const credentialsRefreshLimiter = rateLimit({ | ||
| windowMs: 15 * 60 * 1000, // 15 minutes | ||
| max: 100, // limit each IP to 100 refresh requests per windowMs | ||
| standardHeaders: true, | ||
| legacyHeaders: false, | ||
| }) | ||
|
|
||
| // Google OAuth refresh (used by GoogleDrivePicker, GmailLabelPicker) | ||
| router.post( | ||
| '/refresh-token', | ||
| enforceAbility('Credential'), | ||
| checkPermission('credentials:update'), | ||
| credentialsRefreshLimiter, | ||
| credentialsController.updateAndRefreshToken | ||
| ) | ||
|
|
||
| @@ -32,6 +35,7 @@ | ||
| '/refresh-atlassian-token', | ||
| enforceAbility('Credential'), | ||
| checkPermission('credentials:update'), | ||
| credentialsRefreshLimiter, | ||
| credentialsController.updateAndRefreshAtlassianToken | ||
| ) | ||
|
|
| // Atlassian OAuth refresh | ||
| router.post( | ||
| '/refresh-atlassian-token', | ||
| enforceAbility('Credential'), |
Check failure
Code scanning / CodeQL
Missing rate limiting High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 7 months ago
In general, this should be fixed by adding a rate‑limiting middleware to the credential refresh routes so that a single client cannot send unlimited refresh requests in a short period. For Express, a standard solution is to use the express-rate-limit package to create a limiter with an appropriate window and maximum number of requests, and then apply it to the specific routes that trigger expensive operations.
In this file, the best fix with minimal functional change is to:
- Import
express-rate-limit. - Define one (or two)
rateLimitinstances configured for POST refresh endpoints (e.g., a short window with a modest request cap). - Add the rate‑limiting middleware into the
router.postcalls, alongsideenforceAbilityandcheckPermission, so that requests are authorized and permission‑checked but also throttled.
We should avoid changing existing behavior beyond adding rate limiting, so we’ll keep the controller functions and route paths exactly as they are and just insert the limiter middleware into the chain. We’ll implement this fully withincreateCredentialsRefreshRouter’s file, without assuming any project‑specific helpers.
Concretely:
- In
packages/server/src/aai/routes/credentials-refresh.ts, add an import forrateLimitfromexpress-rate-limit. - Inside
createCredentialsRefreshRouter, after creatingrouter, define a limiter, for example:
const credentialsRefreshLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100,
})(or stricter if desired).
- Add
credentialsRefreshLimiteras a middleware argument to bothrouter.post('/refresh-token', ...)androuter.post('/refresh-atlassian-token', ...), placing it before the auth middlewares or immediately after; either order is acceptable functionally, but placing it early avoids unnecessary auth work on clearly abusive traffic.
| @@ -2,6 +2,7 @@ | ||
| import credentialsController from '../../controllers/credentials' | ||
| import enforceAbility from '../../middlewares/authentication/enforceAbility' | ||
| import { checkPermission } from '../../enterprise/rbac/PermissionCheck' | ||
| import rateLimit from 'express-rate-limit' | ||
|
|
||
| /** | ||
| * Creates AAI-specific credential refresh routes | ||
| @@ -19,9 +20,15 @@ | ||
| export function createCredentialsRefreshRouter(): Router { | ||
| const router = express.Router() | ||
|
|
||
| const credentialsRefreshLimiter = rateLimit({ | ||
| windowMs: 15 * 60 * 1000, // 15 minutes | ||
| max: 100, // limit each IP to 100 refresh requests per window | ||
| }) | ||
|
|
||
| // Google OAuth refresh (used by GoogleDrivePicker, GmailLabelPicker) | ||
| router.post( | ||
| '/refresh-token', | ||
| credentialsRefreshLimiter, | ||
| enforceAbility('Credential'), | ||
| checkPermission('credentials:update'), | ||
| credentialsController.updateAndRefreshToken | ||
| @@ -30,6 +34,7 @@ | ||
| // Atlassian OAuth refresh | ||
| router.post( | ||
| '/refresh-atlassian-token', | ||
| credentialsRefreshLimiter, | ||
| enforceAbility('Credential'), | ||
| checkPermission('credentials:update'), | ||
| credentialsController.updateAndRefreshAtlassianToken |
- Fix hardcoded URL path in Canvas.jsx that was missing the /sidekick-studio prefix - Prevents 404 errors when refreshing page after saving a new agentflow - Enables chat history to load correctly after page refresh Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…flow-url-after-save fix(AGENT-405): add /sidekick-studio prefix to agentflow URL after save
…-update feat(AGENT-573): use default chatflow for chat navigation
Pull Request Review - Staging to Production ReleaseThis PR merges multiple bug fixes from staging to production. Overall code quality is good with proper security measures in place. StrengthsSecurity and Multi-Tenancy (EXCELLENT)
Architecture Compliance
Error Handling
Issues Found1. CRITICAL: Production Branch Target Resolution needed: This appears to be an automated release PR (staging to production). Verify this is intentional and follows your release process. 2. Minor: Inconsistent Error Message Format 3. Code Quality: Hardcoded Fallback Logic Security ReviewNo security vulnerabilities found:
OAuth Token Security:
Performance ConsiderationsGood practices:
Potential optimization: The recursive NodeInputHandler component could benefit from React.memo() wrapper. Test CoverageMissing tests:
Code Quality Suggestions
Checklist CompliancePer .claude/rules/api-routes.md:
RecommendationsHigh Priority:
Medium Priority: Low Priority: Final VerdictOverall Assessment: APPROVED with minor recommendations Deployment Risk: LOW This is a well-implemented bug fix release with:
The code follows repository conventions and is production-ready. Primary concern is ensuring the branch target aligns with your release process. Recommendation: Safe to merge after confirming this is your standard release workflow Review conducted following repository guidelines in CLAUDE.md, .claude/rules/api-routes.md, and .claude/rules/components.md |
PR Review: Staging to Production Release - 2026.01.21OverviewThis is a production release containing 9 bug fixes focused on multi-tenancy authorization, credential refresh functionality, OAuth token handling, and UI improvements. Overall code quality is good with proper adherence to repository patterns. ✅ Strengths1. Multi-Tenancy SecurityAll credential refresh operations now properly filter by
This prevents cross-workspace data leaks. ✅ 2. Authorization & Middleware
Follows repository patterns from 3. Error Handling
4. DocumentationExcellent new documentation in
|
🚀 Release: Staging to Production
Release Date: 2026-01-21
Changes in this release
This PR is automatically created/updated when commits are pushed to staging.
Merging this PR will trigger the release workflow to create a new GitHub release.