Skip to content

Commit 7f82c65

Browse files
committed
Merge origin/staging into feat/mothership-revamp
Staging: e2cdee6 Branch parent: d370714 Reconciles staging's public organization APIs with scoped Mothership settings operations, keeping canonical application use cases, current-role checks, and the locked invitation resend lifecycle. Preserves federated Search, Slack/Search MCP, organization/member Generic Secrets, and the expanded Search composer. Keeps the GitHub repository selector in both live and rollback modes. Retains staging's shared HomeSection and GitLab PAT selector patterns. Reconciles the divergent migration journals with an additive, replay-safe 0380 migration. Verified upgrades from the actual previous branch and staging DDL on disposable PostgreSQL, including skipped-index recovery and existing secret/usage data preservation. Validation: all 26 workspace type-checks; all 49 repository audits; changed-file lint/format; app/auth/Search/CLI/desktop/database suites; disposable Search integration suites; localhost Home, Sources, Gmail configuration, and Generic Secrets smoke checks.
2 parents d370714 + e2cdee6 commit 7f82c65

719 files changed

Lines changed: 129837 additions & 19820 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ jobs:
234234
github.event_name == 'push' &&
235235
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
236236
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
237-
timeout-minutes: 15
237+
timeout-minutes: 30
238238
outputs:
239239
version: ${{ steps.deploy.outputs.deploymentVersion }}
240240
environment: ${{ steps.target.outputs.environment }}
@@ -291,7 +291,7 @@ jobs:
291291
if [ -n "$TRIGGER_BRANCH" ]; then
292292
TARGET_ARGS+=(--branch "$TRIGGER_BRANCH")
293293
fi
294-
bunx trigger.dev@4.5.12 deploy "${TARGET_ARGS[@]}" --skip-promotion
294+
bunx trigger.dev@4.5.16 deploy "${TARGET_ARGS[@]}" --skip-promotion
295295
296296
- name: Validate deployment version output
297297
env:
@@ -644,7 +644,7 @@ jobs:
644644
if [ -n "$TRIGGER_BRANCH" ]; then
645645
TARGET_ARGS+=(--branch "$TRIGGER_BRANCH")
646646
fi
647-
bunx trigger.dev@4.5.12 promote "$VERSION" "${TARGET_ARGS[@]}"
647+
bunx trigger.dev@4.5.16 promote "$VERSION" "${TARGET_ARGS[@]}"
648648
649649
# Build ARM64 images for GHCR (main branch only, runs in parallel with
650650
# tests). Pushes only the immutable sha tag — latest-arm64/version-arm64

