Skip to content

feat: Add auth error code for forbidden emails - #1789

Merged
vishnuszipstack merged 3 commits into
mainfrom
feature/plugin-auth-forbidden-email
Feb 16, 2026
Merged

feat: Add auth error code for forbidden emails#1789
vishnuszipstack merged 3 commits into
mainfrom
feature/plugin-auth-forbidden-email

Conversation

@hari-kuriakose

@hari-kuriakose hari-kuriakose commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

What

  • Add new authorization error code INE003 for forbidden email addresses
  • Add frontend error display for the new forbidden email error
  • Fix frontend dev server to run on port 80 (matching production nginx)
  • Add signup handler to Login component

Why

  • To handle cases where users attempt to authenticate with email addresses that are explicitly forbidden (not just disposable or invalid format)
  • Provides clear user feedback when their email is not allowed
  • Frontend dev server on port 3000 caused 502 errors via Traefik reverse proxy which expects port 80
  • Signup functionality needed for LoginForm component

How

  • Added INE003 constant to AuthorizationErrorCode class in backend
  • Added corresponding error message mapping in frontend GenericError component
  • Set PORT=80 env var and changed EXPOSE to 80 in frontend Dockerfile development stage
  • Added handleSignup function and signupURL in Login.jsx, passed to LoginForm

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No, this is an additive change that only adds a new error code and its display. Existing error codes and flows remain unchanged.
  • The frontend port change only affects development mode and aligns it with production behavior.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • N/A

Related Issues or PRs

  • N/A

Dependencies Versions

  • None

Notes on Testing

  • Test OAuth flow with a forbidden email to verify error code is returned and displayed correctly
  • Rebuild frontend Docker image and verify dev server runs on port 80
  • Verify Traefik routing works without 502 errors

Screenshots

N/A

Checklist

I have read and understood the Contribution Guidelines.

@coderabbitai

coderabbitai Bot commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉


Summary by CodeRabbit

  • New Features

    • Added validation and error messaging for forbidden email addresses during authentication.
  • Chores

    • Updated development environment port configuration to align with production settings.

Walkthrough

Adds backend error code INE003 and updates INE001 description; exposes INE003 to the frontend with a matching user-facing message. Also adjusts frontend Dockerfile dev-stage port to 80 and adds login/signup URL navigation in the Login component.

Changes

Cohort / File(s) Summary
Backend error code definition
backend/account_v2/constants.py
Adds INE003 constant and includes INE003 in AuthorizationErrorCode; updates INE001 description to mention disposable domains.
Frontend error mappings
frontend/src/components/error/GenericError/GenericError.jsx
Adds INE003 entry to the error map with title "Email not allowed" and subtitle "This email is forbidden." No rendering or control-flow changes.
Frontend auth navigation
frontend/src/components/log-in/Login.jsx
Introduces signupURL and loginURL derived from baseUrl; updates handleLogin to use loginURL, adds handleSignup, and passes handleSignup to LoginForm.
Docker dev server port
docker/dockerfiles/frontend.Dockerfile
Adds BUILD_CONTEXT_PATH ARGs, sets PORT=80 and EXPOSE 80 in the development stage, and adds some REACT_APP_* ARG/ENV propagation in the builder stage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change—adding a new authorization error code for forbidden emails—which aligns with the primary objective of the pull request.
Description check ✅ Passed The description follows the template structure and includes all required sections with substantial, relevant information addressing the what, why, how, risk assessment, and testing notes.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/plugin-auth-forbidden-email

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 and usage tips.

@hari-kuriakose hari-kuriakose self-assigned this Feb 13, 2026
Base automatically changed from chore/plugin-loading to main February 13, 2026 05:05
@hari-kuriakose
hari-kuriakose force-pushed the feature/plugin-auth-forbidden-email branch from fa572b9 to 22104e9 Compare February 13, 2026 05:30
@hari-kuriakose
hari-kuriakose marked this pull request as ready for review February 13, 2026 05:34
hari-kuriakose and others added 2 commits February 16, 2026 01:07
- Set PORT=80 env var in frontend Dockerfile development stage
- Change EXPOSE from 3000 to 80 to match production nginx
- Add handleSignup function and pass to LoginForm component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
SonarQube flagged that ARG must be declared in each Docker build stage
where it is used. Added the missing ARG BUILD_CONTEXT_PATH to both
development and builder stages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Test Results

