Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/sim/app/api/files/serve/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ async function compileDocumentIfNeeded(
return { buffer: stored.buffer, contentType: stored.contentType }
}

if (isE2BDocEnabled && getE2BDocFormat(filename)) {
if (isE2BDocEnabled && (await getE2BDocFormat(filename))) {
// Artifact not built yet (still generating, or the source didn't compile at
// write time). Signal "not ready" without compiling — handled as 409.
throw new DocCompileUserError('Document is still being generated')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const GET = withRouteHandler(
// In the E2B regime ALL four formats compile in the doc sandbox (Node for
// pptx/docx, Python for pdf/xlsx). Gate on the flag (not the stored MIME) so
// a stale file can't trigger an E2B compile when the sandbox is disabled.
const e2bFmt = isE2BDocEnabled ? getE2BDocFormat(fileRecord.name) : null
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(fileRecord.name) : null
const taskId = BINARY_DOC_TASKS[ext]
const isMermaidFile = ext === 'mmd' || ext === 'mermaid'
if (!e2bFmt && !taskId && !isMermaidFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,9 @@ import {
DropdownMenuTrigger,
Plus,
} from '@/components/emcn'
import { isWorkflowColumnsEnabledClient } from '@/lib/core/config/env-flags'
import type { ColumnDefinition } from '@/lib/table'
import { COLUMN_TYPE_OPTIONS } from '../column-config-sidebar'

const VISIBLE_COLUMN_TYPE_OPTIONS = isWorkflowColumnsEnabledClient
? COLUMN_TYPE_OPTIONS
: COLUMN_TYPE_OPTIONS.filter((o) => o.type !== 'workflow')

const CELL_HEADER =
'border-[var(--border)] border-r border-b bg-[var(--bg)] px-2 py-[7px] text-left align-middle'

Expand Down Expand Up @@ -67,16 +62,14 @@ export function NewColumnDropdown({
)}
</DropdownMenuTrigger>
<DropdownMenuContent align='start' side='bottom' sideOffset={4}>
{isWorkflowColumnsEnabledClient && (
<>
<DropdownMenuItem onSelect={onPickEnrichment}>
<Sparkles className='size-[14px] text-[var(--text-icon)]' />
Enrichments
</DropdownMenuItem>
<DropdownMenuSeparator />
</>
)}
{VISIBLE_COLUMN_TYPE_OPTIONS.map((option) => {
Comment thread
TheodoreSpeaks marked this conversation as resolved.
<>
<DropdownMenuItem onSelect={onPickEnrichment}>
<Sparkles className='size-[14px] text-[var(--text-icon)]' />
Enrichments
</DropdownMenuItem>
<DropdownMenuSeparator />
</>
{COLUMN_TYPE_OPTIONS.map((option) => {
const Icon = option.icon
const onSelect =
option.type === 'workflow'
Expand Down
9 changes: 5 additions & 4 deletions apps/sim/lib/copilot/tools/handlers/function-execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger'
import { decodeVfsPathSegments, encodeVfsPathSegments } from '@/lib/copilot/vfs/path-utils'
import { resolveWorkflowAliasForWorkspace } from '@/lib/copilot/vfs/workflow-alias-resolver'
import { isPlanAliasPath, workflowAliasSandboxPath } from '@/lib/copilot/vfs/workflow-aliases'
import { isMothershipBetaFeaturesEnabled } from '@/lib/core/config/env-flags'
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import { queryRows } from '@/lib/table/rows/service'
import { getTableById, listTables } from '@/lib/table/service'
import { listWorkspaceFileFolders } from '@/lib/uploads/contexts/workspace/workspace-file-folder-manager'
Expand Down Expand Up @@ -71,10 +71,11 @@ async function resolveInputFiles(
): Promise<SandboxFile[]> {
const sandboxFiles: SandboxFile[] = []
let totalSize = 0
const betaEnabled = await isFeatureEnabled('mothership-beta')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 mothership-beta evaluated without user context in several callers

isFeatureEnabled('mothership-beta') is called here (and in workflow-alias-resolver.ts and getE2BDocFormat in doc-compile.ts) without a userId. If the flag is later configured with a userIds allowlist in AppConfig, beta-enabled users would be denied access via these code paths even though WorkspaceVFS.materialize would correctly grant it. The per-user semantics promised in WorkspaceVFS are silently absent anywhere the call chain doesn't have a userId available — worth documenting or passing through as a future hardening item.

Comment thread
cursor[bot] marked this conversation as resolved.

if (inputFiles?.length && workspaceId) {
const allFiles = await listWorkspaceFiles(workspaceId, {
includeReservedSystemFiles: isMothershipBetaFeaturesEnabled,
includeReservedSystemFiles: betaEnabled,
})
for (const fileRef of inputFiles) {
const filePath =
Expand Down Expand Up @@ -136,11 +137,11 @@ async function resolveInputFiles(

if (inputDirectories?.length && workspaceId) {
const folders = await listWorkspaceFileFolders(workspaceId, {
includeReservedSystemFolders: isMothershipBetaFeaturesEnabled,
includeReservedSystemFolders: betaEnabled,
})
const allFiles = await listWorkspaceFiles(workspaceId, {
folders,
includeReservedSystemFiles: isMothershipBetaFeaturesEnabled,
includeReservedSystemFiles: betaEnabled,
})
for (const dirRef of inputDirectories) {
const dirPath =
Expand Down
12 changes: 6 additions & 6 deletions apps/sim/lib/copilot/tools/server/files/doc-compile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createLogger } from '@sim/logger'
import { isMothershipBetaFeaturesEnabled } from '@/lib/core/config/env-flags'
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import { executeInE2B, executeShellInE2B, type SandboxFile } from '@/lib/execution/e2b'
import { CodeLanguage } from '@/lib/execution/languages'
import {
Expand Down Expand Up @@ -53,7 +53,7 @@ export interface E2BDocFormat {
* pptx/docx → node, pdf/xlsx → python. Only meaningful when the E2B doc sandbox
* is enabled; callers gate on isE2BDocEnabled before using this.
*/
export function getE2BDocFormat(fileName: string): E2BDocFormat | null {
export async function getE2BDocFormat(fileName: string): Promise<E2BDocFormat | null> {
const l = fileName.toLowerCase()
if (l.endsWith('.pptx'))
return {
Expand All @@ -79,10 +79,10 @@ export function getE2BDocFormat(fileName: string): E2BDocFormat | null {
contentType: PDF_MIME,
sourceMime: PYTHON_PDF_SOURCE_MIME,
}
// xlsx is gated behind the mothership beta flag (like plans/changelog): the
// xlsx is gated behind the mothership-beta feature flag (like plans/changelog): the
// skill + prompt are gated on the Go side, and this is the single Sim chokepoint
// that keeps the compile/serve/check/recalc paths off for xlsx when beta is off.
if (l.endsWith('.xlsx') && isMothershipBetaFeaturesEnabled)
if (l.endsWith('.xlsx') && (await isFeatureEnabled('mothership-beta')))
return {
ext: 'xlsx',
engine: 'python',
Expand Down Expand Up @@ -385,7 +385,7 @@ export async function compileDoc(
args: CompileArgs
): Promise<{ buffer: Buffer; contentType: string }> {
const { source, fileName, workspaceId } = args
const fmt = getE2BDocFormat(fileName)
const fmt = await getE2BDocFormat(fileName)
if (!fmt) throw new Error(`Unsupported document format: ${fileName}`)

const existing = await loadCompiledDoc(workspaceId, source, fmt.ext)
Expand All @@ -409,7 +409,7 @@ export async function loadCompiledDocByExt(
source: string,
ext: string
): Promise<{ buffer: Buffer; contentType: string } | null> {
const fmt = getE2BDocFormat(`x.${ext}`)
const fmt = await getE2BDocFormat(`x.${ext}`)
if (!fmt) return null
const buffer = await loadCompiledDoc(workspaceId, source, fmt.ext)
return buffer ? { buffer, contentType: fmt.contentType } : null
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/copilot/tools/server/files/edit-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const editContentServerTool: BaseServerTool<EditContentArgs, EditContentR
try {
const { operation, fileRecord } = intent
const docInfo = getDocumentFormatInfo(fileRecord.name)
const e2bFmt = isE2BDocEnabled ? getE2BDocFormat(fileRecord.name) : null
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(fileRecord.name) : null

let finalContent: string
switch (operation) {
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/lib/copilot/tools/server/files/workspace-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,13 @@ export async function compileDocForWrite(args: {
}): Promise<CompileForWriteResult> {
const { source, fileName, workspaceId, ownerKey, signal, fallbackMime } = args
const docInfo = getDocumentFormatInfo(fileName)
const e2bFmt = isE2BDocEnabled ? getE2BDocFormat(fileName) : null
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(fileName) : null

if (!e2bFmt && fileName.toLowerCase().endsWith('.xlsx')) {
return {
ok: false,
message: isE2BDocEnabled
? 'Excel (.xlsx) generation is currently behind a beta flag (MOTHERSHIP_BETA_FEATURES) and is not available.'
? 'Excel (.xlsx) generation is currently behind the mothership-beta feature flag and is not available.'
: 'Excel (.xlsx) generation requires the E2B document sandbox, which is not enabled in this environment.',
}
}
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/lib/copilot/vfs/workflow-alias-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
resolveWorkspacePlanAliasPath,
type WorkflowAliasTarget,
} from '@/lib/copilot/vfs/workflow-aliases'
import { isMothershipBetaFeaturesEnabled } from '@/lib/core/config/env-flags'
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import { canonicalizeVfsPath } from './path-utils'

export async function resolveWorkflowAliasForWorkspace(args: {
workspaceId: string
path: string
}): Promise<WorkflowAliasTarget | null> {
if (!isMothershipBetaFeaturesEnabled) return null
if (!(await isFeatureEnabled('mothership-beta'))) return null
Comment thread
cursor[bot] marked this conversation as resolved.
if (!isPlanAliasPath(args.path)) return null

let canonicalPath: string
Expand Down
21 changes: 12 additions & 9 deletions apps/sim/lib/copilot/vfs/workspace-vfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ import {
workspacePlanBackingPath,
workspacePlansBackingFolderPath,
} from '@/lib/copilot/vfs/workflow-aliases'
import { isE2BDocEnabled, isMothershipBetaFeaturesEnabled } from '@/lib/core/config/env-flags'
import { isE2BDocEnabled } from '@/lib/core/config/env-flags'
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import {
getAccessibleEnvCredentials,
getAccessibleOAuthCredentials,
Expand Down Expand Up @@ -379,6 +380,7 @@ function getStaticComponentFiles(): Map<string, string> {
export class WorkspaceVFS {
private files: Map<string, string> = new Map()
private _workspaceId = ''
private _betaEnabled = false

get workspaceId(): string {
return this._workspaceId
Expand All @@ -393,6 +395,7 @@ export class WorkspaceVFS {
const start = Date.now()
this.files = new Map()
this._workspaceId = workspaceId
this._betaEnabled = await isFeatureEnabled('mothership-beta', { userId })

// Per-phase wall-clock, stamped on the span so a slow materialize in a
// trace names its bottleneck instead of showing up as unattributed dead
Expand Down Expand Up @@ -591,7 +594,7 @@ export class WorkspaceVFS {
path: string,
suffix: 'style' | 'compiled-check' | 'compiled' | 'render' | 'extract'
): Promise<WorkspaceFileRecord | null> {
if (!isMothershipBetaFeaturesEnabled && isWorkflowAliasBackingPath(path)) {
if (!this._betaEnabled && isWorkflowAliasBackingPath(path)) {
return null
}
const canonicalMatch = path.match(new RegExp(`^files/(.+)/${suffix}$`))
Expand Down Expand Up @@ -642,7 +645,7 @@ export class WorkspaceVFS {
totalLines: 1,
}
}
if (isE2BDocEnabled && getE2BDocFormat(record.name)) {
if (isE2BDocEnabled && (await getE2BDocFormat(record.name))) {
bin = (
await compileDoc({ source: code, fileName: record.name, workspaceId: this._workspaceId })
).buffer
Expand Down Expand Up @@ -695,7 +698,7 @@ export class WorkspaceVFS {
record = await this.resolveWorkspaceFileForDynamicRead(path, 'compiled')
if (!record) return null
const ext = record.name.split('.').pop()?.toLowerCase() ?? ''
const e2bFmt = isE2BDocEnabled ? getE2BDocFormat(record.name) : null
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(record.name) : null
const taskId = BINARY_DOC_TASKS[ext]
if (!e2bFmt && !taskId) return null

Expand Down Expand Up @@ -890,7 +893,7 @@ export class WorkspaceVFS {
record = await this.resolveWorkspaceFileForDynamicRead(path, 'compiled-check')
if (!record) return null
const ext = record.name.split('.').pop()?.toLowerCase() ?? ''
const e2bFmt = isE2BDocEnabled ? getE2BDocFormat(record.name) : null
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(record.name) : null
const taskId = BINARY_DOC_TASKS[ext]
const isMermaidFile = ext === 'mmd' || ext === 'mermaid'
if (!e2bFmt && !taskId && !isMermaidFile) return null
Expand Down Expand Up @@ -978,7 +981,7 @@ export class WorkspaceVFS {
.replace(/\/content$/, '')
.replace(/^\/+/, '')

if (!isMothershipBetaFeaturesEnabled && isWorkflowAliasBackingPath(fileReference)) {
if (!this._betaEnabled && isWorkflowAliasBackingPath(fileReference)) {
return null
}
if (fileReference.endsWith('/meta.json') || path.endsWith('/meta.json')) return null
Expand All @@ -988,7 +991,7 @@ export class WorkspaceVFS {
try {
const files = await listWorkspaceFiles(this._workspaceId, {
scope,
includeReservedSystemFiles: isMothershipBetaFeaturesEnabled,
includeReservedSystemFiles: this._betaEnabled,
})
const record = findWorkspaceFileRecord(files, fileReference)
if (!record) return null
Expand Down Expand Up @@ -1021,7 +1024,7 @@ export class WorkspaceVFS {
* Returns a summary for WORKSPACE.md generation.
*/
private async materializeWorkflows(workspaceId: string): Promise<WorkspaceMdData['workflows']> {
const workflowArtifactsEnabled = isMothershipBetaFeaturesEnabled
const workflowArtifactsEnabled = this._betaEnabled
const [workflowRows, folderRows] = await Promise.all([
listWorkflows(workspaceId),
listFolders(workspaceId),
Expand Down Expand Up @@ -1404,7 +1407,7 @@ export class WorkspaceVFS {
*/
private async materializeFiles(workspaceId: string): Promise<WorkspaceMdData['files']> {
try {
const workflowArtifactsEnabled = isMothershipBetaFeaturesEnabled
const workflowArtifactsEnabled = this._betaEnabled
const folders = await listWorkspaceFileFolders(workspaceId, {
includeReservedSystemFolders: true,
})
Expand Down
22 changes: 0 additions & 22 deletions apps/sim/lib/core/config/env-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,6 @@ export const isBillingEnabled = isTruthy(env.BILLING_ENABLED)
*/
export const isFreeApiDeploymentGateEnabled = isTruthy(env.FREE_API_DEPLOYMENT_GATE_ENABLED)

/**
* Order table rows by fractional `order_key` (O(1) insert/delete) instead of the
* legacy integer `position`. When off, behavior is unchanged. Keys are written
* regardless of this flag; it only controls which column is authoritative for
* reads/ordering and whether inserts/deletes reshift positions.
*/
export const isTablesFractionalOrderingEnabled = isTruthy(env.TABLES_FRACTIONAL_ORDERING)

/**
* Is email verification enabled
*/
Expand Down Expand Up @@ -173,20 +165,6 @@ export const isDataRetentionEnabled = isTruthy(env.DATA_RETENTION_ENABLED)
*/
export const isDataDrainsEnabled = isTruthy(env.DATA_DRAINS_ENABLED)

/**
* Are workflow output columns enabled in user tables.
* Defaults to false; set NEXT_PUBLIC_WORKFLOW_COLUMNS_ENABLED=true to show
* the "Workflow" column type in the new-column dropdown.
*/
export const isWorkflowColumnsEnabledClient = isTruthy(
getEnv('NEXT_PUBLIC_WORKFLOW_COLUMNS_ENABLED')
)

/**
* Enables beta Mothership plan/changelog artifact surfaces.
*/
export const isMothershipBetaFeaturesEnabled = isTruthy(env.MOTHERSHIP_BETA_FEATURES)

/**
* Is E2B enabled for remote code execution
*/
Expand Down
Loading
Loading