‎.github/workflows/test-build.yml‎

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ jobs:
108108
bunx vitest run
109109
scripts/retired-columns.postgres.test.ts
110110
scripts/connector-sync-schedule-precision.postgres.test.ts
111+
scripts/database-failure-classification.postgres.test.ts
111112
112113
- name: Verify OAuth lifecycle and SCIM membership guards in PostgreSQL
113114
working-directory: apps/sim
@@ -133,8 +134,19 @@ jobs:
133134
lib/billing/core/usage-log.postgres.test.ts
134135
lib/billing/core/organization-activity.postgres.test.ts
135136
lib/billing/core/usage-analytics-queries.postgres.test.ts
137+
lib/billing/core/organization-usage-pagination.postgres.test.ts
138+
lib/billing/organizations/member-limits.postgres.test.ts
139+
lib/workspaces/organization-workspaces.postgres.test.ts
136140
lib/billing/calculations/usage-reservation.test.ts
137141
142+
- name: Verify access request flows, pagination, and impact in PostgreSQL
143+
working-directory: apps/sim
144+
env:
145+
ACCESS_REQUESTS_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_access_requests_test
146+
run: |
147+
bun -e 'import postgres from "postgres"; const sql = postgres(process.env.DATABASE_URL); await sql.unsafe("CREATE DATABASE sim_access_requests_test"); await sql.end()'
148+
bunx vitest run ee/access-requests/lib/repository.postgres.test.ts ee/access-requests/lib/impact.postgres.test.ts ee/access-requests/lib/application/flow.postgres.test.ts
149+
138150
- name: Verify fork previews ignore execution file history in PostgreSQL
139151
working-directory: apps/sim
140152
env:
@@ -263,14 +275,23 @@ jobs:
263275
lib/knowledge/__integration__/search-source-pagination.integration.ts
264276
lib/knowledge/__integration__/search-reference-batching.integration.ts
265277
lib/knowledge/__integration__/embedding-insert-batches.integration.ts
278+
lib/knowledge/__integration__/processing-lock-scope.integration.ts
266279
lib/knowledge/__integration__/connector-lifecycle-locks.integration.ts
267280
lib/knowledge/__integration__/connector-deferral.integration.ts
268281
lib/knowledge/__integration__/stored-document-recovery.integration.ts
269282
lib/knowledge/__integration__/connector-partition-work.integration.ts
283+
lib/knowledge/__integration__/user-document-visibility.integration.ts
270284
lib/knowledge/__integration__/listing-continuation.integration.ts
271285
lib/knowledge/__integration__/member-scope-renewal.integration.ts
286+
lib/knowledge/__integration__/member-document-lifecycle.integration.ts
287+
lib/knowledge/__integration__/connector-lease-pages.integration.ts
272288
lib/knowledge/__integration__/slack-empty-threads.integration.ts
273289
lib/knowledge/__integration__/kb-block-search.integration.ts
290+
lib/knowledge/__integration__/gitlab-workspace.integration.ts
291+
lib/knowledge/__integration__/unfilled-projection-source.integration.ts
292+
lib/knowledge/__integration__/knowledge-projection.integration.ts
293+
lib/knowledge/__integration__/async-projection-processing.integration.ts
294+
lib/knowledge/__integration__/purged-detach-reservation.integration.ts
274295
lib/core/outbox/service.integration.ts
275296
lib/knowledge/__integration__/connector-upload.integration.ts
276297
lib/uploads/contexts/organization-logo/application.integration.ts
@@ -293,7 +314,17 @@ jobs:
293314
bunx vitest run --mode integration lib/knowledge/access/group-membership.integration.ts
294315
bunx vitest run \
295316
lib/knowledge/access/predicate.postgres.test.ts \
296-
lib/knowledge/connectors/external-directory.postgres.test.ts
317+
lib/knowledge/connectors/external-directory.postgres.test.ts \
318+
lib/knowledge/connectors/sync-persistence.postgres.test.ts \
319+
lib/knowledge/connectors/sync-content-pass.postgres.test.ts
320+
321+
- name: Verify the projection source and ACL trigger and backfill in PostgreSQL
322+
working-directory: packages/db
323+
env:
324+
KNOWLEDGE_ACL_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_acl_test
325+
run: |
326+
bun -e 'import postgres from "postgres"; const sql = postgres(process.env.DATABASE_URL); const [row] = await sql`SELECT 1 FROM pg_database WHERE datname = ${"sim_acl_test"}`; if (!row) await sql`CREATE DATABASE sim_acl_test`; await sql.end()'
327+
bunx vitest run script-migrations/0021_embedding_search_connector.postgres.test.ts
297328
298329
test-build:
299330
name: Lint and Test

‎apps/desktop/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ Raw local file bytes are never exposed through the preload bridge and cannot be
192192

193193
## Auto-update, channels, rollout, rollback
194194