Summary
  • Runner Tests: 11 passed, 0 failed (11 total)
  • SDK1 Tests: 66 passed, 0 failed (66 total)

Runner Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_logs}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup\_skip}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_client\_init}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config\_without\_mount}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_run\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_for\_sidecar}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_sidecar\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{11}}$$ $$\textcolor{#23d18b}{\tt{11}}$$
SDK1 Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_non\_retryable\_http\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retryable\_http\_errors}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_post\_method\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_logging}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_retry\_on\_errors}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_wrapper\_methods\_retry}}$$ $$\textcolor{#23d18b}{\tt{4}}$$ $$\textcolor{#23d18b}{\tt{4}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_connection\_error\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_timeout\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_non\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_without\_response}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_non\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_other\_exception\_not\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_without\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_successful\_call\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_after\_transient\_failure}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_retries\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_time\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_with\_custom\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_no\_retry\_with\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_exception\_not\_in\_tuple\_not\_retried}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_delay\_would\_exceed\_max\_time}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_default\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_environment\_variable\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_retries}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_time}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_base\_delay}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_multiplier}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_jitter\_values}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_exceptions\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_predicate\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_both\_exceptions\_and\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_exceptions\_match\_but\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_platform\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_prompt\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_platform\_service\_decorator\_retries\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_prompt\_service\_decorator\_retries\_on\_timeout}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_warning\_logged\_on\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_info\_logged\_on\_success\_after\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_exception\_logged\_on\_giving\_up}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{66}}$$ $$\textcolor{#23d18b}{\tt{66}}$$

@sonarqubecloud

Copy link
Copy Markdown

@vishnuszipstack
vishnuszipstack merged commit 2d4433a into main Feb 16, 2026
7 checks passed
@vishnuszipstack
vishnuszipstack deleted the feature/plugin-auth-forbidden-email branch February 16, 2026 06:22
hari-kuriakose added a commit that referenced this pull request Feb 24, 2026
* feat: add auth error code and frontend error display

* fix: run frontend dev server on port 80 and add signup handler

- Set PORT=80 env var in frontend Dockerfile development stage
- Change EXPOSE from 3000 to 80 to match production nginx
- Add handleSignup function and pass to LoginForm component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add ARG declaration to Dockerfile stages using BUILD_CONTEXT_PATH

SonarQube flagged that ARG must be declared in each Docker build stage
where it is used. Added the missing ARG BUILD_CONTEXT_PATH to both
development and builder stages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
gaya3-vijayakumar added a commit that referenced this pull request Mar 9, 2026
…1806)

* refactor: Add dynamic plugin loading for enterprise components

## What

- Add dynamic plugin loading support to OSS codebase
- Enable enterprise components to be loaded at runtime without modifying tracked files

## Why

- Enterprise code was overwriting git-tracked OSS files causing dirty git state
- Need clean separation between OSS and enterprise codebases
- OSS should work independently without enterprise components

## How

- `unstract_migrations.py`: Uses try/except ImportError to load from `pluggable_apps.migrations_ext`
- `api_hub_usage_utils.py`: Uses try/except ImportError to load from `plugins.verticals_usage`
- `utils.py`: Uses try/except ImportError to load from `pluggable_apps.manual_review_v2` and `plugins.workflow_manager.workflow_v2.rule_engine`
- `backend.Dockerfile`: Conditional install of `requirements.txt` if present

## Can this PR break any existing features. If yes, please list possible items. If no, please explain why.

- No. The changes add optional plugin loading that gracefully falls back to default behavior when plugins are not present. Existing OSS functionality is preserved.

## Database Migrations

- None

## Env Config

- None

## Relevant Docs

- None

## Related Issues or PRs

- None

## Dependencies Versions

- None

## Notes on Testing

- OSS build: Verify app starts and works without enterprise plugins
- Enterprise build: Verify plugins are loaded and function correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor: Use get_plugin() for API Hub usage utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Refactor random sampling logic in utils.py

Removed redundant import of random and exception handling for manual_review_v2.

