From e68088ee959888b84c7e01f222f7416db8491cf3 Mon Sep 17 00:00:00 2001 From: Drew Rothstein Date: Thu, 5 Feb 2026 08:16:53 -0500 Subject: [PATCH 1/3] [config] new env var: `REQUIRE_APPROVAL_NEW_MEMBERS` to set requiring approval via config vs. UI toggle only --- CHANGELOG.md | 1 + .../configuration/auth/access-settings.mdx | 2 +- .../configuration/environment-variables.mdx | 1 + packages/shared/src/env.server.ts | 1 + .../memberApprovalRequiredToggle.tsx | 31 +++++++++++++++++-- .../components/organizationAccessSettings.tsx | 2 ++ .../organizationAccessSettingsWrapper.tsx | 5 ++- packages/web/src/initialize.ts | 13 ++++++++ 8 files changed, 51 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e839d3377..454c7b7b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Added support to set "Require approval for new members" via config with (`REQUIRE_APPROVAL_NEW_MEMBERS`). [#858](https://github.com/sourcebot-dev/sourcebot/pull/858) ## [4.10.27] - 2026-02-05 diff --git a/docs/docs/configuration/auth/access-settings.mdx b/docs/docs/configuration/auth/access-settings.mdx index 5bc638e77..6c466fdbe 100644 --- a/docs/docs/configuration/auth/access-settings.mdx +++ b/docs/docs/configuration/auth/access-settings.mdx @@ -21,7 +21,7 @@ By default, Sourcebot requires new members to be approved by the owner of the de to configure this behavior. ### Configuration -Member approval can be configured by the owner of the deployment by navigating to **Settings -> Members**: +Member approval can be configured by the owner of the deployment by navigating to **Settings -> Access**, or by setting the `REQUIRE_APPROVAL_NEW_MEMBERS` environment variable. When the environment variable is set, the UI toggle is disabled and the setting is controlled by the environment variable. ![Member Approval Toggle](/images/member_approval_toggle.png) diff --git a/docs/docs/configuration/environment-variables.mdx b/docs/docs/configuration/environment-variables.mdx index 859fd1c39..580de3593 100644 --- a/docs/docs/configuration/environment-variables.mdx +++ b/docs/docs/configuration/environment-variables.mdx @@ -21,6 +21,7 @@ The following environment variables allow you to configure your Sourcebot deploy | `DATABASE_URL` | `postgresql://postgres@ localhost:5432/sourcebot` |

Connection string of your Postgres database. By default, a Postgres database is automatically provisioned at startup within the container.

If you'd like to use a non-default schema, you can provide it as a parameter in the database url.

You can also use `DATABASE_HOST`, `DATABASE_USERNAME`, `DATABASE_PASSWORD`, `DATABASE_NAME`, and `DATABASE_ARGS` to construct the database url.

| | `EMAIL_FROM_ADDRESS` | `-` |

The email address that transactional emails will be sent from. See [this doc](/docs/configuration/transactional-emails) for more info.

| | `FORCE_ENABLE_ANONYMOUS_ACCESS` | `false` |

When enabled, [anonymous access](/docs/configuration/auth/access-settings#anonymous-access) to the organization will always be enabled

+| `REQUIRE_APPROVAL_NEW_MEMBERS` | - |

When set, controls whether new users require approval before accessing your deployment. If not set, the setting can be configured via the UI. See [member approval](/docs/configuration/auth/access-settings#member-approval) for more info.

| `REDIS_DATA_DIR` | `$DATA_CACHE_DIR/redis` |

The data directory for the default Redis instance.

| | `REDIS_URL` | `redis://localhost:6379` |

Connection string of your Redis instance. By default, a Redis database is automatically provisioned at startup within the container.

| | `REDIS_REMOVE_ON_COMPLETE` | `0` |

Controls how many completed jobs are allowed to remain in Redis queues

| diff --git a/packages/shared/src/env.server.ts b/packages/shared/src/env.server.ts index 6b4ed8be1..0e5e357b3 100644 --- a/packages/shared/src/env.server.ts +++ b/packages/shared/src/env.server.ts @@ -134,6 +134,7 @@ export const env = createEnv({ // Auth FORCE_ENABLE_ANONYMOUS_ACCESS: booleanSchema.default('false'), + REQUIRE_APPROVAL_NEW_MEMBERS: booleanSchema.optional(), AUTH_SECRET: z.string(), AUTH_URL: z.string().url(), AUTH_CREDENTIALS_LOGIN_ENABLED: booleanSchema.default('true'), diff --git a/packages/web/src/app/components/memberApprovalRequiredToggle.tsx b/packages/web/src/app/components/memberApprovalRequiredToggle.tsx index 9d3cf1bcb..5a4f27b23 100644 --- a/packages/web/src/app/components/memberApprovalRequiredToggle.tsx +++ b/packages/web/src/app/components/memberApprovalRequiredToggle.tsx @@ -10,9 +10,10 @@ import { useToast } from "@/components/hooks/use-toast" interface MemberApprovalRequiredToggleProps { memberApprovalRequired: boolean onToggleChange?: (checked: boolean) => void + isControlledByEnvVar: boolean } -export function MemberApprovalRequiredToggle({ memberApprovalRequired, onToggleChange }: MemberApprovalRequiredToggleProps) { +export function MemberApprovalRequiredToggle({ memberApprovalRequired, onToggleChange, isControlledByEnvVar }: MemberApprovalRequiredToggleProps) { const [enabled, setEnabled] = useState(memberApprovalRequired) const [isLoading, setIsLoading] = useState(false) const { toast } = useToast() @@ -45,8 +46,10 @@ export function MemberApprovalRequiredToggle({ memberApprovalRequired, onToggleC } } + const isDisabled = isLoading || isControlledByEnvVar; + return ( -
+

@@ -56,13 +59,35 @@ export function MemberApprovalRequiredToggle({ memberApprovalRequired, onToggleC

When enabled, new users will need approval from an organization owner before they can access your deployment.

+ {isControlledByEnvVar && ( +
+

+ + + + + This setting is controlled by the REQUIRE_APPROVAL_NEW_MEMBERS environment variable. + +

+
+ )}

diff --git a/packages/web/src/app/components/organizationAccessSettings.tsx b/packages/web/src/app/components/organizationAccessSettings.tsx index 94a8c0408..adb039d60 100644 --- a/packages/web/src/app/components/organizationAccessSettings.tsx +++ b/packages/web/src/app/components/organizationAccessSettings.tsx @@ -21,6 +21,7 @@ export async function OrganizationAccessSettings() { const hasAnonymousAccessEntitlement = hasEntitlement("anonymous-access"); const forceEnableAnonymousAccess = env.FORCE_ENABLE_ANONYMOUS_ACCESS === 'true'; + const memberApprovalEnvVarSet = env.REQUIRE_APPROVAL_NEW_MEMBERS !== undefined; return (
@@ -34,6 +35,7 @@ export async function OrganizationAccessSettings() { memberApprovalRequired={org.memberApprovalRequired} inviteLinkEnabled={org.inviteLinkEnabled} inviteLink={inviteLink} + memberApprovalEnvVarSet={memberApprovalEnvVarSet} />
) diff --git a/packages/web/src/app/components/organizationAccessSettingsWrapper.tsx b/packages/web/src/app/components/organizationAccessSettingsWrapper.tsx index 19fa0a095..bc91963bf 100644 --- a/packages/web/src/app/components/organizationAccessSettingsWrapper.tsx +++ b/packages/web/src/app/components/organizationAccessSettingsWrapper.tsx @@ -8,12 +8,14 @@ interface OrganizationAccessSettingsWrapperProps { memberApprovalRequired: boolean inviteLinkEnabled: boolean inviteLink: string | null + memberApprovalEnvVarSet: boolean } export function OrganizationAccessSettingsWrapper({ memberApprovalRequired, inviteLinkEnabled, - inviteLink + inviteLink, + memberApprovalEnvVarSet }: OrganizationAccessSettingsWrapperProps) { const [showInviteLink, setShowInviteLink] = useState(memberApprovalRequired) @@ -27,6 +29,7 @@ export function OrganizationAccessSettingsWrapper({
diff --git a/packages/web/src/initialize.ts b/packages/web/src/initialize.ts index 97efc9eab..06647e57d 100644 --- a/packages/web/src/initialize.ts +++ b/packages/web/src/initialize.ts @@ -100,6 +100,19 @@ const initSingleTenancy = async () => { } } } + + // Sync member approval setting from env var (only if explicitly set) + if (env.REQUIRE_APPROVAL_NEW_MEMBERS !== undefined) { + const requireApprovalNewMembers = env.REQUIRE_APPROVAL_NEW_MEMBERS === 'true'; + const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN); + if (org && org.memberApprovalRequired !== requireApprovalNewMembers) { + await prisma.org.update({ + where: { id: org.id }, + data: { memberApprovalRequired: requireApprovalNewMembers }, + }); + logger.info(`Member approval requirement set to ${requireApprovalNewMembers} via REQUIRE_APPROVAL_NEW_MEMBERS environment variable`); + } + } } const initMultiTenancy = async () => { From 014daec0739488ae077678ddf92698e6350f308c Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Thu, 5 Feb 2026 14:52:27 -0800 Subject: [PATCH 2/3] Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454c7b7b8..70a26fbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -- Added support to set "Require approval for new members" via config with (`REQUIRE_APPROVAL_NEW_MEMBERS`). [#858](https://github.com/sourcebot-dev/sourcebot/pull/858) + +### Added +- Added support to set "Require approval for new members" via config with (`REQUIRE_APPROVAL_NEW_MEMBERS`). [`#858`](https://github.com/sourcebot-dev/sourcebot/pull/858) ## [4.10.27] - 2026-02-05 From da4f59c4d8149cbd6f0d1d80223f0b2cea392978 Mon Sep 17 00:00:00 2001 From: bkellam Date: Thu, 5 Feb 2026 14:58:21 -0800 Subject: [PATCH 3/3] feedback --- CLAUDE.md | 12 ++++++++ .../memberApprovalRequiredToggle.tsx | 30 +++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f95cf5baa..2ff8c9615 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,3 +17,15 @@ To build a specific package: ```bash yarn workspace @sourcebot/ build ``` + +## Tailwind CSS + +Use Tailwind color classes directly instead of CSS variable syntax: + +```tsx +// Correct +className="border-border bg-card text-foreground text-muted-foreground bg-muted bg-secondary" + +// Incorrect +className="border-[var(--border)] bg-[var(--card)] text-[var(--foreground)]" +``` diff --git a/packages/web/src/app/components/memberApprovalRequiredToggle.tsx b/packages/web/src/app/components/memberApprovalRequiredToggle.tsx index 5a4f27b23..671992328 100644 --- a/packages/web/src/app/components/memberApprovalRequiredToggle.tsx +++ b/packages/web/src/app/components/memberApprovalRequiredToggle.tsx @@ -49,34 +49,34 @@ export function MemberApprovalRequiredToggle({ memberApprovalRequired, onToggleC const isDisabled = isLoading || isControlledByEnvVar; return ( -
+
-

+

Require approval for new members

-

+

When enabled, new users will need approval from an organization owner before they can access your deployment.

{isControlledByEnvVar && ( -
-

- +

+ - - This setting is controlled by the REQUIRE_APPROVAL_NEW_MEMBERS environment variable. + This setting is controlled by the REQUIRE_APPROVAL_NEW_MEMBERS environment variable.