195-
- `electron-updater` reads the deployment's `/api/desktop/update` feed; production resolves stable releases from `simstudioai/sim`, while dev/staging resolve prereleases from `simstudioai/sim-desktop-releases`. Artifact downloads go directly to GitHub and deltas use `.zip.blockmap`. Sim validates every candidate before starting its download. Developer ID builds installed under `/Applications` use a prompt (Restart and update / Later; Later installs on quit); other packaged builds offer a validated installer download — never forced mid-session.
195+
- `electron-updater` reads the deployment's `/api/desktop/update` feed; production resolves stable releases from `simstudioai/sim`, while dev/staging resolve prereleases from `simstudioai/sim-desktop-releases`. Artifact downloads go directly to GitHub and deltas use `.zip.blockmap`. Sim validates every candidate before starting its download. Developer ID builds installed under `/Applications` use a prompt (Restart and update / Later; Later installs on quit); other packaged builds offer a validated installer download — never forced mid-session. A staged or offered update keeps being re-checked on the normal cadence, and a newer release replaces it, so a shell left running across several releases installs the latest build in one restart instead of the stale one followed by another prompt.
196196
- Streams: production follows stable `X.Y.Z` releases, dev follows `-dev.N`, and staging follows `-staging.N`. The feed still recognizes legacy `-alpha.N`/`-beta.N` releases during migration.
197197
- Staged rollout: after publishing, edit `stagingPercentage: 10` into the release's `latest-mac.yml`, then raise as crash metrics stay clean.
198198
- Rollback: a pulled release must be superseded by a **higher** version — users on the broken build will not reinstall an equal one. (A blocked-versions kill-switch was removed as unwired dead code; reintroduce it in `updater.ts` if a remote config source ever exists to feed it.)

‎apps/desktop/e2e/smoke.spec.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ const PAGES: Record<string, string> = {
2121
'/login': '<!doctype html><html><body><h1 id="login">fixture-login</h1></body></html>',
2222
}
2323