Signed-off-by: Hari John Kuriakose <hari@zipstack.com>

* fix: Add Traefik port labels and clean up service ignore list

- Add explicit loadbalancer port labels for backend (8000) and frontend (3000)
  services in docker-compose to ensure proper Traefik routing
- Rename spawned_services to ignored_services for clarity
- Extend ignored_services list to include tool-classifier, tool-text_extractor,
  and worker-unified services that don't need environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Update frontend Docker config for nginx serving

Update Traefik port label to 80 to match nginx and fix Dockerfile to use
BUILD_CONTEXT_PATH for the runtime config script in both dev and prod stages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Use ARG instead of ENV for BUILD_CONTEXT_PATH in frontend Dockerfile

Convert BUILD_CONTEXT_PATH from environment variable to build argument
for proper Docker multi-stage build support. ARGs must be declared
globally and re-declared in each stage that needs them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: Add HubSpot integration plugin for contact event tracking

- Add new integrations plugin category under backend/plugins/integrations/
- Create HubSpot plugin with event-based contact updates
- Track user milestone events: project creation, document upload,
  prompt run, tool export, and API deployment
- Plugin validates is_first_for_org flag and first org member status
- Remove unused hubspot_signup_api() stub from authentication_service
- Update subscription_helper to use plugin pattern for form submissions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [FIX] Fix HITL review screen showing "Never expires" despite TTL being set (#1785)

Fix two interacting bugs that prevented TTL from propagating to HITL
queue records:

1. WorkflowUtil.get_hitl_ttl_seconds was an OSS stub that always returned
   None. Now delegates to get_hitl_ttl_seconds_by_workflow via try/except
   import, falling back to None in OSS environments.

2. _push_to_queue_for_api_deployment never fetched TTL. Now mirrors the
   connector path by calling WorkflowUtil.get_hitl_ttl_seconds and passing
   ttl_seconds through to _create_queue_result and
   _enqueue_to_packet_or_regular_queue.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: Add dynamic plugin loading for enterprise components (#1736)

* refactor: Add dynamic plugin loading for enterprise components

- Add dynamic plugin loading support to OSS codebase
- Enable enterprise components to be loaded at runtime without modifying tracked files

- Enterprise code was overwriting git-tracked OSS files causing dirty git state
- Need clean separation between OSS and enterprise codebases
- OSS should work independently without enterprise components

- `unstract_migrations.py`: Uses try/except ImportError to load from `pluggable_apps.migrations_ext`
- `api_hub_usage_utils.py`: Uses try/except ImportError to load from `plugins.verticals_usage`
- `utils.py`: Uses try/except ImportError to load from `pluggable_apps.manual_review_v2` and `plugins.workflow_manager.workflow_v2.rule_engine`
- `backend.Dockerfile`: Conditional install of `requirements.txt` if present

- No. The changes add optional plugin loading that gracefully falls back to default behavior when plugins are not present. Existing OSS functionality is preserved.

- None

- None

- None

- None

- None

- OSS build: Verify app starts and works without enterprise plugins
- Enterprise build: Verify plugins are loaded and function correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor: Use get_plugin() for API Hub usage utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Refactor random sampling logic in utils.py

Removed redundant import of random and exception handling for manual_review_v2.

Signed-off-by: Hari John Kuriakose <hari@zipstack.com>

* fix: Add Traefik port labels and clean up service ignore list

- Add explicit loadbalancer port labels for backend (8000) and frontend (3000)
  services in docker-compose to ensure proper Traefik routing
- Rename spawned_services to ignored_services for clarity
- Extend ignored_services list to include tool-classifier, tool-text_extractor,
  and worker-unified services that don't need environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Update frontend Docker config for nginx serving

Update Traefik port label to 80 to match nginx and fix Dockerfile to use
BUILD_CONTEXT_PATH for the runtime config script in both dev and prod stages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Use ARG instead of ENV for BUILD_CONTEXT_PATH in frontend Dockerfile

Convert BUILD_CONTEXT_PATH from environment variable to build argument
for proper Docker multi-stage build support. ARGs must be declared
globally and re-declared in each stage that needs them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: typo in ignored services var name

* fix: handle script execution via entrypoint

---------

Signed-off-by: Hari John Kuriakose <hari@zipstack.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: Add auth error code for forbidden emails (#1789)

* feat: add auth error code and frontend error display

* fix: run frontend dev server on port 80 and add signup handler

- Set PORT=80 env var in frontend Dockerfile development stage
- Change EXPOSE from 3000 to 80 to match production nginx
- Add handleSignup function and pass to LoginForm component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add ARG declaration to Dockerfile stages using BUILD_CONTEXT_PATH

SonarQube flagged that ARG must be declared in each Docker build stage
where it is used. Added the missing ARG BUILD_CONTEXT_PATH to both
development and builder stages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>

* [MISC] Improve dev experience by adding a compose debug override (#1765)

* [MISC] Improve Docker dev experience: separate debugpy, optimize memory, add V2 workers support

- Move debugpy to optional compose.debug.yaml for cleaner default dev setup
- Update compose.override.yaml with memory-optimized settings (1 worker, 2 threads)
- Add V2 workers configuration with build definitions
- Move V1 workers to optional workers-v1 profile
- Use modern uv run python -Xfrozen_modules=off pattern for services
- Updated README with compose.debug.yaml usage instructions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [MISC] Add Docker Compose version requirement and scheduler comment

- Add Docker Compose 2.24.4+ requirement note for !override directive
- Add comment explaining why worker-log-history-scheduler-v2 has no watch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [MISC] Fix debug ports table in README

- Fix port order: runner=5679, platform=5680, prompt=5681
- Remove x2text-service (not in compose.debug.yaml)
- Add V2 workers debug ports (5682-5688)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [MISC] Simplify sample.compose.override.yaml

Remove db image override and V1 worker command overrides from
sample file. Users should reference compose.override.yaml for
actual dev setup.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* [FIX] Optimize queries made by worker and retry config of worker base client (#1798)

* Fix production queryset performance and retry amplification

Resolves 39.8s GET /internal/v1/file-execution/<uuid>/ latency by:
- Removing 7 debug COUNT(*) full table scans from get_queryset()
- Adding get_object() O(1) PK lookup override in ViewSet
- Adding @with_cache decorators to pipeline fetch methods
- Adding pipeline_data_key() to prevent cache key collisions
- Fixing urllib3 retry amplification: clear status_forcelist, let app-level retries handle status codes
- Use config defaults instead of hardcoded retry values

Root cause: Count queries on every request + retry storm (urllib3 × app-level).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR #1798 review comments

- Chain exception context in get_object() (Ruff B904)
- Fix cache key collision: get_workflow_definition() now uses
  CacheType.WORKFLOW_DEFINITION instead of CacheType.WORKFLOW to avoid
  type mismatch with get_workflow() sharing the same cache key
- Include check_active in get_pipeline_data() cache key to prevent
  active-status bypass when check_active=False is cached first
- Refactor status() and update_hash() to use self.get_object() instead
  of duplicating manual queryset + org filtering; add except APIException
  pass-through so NotFound propagates as 404 not 500

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* UN-2971 [FEAT] Pass selectedProduct to login/signup API for OAuth product scope (#1803)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Hari John Kuriakose <hari@zipstack.com>
Co-authored-by: Claude <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: Scope HubSpot milestone count checks to current organization

PromptStudioOutputManager and DocumentManager lack
DefaultOrganizationManagerMixin, so .objects.count() was counting
across ALL organizations. Filter through the tool FK to CustomTool
(which is org-scoped) to get correct per-org counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [REFACTOR] Extract HubSpot notification logic into shared utility

Move all _notify_hubspot_* methods from views into a shared
utils/hubspot_notify.py module with a single notify_hubspot_event()
function, reducing duplication across prompt_studio views and
api_deployment_views.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Signed-off-by: Hari John Kuriakose <hari@zipstack.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: vishnuszipstack <117254672+vishnuszipstack@users.noreply.github.com>
Co-authored-by: Chandrasekharan M <117059509+chandrasekharan-zipstack@users.noreply.github.com>
Co-authored-by: vishnuszipstack <vishnu@zipstack.com>
Co-authored-by: Gayathri <142381512+gaya3-zipstack@users.noreply.github.com>
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.

4 participants