chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,155 @@
/**
* @vitest-environment node
*/
import { createLogger } from '@sim/logger'
import { describe, expect, it } from 'vitest'
import {
inferContextFromKey,
isAbortError,
isInternalFileUrl,
isNetworkError,
processSingleFileToUserFile,
resolveTrustedFileContext,
} from '@/lib/uploads/utils/file-utils'
const logger = createLogger('FileUtilsTest')
describe('isInternalFileUrl', () => {
it('classifies relative serve paths as internal', () => {
expect(isInternalFileUrl('/api/files/serve/kb/123-file.pdf')).toBe(true)
expect(isInternalFileUrl('/api/files/serve/workspace/ws-1/file.txt?context=workspace')).toBe(
true
)
})
it('classifies absolute serve URLs as internal regardless of host', () => {
expect(isInternalFileUrl('https://www.sim.ai/api/files/serve/kb/x.pdf')).toBe(true)
expect(isInternalFileUrl('http://localhost:3000/api/files/serve/blob/kb/x')).toBe(true)
// Host is not used to gate (self-hosted/multi-domain); the storage sink authorizes.
expect(isInternalFileUrl('https://other-host/api/files/serve/workspace/v/x')).toBe(true)
})
it('does not match the marker outside the path (query/fragment)', () => {
expect(isInternalFileUrl('https://evil.com/x?next=/api/files/serve/secret')).toBe(false)
expect(isInternalFileUrl('https://evil.com/page#/api/files/serve/secret')).toBe(false)
expect(isInternalFileUrl('https://evil.com/redirect?u=/api/files/serve/kb/x')).toBe(false)
})
it('preserves traversal sequences so they survive downstream rejection', () => {
// Must stay internal (not normalized away) so the parse route applies its `..` check.
expect(isInternalFileUrl('https://attacker.com/api/files/serve/../../../etc/passwd')).toBe(true)
expect(isInternalFileUrl('/api/files/serve/../../app.js')).toBe(true)
})
it('returns false for non-internal and non-string inputs', () => {
expect(isInternalFileUrl('https://example.com/file.pdf')).toBe(false)
expect(isInternalFileUrl('data:text/plain;base64,abc')).toBe(false)
// @ts-expect-error verifying runtime guard
expect(isInternalFileUrl(undefined)).toBe(false)
})
})
describe('inferContextFromKey', () => {
it('maps both kb/ and knowledge-base/ prefixes to knowledge-base', () => {
expect(inferContextFromKey('kb/1700000000000-doc.pdf')).toBe('knowledge-base')
// Direct/presigned uploads key as `${context}/...`, i.e. `knowledge-base/...`
expect(inferContextFromKey('knowledge-base/1781612506186-b2442e0dc045cb6c-doc.txt')).toBe(
'knowledge-base'
)
})
it('maps the remaining context prefixes', () => {
expect(inferContextFromKey('chat/x')).toBe('chat')
expect(inferContextFromKey('copilot/x')).toBe('copilot')
expect(inferContextFromKey('execution/ws/wf/ex/x')).toBe('execution')
expect(inferContextFromKey('workspace/ws/x')).toBe('workspace')
expect(inferContextFromKey('profile-pictures/x')).toBe('profile-pictures')
expect(inferContextFromKey('og-images/x')).toBe('og-images')
expect(inferContextFromKey('workspace-logos/x')).toBe('workspace-logos')
expect(inferContextFromKey('logs/x')).toBe('logs')
})
it('throws for empty or unrecognized keys', () => {
expect(() => inferContextFromKey('')).toThrow()
expect(() => inferContextFromKey('mystery/x')).toThrow()
})
})
describe('resolveTrustedFileContext', () => {
it('derives from the key prefix and ignores a mismatched caller context', () => {
expect(resolveTrustedFileContext('workspace/ws/1700000000000-abc-x.pdf', 'og-images')).toBe(
'workspace'
)
expect(resolveTrustedFileContext('chat/x', 'workspace-logos')).toBe('chat')
expect(resolveTrustedFileContext('workspace/ws/x', 'mothership')).toBe('workspace')
})
it('honors the caller context for legacy keys with no inferrable prefix', () => {
expect(resolveTrustedFileContext('legacy/ws/wf/ex/report.pdf', 'execution')).toBe('execution')
})
it('never resolves an un-inferrable key to a world-readable context', () => {
expect(() => resolveTrustedFileContext('legacy/report.pdf', 'og-images')).toThrow()
expect(() => resolveTrustedFileContext('legacy/report.pdf', 'profile-pictures')).toThrow()
expect(() => resolveTrustedFileContext('legacy/report.pdf')).toThrow()
})
})
describe('isAbortError', () => {
it('returns true for AbortError-named errors', () => {
const err = new Error('aborted')
err.name = 'AbortError'
expect(isAbortError(err)).toBe(true)
})
it('returns false for generic Errors', () => {
expect(isAbortError(new Error('boom'))).toBe(false)
expect(isAbortError(null)).toBe(false)
expect(isAbortError('AbortError')).toBe(false)
})
})
describe('isNetworkError', () => {
it.each([
'fetch failed',
'Network request failed',
'connection reset',
'request timeout',
'operation timed out',
'ECONNRESET while reading body',
])('matches transient message %s', (msg) => {
expect(isNetworkError(new Error(msg))).toBe(true)
})
it('does not match deterministic errors', () => {
expect(isNetworkError(new Error('Forbidden'))).toBe(false)
expect(isNetworkError(new Error('Validation failed: name is required'))).toBe(false)
expect(isNetworkError('not an error')).toBe(false)
expect(isNetworkError(null)).toBe(false)
})
})
describe('processSingleFileToUserFile', () => {
it('strips server-only provider file handles from untrusted input', () => {
const result = processSingleFileToUserFile(
{
id: 'file-1',
name: 'doc.pdf',
url: '/api/files/serve/workspace%2Fws-1%2Fdoc.pdf?context=workspace',
size: 1024,
type: 'application/pdf',
key: 'workspace/ws-1/doc.pdf',
providerFileId: 'file-injected',
providerFileUri: 'https://injected/uri',
remoteUrl: 'http://169.254.169.254/latest/meta-data',
} as never,
'req-1',
logger
)
expect(result.providerFileId).toBeUndefined()
expect(result.providerFileUri).toBeUndefined()
expect(result.remoteUrl).toBeUndefined()
expect(result.key).toBe('workspace/ws-1/doc.pdf')
})
})