24+
/** `User-Agent` of every request the fixture origin has served, in arrival order. */
25+
const requestUserAgents: string[] = []
26+
2427
function startFixtureServer(): Promise<{ server: Server; origin: string }> {
2528
return new Promise((resolvePromise) => {
2629
const server = createServer((request, response) => {
30+
requestUserAgents.push(request.headers['user-agent'] ?? '')
2731
const path = new URL(request.url ?? '/', 'http://127.0.0.1').pathname
2832
const sessionCookie = request.headers.cookie
2933
?.split(';')
@@ -85,6 +89,21 @@ test.describe('desktop shell smoke', () => {
8589
expect(window.url()).toBe(`${origin}/home`)
8690
})
8791

92+
test('presents one stock Chrome user agent on every request from the first load', async () => {
93+
requestUserAgents.length = 0
94+
app = await launchApp(origin)
95+
const window = await app.firstWindow()
96+
await expect(window.locator('#app')).toHaveText('fixture-app')
97+
await window.evaluate(() => fetch('/home').then((response) => response.text()))
98+
99+
const pageUserAgent = await window.evaluate(() => navigator.userAgent)
100+
expect(pageUserAgent).toMatch(
101+
/^Mozilla\/5\.0 \(.+\) AppleWebKit\/537\.36 \(KHTML, like Gecko\) Chrome\/\d+\.0\.0\.0 Safari\/537\.36$/
102+
)
103+
expect(requestUserAgents.length).toBeGreaterThanOrEqual(2)
104+
expect(new Set(requestUserAgents)).toEqual(new Set([pageUserAgent]))
105+
})
106+
88107
test('internal window.open creates an independent full Sim window', async () => {
89108
app = await launchApp(origin)
90109
const window = await app.firstWindow()

‎apps/desktop/src/main/browser-agent/session.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ interface MockView {
3939
session: {
4040
setPermissionRequestHandler: ReturnType<typeof vi.fn>
4141
setPermissionCheckHandler: ReturnType<typeof vi.fn>
42+
setUserAgent: ReturnType<typeof vi.fn>
4243
webRequest: { onBeforeRequest: ReturnType<typeof vi.fn> }
4344
}
4445
on: ReturnType<typeof vi.fn>
@@ -362,15 +363,14 @@ describe('browser-agent session', () => {
362363
expect(onTabNavigated).toHaveBeenCalledWith(contents, true)
363364
})
364365

365-
it('gives every tab a user agent with no Electron token in it', () => {
366+
it('leaves every tab on the process-wide user agent instead of overriding it', () => {
366367
const first = session.ensureTab()
367368
const second = session.addTab()
368369

369370
for (const tab of [first, second]) {
370371
const contents = (tab.view as unknown as MockView).webContents
371-
const agent = contents.setUserAgent.mock.calls.at(-1)?.[0] as string | undefined
372-
expect(agent).toMatch(/^Mozilla\/5\.0 \(.+\) .*Chrome\/\d+\.0\.0\.0 Safari\/537\.36$/)
373-
expect(agent).not.toMatch(/Electron|Sim\//)
372+
expect(contents.setUserAgent).not.toHaveBeenCalled()
373+
expect(contents.session.setUserAgent).not.toHaveBeenCalled()
374374
}
375375
})
376376

‎apps/desktop/src/main/browser-agent/session.ts‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ import {
6868
} from '@/main/browser-agent/registry'
6969
import { handleBrowserRequest } from '@/main/browser-agent/request-policy'
7070
import { clearHostVerdictCache } from '@/main/browser-agent/url-guard'
71-
import { browserUserAgent } from '@/main/browser-agent/user-agent'
7271
import type { BrowserSessionSnapshot } from '@/main/desktop-chat-session-store'
7372
import { suggestedFilename, uniqueDownloadPath } from '@/main/downloads'
7473
import { isAppOrigin } from '@/main/navigation'
@@ -1432,11 +1431,6 @@ function configureAgentPartition(ses: Session): void {
14321431
configuredPartitions.add(ses)
14331432
ses.setPermissionRequestHandler(browserPermissions.request)
14341433
ses.setPermissionCheckHandler(browserPermissions.check)
1435-
// Service workers do not inherit a tab's user agent. With only the tab's set,
1436-
// the document request carries the browser string while the worker's own
1437-
// script request still announces Electron — and on a site that routes its
1438-
// fetches through a worker, that is the one the server sees.
1439-
ses.setUserAgent(browserUserAgent())
14401434
ses.webRequest.onBeforeRequest((details, callback) => {
14411435
handleBrowserRequest(details, callback)
14421436
})
@@ -1984,10 +1978,6 @@ function initializeTabView(
19841978
}
19851979
}
19861980
registerAgentNavigation(contents, routeNavigation)
1987-
// The session default does not reach a WebContents that already exists, and
1988-
// the first tab is what brings the session into being, so each tab sets its
1989-
// own as well — otherwise tab one browses as Electron and the rest as Chrome.
1990-
contents.setUserAgent(browserUserAgent())
19911981
attachAgentContextMenu(contents, {
19921982
addToChat: (text) => withBrowserScope(scopeId, () => addPageSelectionToChat(contents, text)),
19931983
openTab: (url) => withBrowserScope(scopeId, () => openTabWithUrl(url, { agentOwned: false })),

‎apps/desktop/src/main/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ import { attachTelemetryPolicy } from '@/main/telemetry-policy'
8383
import { TerminalRegistry } from '@/main/terminal/registry'
8484
import { installTray, type TrayHandle } from '@/main/tray'
8585
import { checkForUpdatesInteractive, initUpdater, type UpdaterHandle } from '@/main/updater'
86+
import { installBrowserUserAgent } from '@/main/user-agent'
8687
import { createMainWindow, setupPermissionHandlers } from '@/main/window'
8788
import { attachWindowOpenPolicy, isPopupContents } from '@/main/windows'
8889

@@ -900,6 +901,7 @@ app.setName(APP_NAME_FOR_CHANNEL[channelForOrigin(DEFAULT_ORIGIN)])
900901
if (process.env.SIM_DESKTOP_USER_DATA) {
901902
app.setPath('userData', process.env.SIM_DESKTOP_USER_DATA)
902903
}
904+
installBrowserUserAgent()
903905

904906
// The scheme the offline page and server picker load from must be declared
905907
// before the app is ready; the per-session handlers attach later.

0 commit comments

Comments
 (0)