mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-30 19:32:46 +08:00
chore(flags): remove released feature gates (#7087)
* chore(flags): remove released feature gates * chore(helm): bump chart version
This commit is contained in:
@@ -186,17 +186,11 @@ Once enabled, retention settings are configurable through **Settings → Enterpr
|
||||
|
||||
### PII redaction
|
||||
|
||||
PII redaction runs against a standalone [Presidio](https://microsoft.github.io/presidio/) service. Deploy it (see `apps/pii`) and point Sim at it, then enable the redaction surfaces:
|
||||
PII redaction runs against a standalone [Presidio](https://microsoft.github.io/presidio/) service. Deploy it (see `apps/pii`) and point Sim at it:
|
||||
|
||||
```bash
|
||||
# The Presidio service exposing /analyze and /anonymize
|
||||
PII_URL=http://localhost:5001
|
||||
|
||||
# Expose the log-redaction stage and the Data Retention PII section
|
||||
PII_REDACTION=true
|
||||
|
||||
# Additionally expose the execution-altering stages (Workflow input, Block outputs)
|
||||
PII_GRANULAR_REDACTION=true
|
||||
```
|
||||
|
||||
`PII_GRANULAR_REDACTION` layers on top of `PII_REDACTION` — with only `PII_REDACTION` enabled, just the **Logs** stage is configurable.
|
||||
All PII stages are configurable under **Settings → Enterprise → Data Retention**.
|
||||
|
||||
@@ -179,8 +179,6 @@ See [Observability](/platform/self-hosting/observability).
|
||||
|----------|-------------|
|
||||
| `COPILOT_API_KEY` | API key for Chat. Without it the Sim Chat block, scheduled prompt jobs, and Inbox cannot run |
|
||||
| `NEXT_PUBLIC_CHAT_DISABLED` | Set to `true` to hide the Chat module: the workspace lands on your first workflow, with no chats list, scheduled tasks, or editor Chat panel. Chat is shown when unset; `npx sim-setup` sets it for you if you skip the chat key |
|
||||
| `PII_REDACTION` | Redact PII from workflow logs via Data Retention rules; requires the PII service and a cluster-reachable `INTERNAL_API_BASE_URL` |
|
||||
| `PII_GRANULAR_REDACTION` | Additionally expose the execution-altering redaction stages |
|
||||
| `DURABLE_SECRET_PROVENANCE_ENFORCED_SURFACES` | Durable stores where a value whose secret provenance was never recorded fails the run instead of logging a warning. `all`, or a comma-separated subset of `memory`, `table-row`, `knowledge`. Unset (nothing enforced) by default |
|
||||
| `ADMIN_API_KEY` | Admin API key for GitOps operations and organization provisioning |
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ pii:
|
||||
enabled: true
|
||||
app:
|
||||
env:
|
||||
PII_REDACTION: "true"
|
||||
INTERNAL_API_BASE_URL: "http://sim-app.simstudio.svc.cluster.local:3000"
|
||||
```
|
||||
|
||||
|
||||
@@ -164,7 +164,6 @@ pii:
|
||||
|
||||
app:
|
||||
env:
|
||||
PII_REDACTION: "true"
|
||||
INTERNAL_API_BASE_URL: "http://sim-app.simstudio.svc.cluster.local:3000"
|
||||
```
|
||||
|
||||
|
||||
@@ -2908,11 +2908,11 @@
|
||||
"get": {
|
||||
"operationId": "getApiMeta",
|
||||
"summary": "Get API Capabilities",
|
||||
"description": "Report facts about the calling API key: whether it is in the v2 rollout cohort, whether it is personal or workspace-scoped, and when it expires. Every other v2 endpoint answers 404 both when the path does not exist and when your credential is not in the rollout cohort; call this endpoint to tell the two apart. It is the one v2 endpoint the rollout gate does not apply to, and it still requires a valid key.",
|
||||
"description": "Report whether v2 is available, whether the calling API key is personal or workspace-scoped, and when it expires. Requires a valid key.",
|
||||
"tags": ["Meta"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Rollout and lifecycle facts about the calling key.",
|
||||
"description": "Availability and lifecycle facts about the calling key.",
|
||||
"headers": {
|
||||
"X-RateLimit-Limit": {
|
||||
"$ref": "#/components/headers/X-RateLimit-Limit"
|
||||
@@ -7252,7 +7252,7 @@
|
||||
"properties": {
|
||||
"v2Enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether this credential is in the v2 rollout cohort. When false, every other v2 endpoint answers 404 for this credential."
|
||||
"description": "Whether this API version is available. This is true when the endpoint is served."
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string",
|
||||
@@ -7276,7 +7276,7 @@
|
||||
"required": ["v2Enabled", "keyType", "expiresAt"],
|
||||
"additionalProperties": false,
|
||||
"title": "API capabilities",
|
||||
"description": "Rollout and lifecycle facts about the calling API key."
|
||||
"description": "API availability and lifecycle facts about the calling API key."
|
||||
},
|
||||
"GetApiMetaResponse": {
|
||||
"type": "object",
|
||||
@@ -7289,7 +7289,7 @@
|
||||
"required": ["data"],
|
||||
"additionalProperties": false,
|
||||
"title": "API capabilities response",
|
||||
"description": "Rollout cohort, key type, and expiry for the calling key.",
|
||||
"description": "API availability, key type, and expiry for the calling key.",
|
||||
"examples": [
|
||||
{
|
||||
"data": {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { getCustomBlockManageContext } from '@/lib/workflows/custom-blocks/operations'
|
||||
import { hasWorkspaceAdminAccess } from '@/lib/workspaces/permissions/utils'
|
||||
|
||||
@@ -19,12 +18,6 @@ export async function authorizeManage(
|
||||
const ctx = await getCustomBlockManageContext(id)
|
||||
if (!ctx) return { error: NextResponse.json({ error: 'Not found' }, { status: 404 }), ctx: null }
|
||||
|
||||
if (!(await isFeatureEnabled('deploy-as-block', { userId, orgId: ctx.organizationId }))) {
|
||||
return {
|
||||
error: NextResponse.json({ error: 'Deploy as block is not enabled' }, { status: 403 }),
|
||||
ctx: null,
|
||||
}
|
||||
}
|
||||
if (!ctx.sourceWorkspaceId || !(await hasWorkspaceAdminAccess(userId, ctx.sourceWorkspaceId))) {
|
||||
return {
|
||||
error: NextResponse.json({ error: 'Admin permissions required' }, { status: 403 }),
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
import { authMockFns, createMockRequest } from '@sim/testing'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { mockIsFeatureEnabled, mockHasWorkspaceAdminAccess, mockOperations } = vi.hoisted(() => ({
|
||||
mockIsFeatureEnabled: vi.fn(),
|
||||
const { mockHasWorkspaceAdminAccess, mockOperations } = vi.hoisted(() => ({
|
||||
mockHasWorkspaceAdminAccess: vi.fn(),
|
||||
mockOperations: {
|
||||
getCustomBlockManageContext: vi.fn(),
|
||||
@@ -13,10 +12,6 @@ const { mockIsFeatureEnabled, mockHasWorkspaceAdminAccess, mockOperations } = vi
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/core/config/feature-flags', () => ({
|
||||
isFeatureEnabled: mockIsFeatureEnabled,
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/workspaces/permissions/utils', () => ({
|
||||
hasWorkspaceAdminAccess: mockHasWorkspaceAdminAccess,
|
||||
}))
|
||||
@@ -44,7 +39,6 @@ describe('GET /api/custom-blocks/[id]/usages', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockGetSession.mockResolvedValue({ user: { id: 'user-1' } })
|
||||
mockIsFeatureEnabled.mockResolvedValue(true)
|
||||
mockHasWorkspaceAdminAccess.mockResolvedValue(true)
|
||||
mockOperations.getCustomBlockManageContext.mockResolvedValue(MANAGE_CONTEXT)
|
||||
mockOperations.getCustomBlockUsageCounts.mockResolvedValue(USAGE_COUNTS)
|
||||
@@ -62,12 +56,6 @@ describe('GET /api/custom-blocks/[id]/usages', () => {
|
||||
expect(response.status).toBe(404)
|
||||
})
|
||||
|
||||
it('returns 403 when the feature flag is off', async () => {
|
||||
mockIsFeatureEnabled.mockResolvedValue(false)
|
||||
const response = await callRoute()
|
||||
expect(response.status).toBe(403)
|
||||
})
|
||||
|
||||
it('returns 403 for a non-admin of the source workspace', async () => {
|
||||
mockHasWorkspaceAdminAccess.mockResolvedValue(false)
|
||||
const response = await callRoute()
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import { parseRequest } from '@/lib/api/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { isOrganizationOnEnterprisePlan } from '@/lib/billing'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import {
|
||||
CustomBlockValidationError,
|
||||
@@ -64,10 +63,6 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
|
||||
return NextResponse.json({ enabled: false, customBlocks: [] })
|
||||
}
|
||||
|
||||
if (!(await isFeatureEnabled('deploy-as-block', { userId, orgId: organizationId }))) {
|
||||
return NextResponse.json({ enabled: false, customBlocks: [] })
|
||||
}
|
||||
|
||||
const enabled = await isOrganizationOnEnterprisePlan(organizationId)
|
||||
const blocks = enabled ? await listCustomBlocksWithInputs(organizationId) : []
|
||||
return NextResponse.json({ enabled, customBlocks: blocks.map(toWire) })
|
||||
@@ -107,10 +102,6 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (!(await isFeatureEnabled('deploy-as-block', { userId, orgId: organizationId }))) {
|
||||
return NextResponse.json({ error: 'Deploy as block is not enabled' }, { status: 403 })
|
||||
}
|
||||
|
||||
if (!(await isOrganizationOnEnterprisePlan(organizationId))) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Deploy as block requires an enterprise plan' },
|
||||
|
||||
@@ -13,12 +13,8 @@ import { parseRequest, validationErrorResponse } from '@/lib/api/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { CLEANUP_CONFIG } from '@/lib/billing/cleanup-dispatcher'
|
||||
import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription'
|
||||
import {
|
||||
getForeignWorkspaceTargetsReason,
|
||||
getPiiRedactionDenialReason,
|
||||
} from '@/lib/billing/retention'
|
||||
import { getForeignWorkspaceTargetsReason } from '@/lib/billing/retention'
|
||||
import { isBillingEnabled } from '@/lib/core/config/env-flags'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { coercePiiLanguage } from '@/lib/guardrails/pii-entities'
|
||||
|
||||
@@ -107,10 +103,6 @@ export const GET = withRouteHandler(
|
||||
}
|
||||
|
||||
const isEnterprise = !isBillingEnabled || (await isOrganizationOnEnterprisePlan(organizationId))
|
||||
const [piiRedactionEnabled, piiGranularRedactionEnabled] = await Promise.all([
|
||||
isFeatureEnabled('pii-redaction'),
|
||||
isFeatureEnabled('pii-granular-redaction'),
|
||||
])
|
||||
const configured = normalizeConfigured(org.dataRetentionSettings)
|
||||
const defaults = enterpriseDefaults()
|
||||
|
||||
@@ -121,8 +113,6 @@ export const GET = withRouteHandler(
|
||||
defaults,
|
||||
configured,
|
||||
effective: isEnterprise ? configured : defaults,
|
||||
piiRedactionEnabled,
|
||||
piiGranularRedactionEnabled,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -191,11 +181,6 @@ export const PUT = withRouteHandler(
|
||||
return NextResponse.json({ error: 'Organization not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
const [piiRedactionEnabled, piiGranularRedactionEnabled] = await Promise.all([
|
||||
isFeatureEnabled('pii-redaction'),
|
||||
isFeatureEnabled('pii-granular-redaction'),
|
||||
])
|
||||
|
||||
const current = normalizeConfigured(currentOrg.dataRetentionSettings)
|
||||
const merged: DataRetentionSettings = { ...current }
|
||||
if (body.logRetentionHours !== undefined) {
|
||||
@@ -208,15 +193,6 @@ export const PUT = withRouteHandler(
|
||||
merged.taskCleanupHours = body.taskCleanupHours
|
||||
}
|
||||
if (body.piiRedaction !== undefined) {
|
||||
const denialReason = getPiiRedactionDenialReason({
|
||||
current: current.piiRedaction,
|
||||
incoming: body.piiRedaction,
|
||||
piiRedactionEnabled,
|
||||
piiGranularRedactionEnabled,
|
||||
})
|
||||
if (denialReason) {
|
||||
return NextResponse.json({ error: denialReason }, { status: 403 })
|
||||
}
|
||||
merged.piiRedaction = body.piiRedaction
|
||||
}
|
||||
if (body.retentionOverrides !== undefined) {
|
||||
@@ -266,8 +242,6 @@ export const PUT = withRouteHandler(
|
||||
defaults,
|
||||
configured,
|
||||
effective: configured,
|
||||
piiRedactionEnabled,
|
||||
piiGranularRedactionEnabled,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,23 +7,16 @@ import { z } from 'zod'
|
||||
import { defineRouteContract } from '@/lib/api/contracts'
|
||||
import { recordRateLimitSnapshot } from '@/lib/api/server/rate-limit-context'
|
||||
|
||||
const {
|
||||
mockCheckRateLimit,
|
||||
mockGate,
|
||||
mockHandler,
|
||||
mockLoggerError,
|
||||
mockLoggerInfo,
|
||||
requestContextState,
|
||||
} = vi.hoisted(() => ({
|
||||
mockCheckRateLimit: vi.fn(),
|
||||
mockGate: vi.fn(),
|
||||
mockHandler: vi.fn(),
|
||||
mockLoggerError: vi.fn(),
|
||||
mockLoggerInfo: vi.fn(),
|
||||
requestContextState: {
|
||||
current: undefined as { requestId: string; method?: string; path?: string } | undefined,
|
||||
},
|
||||
}))
|
||||
const { mockCheckRateLimit, mockHandler, mockLoggerError, mockLoggerInfo, requestContextState } =
|
||||
vi.hoisted(() => ({
|
||||
mockCheckRateLimit: vi.fn(),
|
||||
mockHandler: vi.fn(),
|
||||
mockLoggerError: vi.fn(),
|
||||
mockLoggerInfo: vi.fn(),
|
||||
requestContextState: {
|
||||
current: undefined as { requestId: string; method?: string; path?: string } | undefined,
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@sim/logger', () => ({
|
||||
createLogger: () => ({
|
||||
@@ -55,10 +48,6 @@ vi.mock('@/app/api/v1/middleware', () => ({
|
||||
checkRateLimit: mockCheckRateLimit,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({
|
||||
v2ApiGateError: mockGate,
|
||||
}))
|
||||
|
||||
import { withPublicApiRouteHandler } from '@/app/api/public-api-route-handler'
|
||||
|
||||
const RATE_LIMIT = {
|
||||
@@ -132,7 +121,6 @@ function listRequest(query = 'workspaceId=workspace-1'): NextRequest {
|
||||
describe('withPublicApiRouteHandler', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockGate.mockResolvedValue(null)
|
||||
mockCheckRateLimit.mockImplementation(async (request: NextRequest) => {
|
||||
recordRateLimitSnapshot(request, RATE_LIMIT)
|
||||
return RATE_LIMIT
|
||||
@@ -165,7 +153,6 @@ describe('withPublicApiRouteHandler', () => {
|
||||
expect(request.bodyUsed).toBe(false)
|
||||
expect(mockHandler).not.toHaveBeenCalled()
|
||||
expect(mockCheckRateLimit).toHaveBeenCalledWith(request, 'table-rows')
|
||||
expect(mockGate).not.toHaveBeenCalled()
|
||||
if (status === 401) {
|
||||
expect(response.headers.get('X-RateLimit-Limit')).toBe('0')
|
||||
} else {
|
||||
@@ -174,25 +161,12 @@ describe('withPublicApiRouteHandler', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('checks the v2 rollout gate before reading or parsing the body', async () => {
|
||||
mockGate.mockResolvedValue(NextResponse.json({ error: 'Not found' }, { status: 404 }))
|
||||
const request = postRequest('{not valid json')
|
||||
|
||||
const response = await POST(request, { params: { itemId: 'item-1' } })
|
||||
|
||||
expect(response.status).toBe(404)
|
||||
expect(request.bodyUsed).toBe(false)
|
||||
expect(mockGate).toHaveBeenCalledWith('user-1')
|
||||
expect(mockHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('fails fast when an allowed rate-limit result has no user ID', async () => {
|
||||
mockCheckRateLimit.mockResolvedValue({ ...RATE_LIMIT, userId: undefined })
|
||||
|
||||
const response = await GET(listRequest())
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(mockGate).not.toHaveBeenCalled()
|
||||
expect(mockHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { type ParsedRequest, type ParseRequestOptions, parseRequest } from '@/li
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { type ApiEndpoint, type AuthorizedRequest, checkRateLimit } from '@/app/api/v1/middleware'
|
||||
import { v2ApiGateError } from '@/app/api/v2/lib/gate'
|
||||
import { v2Error, v2RateLimitError, v2ValidationError } from '@/app/api/v2/lib/response'
|
||||
|
||||
interface PublicApiRouteContext {
|
||||
@@ -55,8 +54,6 @@ export function withPublicApiRouteHandler<C extends AnyApiRouteContract>({
|
||||
throw new Error('Allowed public API request is missing a user ID')
|
||||
}
|
||||
const userId = rateLimit.userId
|
||||
const gate = await v2ApiGateError(userId)
|
||||
if (gate) return gate
|
||||
|
||||
const parsed = await parseRequest(contract, request, context ?? {}, {
|
||||
validationErrorResponse: v2ValidationError,
|
||||
|
||||
@@ -42,7 +42,6 @@ vi.mock('@/lib/table/service', () => ({
|
||||
}))
|
||||
vi.mock('@/lib/table/billing', () => ({ getWorkspaceTableLimits: mockGetLimits }))
|
||||
vi.mock('@/lib/folders/queries', () => ({ findActiveFolder: mockFindActiveFolder }))
|
||||
vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: vi.fn() }))
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: vi.fn() }))
|
||||
vi.mock('@/lib/workspaces/permissions/utils', () => ({
|
||||
getWorkspaceWithOwner: vi.fn(),
|
||||
|
||||
@@ -4,7 +4,6 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getTableQuerySchema, updateTableContract } from '@/lib/api/contracts/tables'
|
||||
import { isZodError, parseRequest, validationErrorResponse } from '@/lib/api/server/validation'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { findActiveFolder } from '@/lib/folders/queries'
|
||||
@@ -17,9 +16,7 @@ import {
|
||||
performRenameTable,
|
||||
performUpdateTableLocks,
|
||||
} from '@/lib/table/orchestration'
|
||||
import { TABLE_LOCK_FLAGS, TABLE_LOCK_KINDS } from '@/lib/table/types'
|
||||
import { normalizeColumn } from '@/lib/table/wire'
|
||||
import { getWorkspaceWithOwner } from '@/lib/workspaces/permissions/utils'
|
||||
import {
|
||||
accessError,
|
||||
checkAccess,
|
||||
@@ -146,32 +143,6 @@ export const PATCH = withRouteHandler(
|
||||
}
|
||||
|
||||
if (validated.locks !== undefined) {
|
||||
// With the flag off you may still CLEAR locks — otherwise flipping the
|
||||
// kill switch would strand an already-locked table with no way to
|
||||
// unlock it, while enforcement of those stored locks keeps running.
|
||||
// Only a lock actually transitioning off→on needs the feature enabled;
|
||||
// comparing against the stored state (rather than "every value is
|
||||
// false") is what lets the settings UI, which always submits the full
|
||||
// four-flag draft, clear one lock while another stays on.
|
||||
const enablesALock = TABLE_LOCK_KINDS.some((kind) => {
|
||||
const flag = TABLE_LOCK_FLAGS[kind]
|
||||
return validated.locks?.[flag] === true && !table.locks[flag]
|
||||
})
|
||||
if (enablesALock) {
|
||||
// Resolve with the same context the page uses to decide whether to
|
||||
// show the panel — keyed on the workspace's host organization, not
|
||||
// the viewer's active one. Without it an org- or user-targeted
|
||||
// rollout would open the panel and then 403 on save. Looked up only
|
||||
// on the enabling path, so an unlock never pays for it.
|
||||
const workspace = await getWorkspaceWithOwner(table.workspaceId)
|
||||
const enabled = await isFeatureEnabled('table-locks', {
|
||||
userId: authResult.userId,
|
||||
orgId: workspace?.organizationId ?? undefined,
|
||||
})
|
||||
if (!enabled) {
|
||||
return NextResponse.json({ error: 'Table locks are not enabled' }, { status: 403 })
|
||||
}
|
||||
}
|
||||
const adminResult = await checkAccess(tableId, authResult.userId, 'admin')
|
||||
if (!adminResult.ok) {
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -23,18 +23,13 @@ import { createLogger } from '@sim/logger'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { adminV1UpdateOrganizationDataRetentionContract } from '@/lib/api/contracts/v1/admin'
|
||||
import { parseRequest } from '@/lib/api/server'
|
||||
import {
|
||||
getForeignWorkspaceTargetsReason,
|
||||
getPiiRedactionDenialReason,
|
||||
} from '@/lib/billing/retention'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { getForeignWorkspaceTargetsReason } from '@/lib/billing/retention'
|
||||
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { withAdminAuthParams } from '@/app/api/v1/admin/middleware'
|
||||
import {
|
||||
adminInvalidJsonResponse,
|
||||
adminValidationErrorResponse,
|
||||
badRequestResponse,
|
||||
forbiddenResponse,
|
||||
internalErrorResponse,
|
||||
notFoundResponse,
|
||||
singleResponse,
|
||||
@@ -84,24 +79,6 @@ export const PATCH = withRouteHandler(
|
||||
if (body.taskCleanupHours !== undefined) merged.taskCleanupHours = body.taskCleanupHours
|
||||
|
||||
if (body.piiRedaction !== undefined) {
|
||||
/**
|
||||
* The same gate the settings UI applies. An admin key authenticates an
|
||||
* operator, not an entitlement — without this check it would be a way
|
||||
* to switch on PII redaction that the product does not offer this
|
||||
* organization.
|
||||
*/
|
||||
const [piiRedactionEnabled, piiGranularRedactionEnabled] = await Promise.all([
|
||||
isFeatureEnabled('pii-redaction'),
|
||||
isFeatureEnabled('pii-granular-redaction'),
|
||||
])
|
||||
const denialReason = getPiiRedactionDenialReason({
|
||||
current: existing.dataRetentionSettings?.piiRedaction,
|
||||
incoming: body.piiRedaction,
|
||||
piiRedactionEnabled,
|
||||
piiGranularRedactionEnabled,
|
||||
})
|
||||
if (denialReason) return forbiddenResponse(denialReason)
|
||||
|
||||
merged.piiRedaction = body.piiRedaction
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ import { DELETE, GET, PATCH, POST, PUT } from '@/app/api/v2/[[...segments]]/rout
|
||||
* `not-found` page, so a mistyped URL handed an API client a full HTML document
|
||||
* — the one v2 response a JSON-parsing caller cannot read.
|
||||
*
|
||||
* The body must stay byte-identical to the rollout gate's 404
|
||||
* (`v2ApiGateError`), which answers 404 so an ungated caller cannot tell "not in
|
||||
* the cohort" from "no such endpoint". A different body here would give that
|
||||
* distinction straight back.
|
||||
* The body must stay in the canonical v2 error envelope.
|
||||
*/
|
||||
describe('unknown /api/v2 path', () => {
|
||||
const EXPECTED = { error: { code: 'NOT_FOUND', message: 'Not found' } }
|
||||
|
||||
@@ -9,13 +9,8 @@ export const revalidate = 0
|
||||
*
|
||||
* Without it a mistyped path falls through to the app's global `not-found`
|
||||
* page and hands an API client a full HTML document, which is the one v2
|
||||
* response a JSON-parsing caller cannot read. Every other v2 failure — including
|
||||
* the rollout gate's own 404 — is the `{ error: { code, message } }` envelope.
|
||||
*
|
||||
* The body is deliberately byte-identical to `v2ApiGateError`'s. The gate
|
||||
* answers 404 so an ungated caller cannot distinguish "not in the rollout
|
||||
* cohort" from "no such endpoint"; a different body here would reintroduce
|
||||
* exactly that distinction.
|
||||
* response a JSON-parsing caller cannot read. This route keeps unknown paths in
|
||||
* the canonical `{ error: { code, message } }` envelope.
|
||||
*
|
||||
* This is a documented raw-`withRouteHandler` route rather than a contract
|
||||
* builder: it has no contract, no operation, and no authentication, because a
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/audit-logs/application/list-audit-logs', () => ({
|
||||
listAuditLogs: { operation: { id: 'audit_logs.list' }, execute: mocks.list },
|
||||
@@ -36,7 +34,6 @@ import { GET as listLogs } from '@/app/api/v2/audit-logs/route'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'admin-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'admin-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:admin-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -62,7 +59,6 @@ describe('v2 audit-log routes', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({ data: [log], nextCursor: 'next-1' })
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/billing/application/list-billing-logs', () => ({
|
||||
listBillingLogs: { operation: { id: 'billing.logs.list' }, execute: mocks.execute },
|
||||
@@ -41,7 +39,6 @@ function ledgerCursor(
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -53,7 +50,6 @@ describe('GET /api/v2/billing/logs', () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date('2026-08-01T00:00:00Z'))
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/billing/application/get-billing-status', () => ({
|
||||
getBillingStatus: { operation: { id: 'billing.status.read' }, execute: mocks.execute },
|
||||
@@ -32,7 +30,6 @@ import { GET } from '@/app/api/v2/billing/status/route'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: 'workspace-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'workspace:workspace-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -50,7 +47,6 @@ describe('GET /api/v2/billing/status', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue(result)
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -16,7 +15,6 @@ const mocks = vi.hoisted(() => ({ list: vi.fn(), read: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/catalog/application/list-blocks', () => ({
|
||||
listCatalogBlocks: { operation: { id: 'catalog.blocks.list' }, execute: mocks.list },
|
||||
}))
|
||||
@@ -35,7 +33,6 @@ const WORKSPACE_ID = '11111111-2222-4333-8444-555555555555'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -106,7 +103,6 @@ describe('/api/v2/blocks', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({ entries: [summary], hasMore: false, offset: 0, limit: 50 })
|
||||
@@ -203,7 +199,6 @@ describe('/api/v2/blocks/[blockId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.read.mockResolvedValue({ block: detail })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -73,7 +72,6 @@ vi.mock('@/ee/access-control/utils/permission-check', () => {
|
||||
})
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
import { GET } from '@/app/api/v2/chat-deployments/route'
|
||||
|
||||
@@ -82,7 +80,6 @@ const WORKFLOW_ID = 'workflow-1'
|
||||
|
||||
const personalKeyAuth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'personal-key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:personal-key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -94,7 +91,6 @@ const workspaceKeyAuth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'workspace-key-1',
|
||||
},
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:workspace-key-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -141,7 +137,6 @@ describe('/api/v2/chat-deployments', () => {
|
||||
vi.clearAllMocks()
|
||||
resetDbChainMock()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(personalKeyAuth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.resolvePermission.mockResolvedValue('admin')
|
||||
|
||||
@@ -52,10 +52,6 @@ vi.mock('@/lib/core/rate-limiter', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({
|
||||
v2ApiGateError: vi.fn().mockResolvedValue(null),
|
||||
}))
|
||||
|
||||
vi.mock('@sim/utils/id', () => ({
|
||||
generateId: mockGenerateId,
|
||||
generateShortId: vi.fn(() => 'mock-short-id'),
|
||||
@@ -110,7 +106,6 @@ import { POST } from '@/app/api/v2/chat/route'
|
||||
|
||||
const personalAuth = {
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -16,7 +15,6 @@ const mocks = vi.hoisted(() => ({ connectorTypes: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/catalog/application/list-connector-types', () => ({
|
||||
listCatalogConnectorTypes: {
|
||||
operation: { id: 'catalog.connector_types.list' },
|
||||
@@ -31,7 +29,6 @@ const WORKSPACE_ID = '11111111-2222-4333-8444-555555555555'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -65,7 +62,6 @@ describe('/api/v2/connector-types', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.connectorTypes.mockResolvedValue({ connectorTypes: [connectorType] })
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,8 +18,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/credentials/application/service-account', () => ({
|
||||
deleteCredentialUseCase: {
|
||||
operation: { id: 'credentials.delete' },
|
||||
@@ -59,7 +56,6 @@ const CREDENTIAL_ID = '7c9e6679-7425-40de-944b-e07fc1f90ae7'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -95,7 +91,6 @@ describe('PATCH /api/v2/credentials/[credentialId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.update.mockResolvedValue({
|
||||
@@ -242,7 +237,6 @@ describe('DELETE /api/v2/credentials/[credentialId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.remove.mockResolvedValue({ credential, deleted: true })
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -16,7 +15,6 @@ const mocks = vi.hoisted(() => ({ execute: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/credentials/application/create-credential-connection', () => ({
|
||||
createCredentialConnection: {
|
||||
operation: { id: 'credentials.connections.create' },
|
||||
@@ -29,7 +27,6 @@ import { POST } from '@/app/api/v2/credentials/connections/route'
|
||||
const WORKSPACE_ID = '11111111-2222-4333-8444-555555555555'
|
||||
const auth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -39,7 +36,6 @@ describe('POST /api/v2/credentials/connections', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -16,7 +15,6 @@ const mocks = vi.hoisted(() => ({ execute: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/credentials/application/list-credential-providers', () => ({
|
||||
listCredentialProviders: {
|
||||
operation: { id: 'credentials.providers.list' },
|
||||
@@ -33,7 +31,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -80,7 +77,6 @@ describe('GET /api/v2/credentials/providers', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({ providers })
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/credentials/application/list-workspace-credentials', () => ({
|
||||
listWorkspaceCredentials: {
|
||||
@@ -46,7 +44,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -72,7 +69,6 @@ describe('GET /api/v2/credentials', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({
|
||||
@@ -229,10 +225,8 @@ describe('POST /api/v2/credentials', () => {
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
...auth,
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
keyType: 'personal',
|
||||
})
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.create.mockResolvedValue({
|
||||
|
||||
@@ -15,7 +15,6 @@ const { mocks, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
get: vi.fn(),
|
||||
update: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
@@ -47,7 +46,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/custom-tools/application/use-cases', () => ({
|
||||
getWorkspaceCustomToolUseCase: { operation: { id: 'custom_tools.read' }, execute: mocks.get },
|
||||
updateWorkspaceCustomToolUseCase: {
|
||||
@@ -66,7 +64,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['workspace:workspace-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -117,7 +114,6 @@ describe('/api/v2/custom-tools/[customToolId]', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.get.mockResolvedValue({ tool })
|
||||
mocks.update.mockResolvedValue({ tool })
|
||||
mocks.remove.mockResolvedValue({ tool })
|
||||
|
||||
@@ -29,7 +29,6 @@ const { mocks, log, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
@@ -82,7 +81,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/custom-tools/application/use-cases', () => ({
|
||||
listWorkspaceCustomToolsUseCase: {
|
||||
operation: { id: 'custom_tools.list' },
|
||||
@@ -102,7 +100,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['workspace:workspace-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -149,7 +146,6 @@ describe('/api/v2/custom-tools', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.list.mockResolvedValue({ tools: [tool] })
|
||||
mocks.create.mockResolvedValue({ tool })
|
||||
})
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -33,7 +32,6 @@ vi.mock('@/lib/workspace-files/application/update-workspace-file-content', () =>
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/users/queries', () => ({
|
||||
getUserEmailsByIds: mocks.getUserEmailsByIds,
|
||||
@@ -52,7 +50,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -88,7 +85,6 @@ describe('PUT /api/v2/files/[fileId]/content', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.admit.mockResolvedValue(undefined)
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -27,7 +26,6 @@ vi.mock('@/lib/workspace-files/application/read-workspace-file-metadata', () =>
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/users/queries', () => ({
|
||||
getUserEmailsByIds: mocks.getUserEmailsByIds,
|
||||
@@ -43,7 +41,6 @@ const FILE_ID = 'wf_1'
|
||||
const context = { params: Promise.resolve({ fileId: FILE_ID }) }
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -93,7 +90,6 @@ describe('GET /api/v2/files/[fileId]/metadata', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.readMetadata.mockResolvedValue({ file: buildRecord(), share: SHARE })
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -27,7 +26,6 @@ vi.mock('@/lib/workspace-files/application/restore-workspace-file', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/users/queries', () => ({
|
||||
getUserEmailsByIds: mocks.getUserEmailsByIds,
|
||||
@@ -46,7 +44,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -85,7 +82,6 @@ describe('POST /api/v2/files/[fileId]/restore', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.restoreFile.mockResolvedValue({ restored: true, file: RESTORED_FILE })
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -45,7 +44,6 @@ vi.mock('@/lib/workspace-files/application/delete-workspace-file', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/users/queries', () => ({
|
||||
getUserEmailsByIds: mocks.getUserEmailsByIds,
|
||||
@@ -68,7 +66,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -101,7 +98,6 @@ describe('v2 single-file routes', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.download.mockResolvedValue({
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
@@ -45,14 +43,12 @@ vi.mock('@/lib/workspace-files/application/share-workspace-file', () => ({
|
||||
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
import { GET, PATCH } from '@/app/api/v2/files/[fileId]/share/route'
|
||||
import { v2Error } from '@/app/api/v2/lib/response'
|
||||
|
||||
const WORKSPACE_ID = 'workspace-1'
|
||||
const FILE_ID = 'wf_1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -103,7 +99,6 @@ describe('GET /api/v2/files/[fileId]/share', () => {
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
mocks.getShare.mockResolvedValue({ share: SHARE })
|
||||
})
|
||||
|
||||
@@ -119,15 +114,6 @@ describe('GET /api/v2/files/[fileId]/share', () => {
|
||||
expect(v2RouteMocks.operationRate).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('returns 404 when the v2 API surface flag is off', async () => {
|
||||
v2RouteMocks.gate.mockResolvedValueOnce(v2Error('NOT_FOUND', 'Not found'))
|
||||
|
||||
const response = await callGet()
|
||||
|
||||
expect(response.status).toBe(404)
|
||||
expect(mocks.getShare).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('validates the asserted workspace before executing the use case', async () => {
|
||||
const response = await callGet('')
|
||||
|
||||
@@ -174,7 +160,6 @@ describe('PATCH /api/v2/files/[fileId]/share', () => {
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
mocks.updateShare.mockResolvedValue({ share: SHARE })
|
||||
})
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ vi.mock('@/lib/workspace-files/application/read-workspace-file-text', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
import { NoWorkspaceAccessError } from '@/lib/core/application'
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
@@ -39,7 +37,6 @@ const context = { params: Promise.resolve({ fileId: FILE_ID }) }
|
||||
|
||||
const AUTH = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -67,7 +64,6 @@ describe('GET /api/v2/files/[fileId]/text', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.readText.mockResolvedValue(result())
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ vi.mock('@/lib/workspace-files/application/extract-workspace-file', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
import { NoWorkspaceAccessError } from '@/lib/core/application'
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
@@ -38,7 +36,6 @@ const context = { params: Promise.resolve({ fileId: FILE_ID }) }
|
||||
|
||||
const AUTH = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -56,7 +53,6 @@ describe('POST /api/v2/files/[fileId]/unzip', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.extract.mockResolvedValue({
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const { mockExecute } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -37,12 +35,10 @@ vi.mock('@/lib/workspace-files/application/archive-workspace-file-items', () =>
|
||||
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
import { POST } from '@/app/api/v2/files/bulk-delete/route'
|
||||
import { v2Error } from '@/app/api/v2/lib/response'
|
||||
|
||||
const WS = 'workspace-1'
|
||||
const AUTH = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WS, keyId: 'key-1' },
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WS}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -68,19 +64,11 @@ describe('POST /api/v2/files/bulk-delete', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mockExecute.mockResolvedValue({ deletedItems: { files: 3, folders: 0 } })
|
||||
})
|
||||
|
||||
it('returns 404 when the v2 API surface flag is off', async () => {
|
||||
v2RouteMocks.gate.mockResolvedValueOnce(v2Error('NOT_FOUND', 'Not found'))
|
||||
const res = await callDelete({ workspaceId: WS, fileIds: ['wf_1'] })
|
||||
expect(res.status).toBe(404)
|
||||
expect(mockExecute).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('400s when the selection is empty', async () => {
|
||||
const res = await callDelete({ workspaceId: WS, fileIds: [] })
|
||||
expect(res.status).toBe(400)
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -33,7 +32,6 @@ vi.mock('@/lib/uploads/core/storage-service', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
import { Readable } from 'node:stream'
|
||||
import { NoWorkspaceAccessError } from '@/lib/core/application'
|
||||
@@ -46,7 +44,6 @@ const context = { params: Promise.resolve({}) }
|
||||
|
||||
const AUTH = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -74,7 +71,6 @@ describe('GET /api/v2/files/bulk-download', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.authorizeDownload.mockResolvedValue(undefined)
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ vi.mock('@/lib/workspace-files/application/workspace-file-folders', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
import { NoWorkspaceAccessError } from '@/lib/core/application'
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
@@ -36,7 +34,6 @@ const WORKSPACE_ID = '6fc7631d-88cd-46f8-9f0a-d4764daef7f8'
|
||||
|
||||
const AUTH = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -56,7 +53,6 @@ describe('POST /api/v2/files/folders/restore', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.restore.mockResolvedValue({
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -22,7 +21,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -60,7 +58,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -94,7 +91,6 @@ describe('/api/v2/files/folders', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.listFolders.mockResolvedValue({ folders: [folder] })
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const { mockExecute } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -38,12 +36,10 @@ vi.mock('@/lib/workspace-files/application/move-workspace-file-items', () => ({
|
||||
import { OrchestrationError } from '@/lib/core/orchestration/types'
|
||||
import { WorkspaceFileMoveConflictError } from '@/lib/uploads/contexts/workspace/workspace-file-folder-manager'
|
||||
import { POST } from '@/app/api/v2/files/move/route'
|
||||
import { v2Error } from '@/app/api/v2/lib/response'
|
||||
|
||||
const WS = 'workspace-1'
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WS, keyId: 'key-1' },
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WS}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -69,7 +65,6 @@ describe('POST /api/v2/files/move', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mockExecute.mockResolvedValue({ movedItems: { files: 2, folders: 0 } })
|
||||
@@ -82,13 +77,6 @@ describe('POST /api/v2/files/move', () => {
|
||||
expect((await res.json()).error.code).toBe('UNAUTHORIZED')
|
||||
})
|
||||
|
||||
it('returns 404 when the v2 API surface flag is off', async () => {
|
||||
v2RouteMocks.gate.mockResolvedValueOnce(v2Error('NOT_FOUND', 'Not found'))
|
||||
const res = await callMove({ workspaceId: WS, fileIds: ['wf_1'] })
|
||||
expect(res.status).toBe(404)
|
||||
expect(mockExecute).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('400s when the selection is empty', async () => {
|
||||
const res = await callMove({ workspaceId: WS })
|
||||
expect(res.status).toBe(400)
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -35,7 +34,6 @@ vi.mock('@/lib/workspace-files/application/list-workspace-files', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/users/queries', () => ({
|
||||
getUserEmailsByIds: mocks.getUserEmailsByIds,
|
||||
@@ -52,7 +50,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -84,7 +81,6 @@ describe('/api/v2/files', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.queryFiles.mockResolvedValue({
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -31,7 +30,6 @@ vi.mock('@/lib/uploads/upload-session/application', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/app/api/v2/files/uploads/utils', () => ({
|
||||
toV2FileUpload: vi.fn(async () => ({
|
||||
@@ -62,7 +60,6 @@ const AUTH = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -86,7 +83,6 @@ describe('GET /api/v2/files/uploads/[uploadId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.read.mockResolvedValue({ id: UPLOAD_ID })
|
||||
@@ -172,7 +168,6 @@ describe('DELETE /api/v2/files/uploads/[uploadId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.abort.mockResolvedValue({ id: UPLOAD_ID })
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ vi.mock('@/lib/uploads/upload-session/application', () => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/app/api/v2/files/uploads/utils', () => ({
|
||||
toV2FileUpload: vi.fn(async () => ({
|
||||
@@ -51,7 +49,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -81,7 +78,6 @@ describe('POST /api/v2/files/uploads', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.createUpload.mockResolvedValue(UPLOAD_SESSION)
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -28,7 +27,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/knowledge/api/internal-route', () => ({
|
||||
internalKnowledgeAnalytics: {
|
||||
connectorAdded: mocks.connectorAdded,
|
||||
@@ -92,7 +90,6 @@ const CONNECTOR_ID = 'connector-1'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -144,7 +141,6 @@ describe('v2 knowledge connector routes', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({
|
||||
|
||||
-4
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const { mockReadChunk, mockUpdateChunk, mockDeleteChunk } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/chunks', () => ({
|
||||
readKnowledgeChunk: { operation: { id: 'knowledge.chunks.read' }, execute: mockReadChunk },
|
||||
@@ -78,10 +76,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
-4
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const { mockListChunks, mockCreateChunk, mockBulkChunks } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/chunks', () => ({
|
||||
listKnowledgeChunks: { operation: { id: 'knowledge.chunks.list' }, execute: mockListChunks },
|
||||
@@ -84,10 +82,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const { mockReadDocument, mockUpdateDocument, mockDeleteDocument, mockCapture }
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/documents', () => ({
|
||||
readKnowledgeDocument: {
|
||||
@@ -117,10 +115,8 @@ describe('/api/v2/knowledge/[knowledgeBaseId]/documents/[documentId]', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const { mockListDocuments, mockBulkUpdate } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/documents', () => ({
|
||||
listKnowledgeDocuments: {
|
||||
@@ -99,10 +97,8 @@ function buildPatchRequest(body: unknown) {
|
||||
function authenticateAsPersonalKey() {
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
-4
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const { mockAddWorkspaceFiles } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/add-workspace-files', () => ({
|
||||
addWorkspaceFilesToKnowledgeBase: {
|
||||
@@ -46,10 +44,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -36,7 +35,6 @@ const {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/documents', () => ({
|
||||
listKnowledgeDocuments: {
|
||||
@@ -93,12 +91,10 @@ describe('POST /api/v2/knowledge/[knowledgeBaseId]/documents', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
mockIsPayloadSizeLimitError.mockReturnValue(false)
|
||||
mockIsMultipartFieldValidationError.mockReturnValue(false)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
@@ -198,7 +194,6 @@ describe('POST /api/v2/knowledge/[knowledgeBaseId]/documents', () => {
|
||||
it('does not create human analytics for a workspace key', async () => {
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'workspace_api_key', workspaceId: WORKSPACE_ID, keyId: 'key-2' },
|
||||
rolloutUserId: 'billing-owner',
|
||||
rateLimitSubjectIds: ['api-key:key-2', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace',
|
||||
@@ -381,10 +376,8 @@ describe('GET /api/v2/knowledge/[knowledgeBaseId]/documents', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
-4
@@ -10,7 +10,6 @@ const mocks = vi.hoisted(() => ({
|
||||
checkRateLimitDirect: vi.fn(),
|
||||
checkRateLimitDirectOrThrow: vi.fn(),
|
||||
completeUpload: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
platformEvent: vi.fn(),
|
||||
}))
|
||||
|
||||
@@ -42,7 +41,6 @@ vi.mock('@/lib/core/telemetry', () => ({
|
||||
PlatformEvents: { knowledgeBaseDocumentsUploaded: mocks.platformEvent },
|
||||
}))
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: mocks.captureServerEvent }))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/app/api/v2/knowledge/[knowledgeBaseId]/documents/uploads/utils', () => ({
|
||||
toV2KnowledgeDocumentUpload: (_session: unknown, document: { id: string } | null) => ({
|
||||
id: 'upload-1',
|
||||
@@ -97,7 +95,6 @@ const RESULT = {
|
||||
function auth(principal: Record<string, unknown>) {
|
||||
return {
|
||||
principal,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType:
|
||||
@@ -124,7 +121,6 @@ describe('POST knowledge-document upload completion', () => {
|
||||
mocks.authenticateV2ApiKey.mockResolvedValue(
|
||||
auth({ kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' })
|
||||
)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.checkRateLimitDirect.mockResolvedValue({
|
||||
allowed: true,
|
||||
remaining: 599,
|
||||
|
||||
@@ -11,7 +11,6 @@ const mocks = vi.hoisted(() => ({
|
||||
checkRateLimitDirectOrThrow: vi.fn(),
|
||||
complete: vi.fn(),
|
||||
create: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
parts: vi.fn(),
|
||||
}))
|
||||
|
||||
@@ -52,7 +51,6 @@ vi.mock('@/lib/core/rate-limiter', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: vi.fn() }))
|
||||
|
||||
import {
|
||||
@@ -152,12 +150,10 @@ describe('v2 knowledge upload resource concealment', () => {
|
||||
vi.clearAllMocks()
|
||||
mocks.authenticateV2ApiKey.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
})
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
for (const limiter of [mocks.checkRateLimitDirect, mocks.checkRateLimitDirectOrThrow]) {
|
||||
limiter.mockResolvedValue({
|
||||
allowed: true,
|
||||
|
||||
-4
@@ -9,7 +9,6 @@ const mocks = vi.hoisted(() => ({
|
||||
cancel: vi.fn(),
|
||||
checkRateLimitDirect: vi.fn(),
|
||||
checkRateLimitDirectOrThrow: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
parts: vi.fn(),
|
||||
}))
|
||||
|
||||
@@ -45,7 +44,6 @@ vi.mock('@/lib/core/rate-limiter', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/app/api/v2/knowledge/[knowledgeBaseId]/documents/uploads/utils', () => ({
|
||||
toV2KnowledgeDocumentUpload: () => ({
|
||||
id: 'upload-1',
|
||||
@@ -83,12 +81,10 @@ describe('v2 knowledge-document upload control routes', () => {
|
||||
vi.clearAllMocks()
|
||||
mocks.authenticateV2ApiKey.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
})
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.checkRateLimitDirect.mockResolvedValue({
|
||||
allowed: true,
|
||||
remaining: 599,
|
||||
|
||||
@@ -9,7 +9,6 @@ const mocks = vi.hoisted(() => ({
|
||||
checkRateLimitDirect: vi.fn(),
|
||||
checkRateLimitDirectOrThrow: vi.fn(),
|
||||
createUpload: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/knowledge/application/upload-sessions', () => ({
|
||||
@@ -36,8 +35,6 @@ vi.mock('@/lib/core/rate-limiter', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
|
||||
vi.mock('@/app/api/v2/knowledge/[knowledgeBaseId]/documents/uploads/utils', () => ({
|
||||
toV2KnowledgeDocumentUpload: (session: Record<string, unknown>) => ({
|
||||
id: session.id,
|
||||
@@ -62,7 +59,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -99,7 +95,6 @@ describe('POST /api/v2/knowledge/[knowledgeBaseId]/documents/uploads', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mocks.authenticateV2ApiKey.mockResolvedValue(AUTH)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.checkRateLimitDirect.mockResolvedValue({
|
||||
allowed: true,
|
||||
remaining: 599,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const { mockRestore, mockGetUserEmails } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/knowledge-bases', () => ({
|
||||
restoreKnowledgeBase: { operation: { id: 'knowledge.restore' }, execute: mockRestore },
|
||||
@@ -71,10 +69,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -19,7 +18,6 @@ const { mockUpdateTag, mockDeleteTag } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/tags', () => ({
|
||||
updateKnowledgeTag: { operation: { id: 'knowledge.tags.update' }, execute: mockUpdateTag },
|
||||
@@ -36,10 +34,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const { mockReadNextSlot } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/tags', () => ({
|
||||
readNextKnowledgeTagSlot: {
|
||||
@@ -42,10 +40,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -21,7 +20,6 @@ const { mockListTags, mockCreateTag, mockBulkSave, mockDeleteDefinitions } = vi.
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/tags', () => ({
|
||||
listKnowledgeTags: { operation: { id: 'knowledge.tags.list' }, execute: mockListTags },
|
||||
@@ -63,10 +61,8 @@ describe('GET /api/v2/knowledge/[knowledgeBaseId]/tags', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'billing-owner',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace',
|
||||
@@ -136,10 +132,8 @@ describe('POST /api/v2/knowledge/[knowledgeBaseId]/tags', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
@@ -233,10 +227,8 @@ describe('PUT /api/v2/knowledge/[knowledgeBaseId]/tags', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
@@ -326,10 +318,8 @@ describe('DELETE /api/v2/knowledge/[knowledgeBaseId]/tags', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const { mockReadUsage } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/tags', () => ({
|
||||
readKnowledgeTagUsage: {
|
||||
@@ -42,10 +40,8 @@ beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
|
||||
@@ -42,8 +42,6 @@ vi.mock('@/lib/core/rate-limiter', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: vi.fn().mockResolvedValue(null) }))
|
||||
|
||||
vi.mock('@/lib/knowledge/application/knowledge-bases', () => ({
|
||||
listKnowledgeBases: { operation: { id: 'knowledge.list' }, execute: mockList },
|
||||
createKnowledgeBase: { operation: { id: 'knowledge.create' }, execute: mockCreate },
|
||||
@@ -100,7 +98,6 @@ describe('/api/v2/knowledge route composition', () => {
|
||||
mockCheckRateLimit.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mockAuthenticate.mockResolvedValue({
|
||||
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal',
|
||||
@@ -380,7 +377,6 @@ describe('/api/v2/knowledge route composition', () => {
|
||||
it('does not attribute workspace-key creation analytics to a billing owner', async () => {
|
||||
mockAuthenticate.mockResolvedValue({
|
||||
principal: { kind: 'workspace_api_key', workspaceId: WORKSPACE_ID, keyId: 'key-2' },
|
||||
rolloutUserId: 'billing-owner',
|
||||
rateLimitSubjectIds: ['api-key:key-2', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace',
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const { mockSearch } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/knowledge/application/search', () => ({
|
||||
searchKnowledge: { operation: { id: 'knowledge.search' }, execute: mockSearch },
|
||||
@@ -43,10 +41,8 @@ describe('POST /api/v2/knowledge/search', () => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.authenticate.mockResolvedValue({
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'billing-owner',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace',
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { NextResponse } from 'next/server'
|
||||
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { v2Error } from '@/app/api/v2/lib/response'
|
||||
|
||||
/**
|
||||
* Rollout gate for the entire `/api/v2` surface.
|
||||
*
|
||||
* Exactly one check per request, placed immediately after the route
|
||||
* authenticates and before it does any work. When the flag is off the route
|
||||
* answers 404 as if it did not exist, so an ungated caller cannot distinguish
|
||||
* "not in the rollout cohort" from "no such endpoint".
|
||||
*
|
||||
* Deliberately keyed on a server-resolved user rollout subject, never a
|
||||
* caller-supplied workspace. Personal keys use their authenticated user;
|
||||
* workspace keys use the canonical workspace billing owner as rollout-only
|
||||
* context. That billing owner is not an authorization principal.
|
||||
*/
|
||||
export async function v2ApiGateError(userId: string): Promise<NextResponse | null> {
|
||||
if (await isFeatureEnabled('v2-api', { userId })) return null
|
||||
return v2Error('NOT_FOUND', 'Not found')
|
||||
}
|
||||
@@ -48,8 +48,8 @@ const PRIVATE_NO_STORE = { 'Cache-Control': 'private, no-store' } as const
|
||||
* improvement on the baseline rather than a conformance fix: without it a
|
||||
* client's only defensible policy on a 503 is an immediate retry, which is
|
||||
* exactly the traffic a degraded dependency cannot absorb. Sim raises 503 when
|
||||
* the API-key store, the rollout gate, the rate-limit backend, or
|
||||
* execution-identity allocation is briefly unavailable, and all four are made
|
||||
* the API-key store, the rate-limit backend, or execution-identity allocation
|
||||
* is briefly unavailable, and all three are made
|
||||
* worse by an unthrottled retry storm.
|
||||
*
|
||||
* 429 is deliberately absent because every 429 already knows its own wait: the
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/logs/application/get-public-log', () => ({
|
||||
getPublicLog: { operation: { id: 'logs.read_detail' }, execute: mocks.execute },
|
||||
@@ -33,7 +31,6 @@ const auth = {
|
||||
workspaceId: 'workspace-1',
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'workspace:workspace-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -66,7 +63,6 @@ describe('GET /api/v2/logs/[runId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/logs/application/list-public-logs', () => ({
|
||||
listPublicLogs: { operation: { id: 'logs.list' }, execute: mocks.execute },
|
||||
@@ -37,7 +35,6 @@ const auth = {
|
||||
workspaceId: WORKSPACE_ID,
|
||||
keyId: 'key-1',
|
||||
},
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -64,7 +61,6 @@ describe('GET /api/v2/logs', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -16,7 +15,6 @@ const mocks = vi.hoisted(() => ({ execute: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/logs/application/get-log-stats', () => ({
|
||||
getLogStats: { operation: { id: 'logs.read_stats' }, execute: mocks.execute },
|
||||
@@ -28,7 +26,6 @@ import { GET } from '@/app/api/v2/logs/stats/route'
|
||||
const WORKSPACE_ID = '6fc7631d-88cd-46f8-9f0a-d4764daef7f8'
|
||||
const auth = {
|
||||
principal: { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' },
|
||||
rolloutUserId: 'billing-owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -70,7 +67,6 @@ describe('GET /api/v2/logs/stats', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.execute.mockResolvedValue({ stats, workflowsTruncated: false })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -27,7 +26,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -50,7 +48,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -106,7 +103,6 @@ describe('/api/v2/mcp-servers/[mcpServerId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.get.mockResolvedValue({ server })
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -51,7 +49,6 @@ const SERVER_ID = 'mcp-3f7a9c21'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -81,7 +78,6 @@ describe('/api/v2/mcp-servers/[mcpServerId]/tools', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.discover.mockResolvedValue({ tools: [TOOL] })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -22,7 +21,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/api/server/rate-limit-context', () => ({
|
||||
recordRateLimitSnapshot: vi.fn(),
|
||||
getRateLimitHeaders: vi.fn().mockReturnValue(null),
|
||||
@@ -45,7 +43,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -93,7 +90,6 @@ describe('/api/v2/mcp-servers', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({
|
||||
|
||||
@@ -6,11 +6,10 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { NextRequest } from 'next/server'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
@@ -19,7 +18,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
|
||||
vi.mock('@/lib/api/application/read-v2-api-capabilities', () => ({
|
||||
readV2ApiCapabilities: {
|
||||
@@ -32,7 +30,6 @@ import { GET } from '@/app/api/v2/meta/route'
|
||||
|
||||
const auth = {
|
||||
principal: { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' },
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', 'user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -49,7 +46,6 @@ describe('GET /api/v2/meta', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.read.mockResolvedValue({
|
||||
@@ -74,34 +70,16 @@ describe('GET /api/v2/meta', () => {
|
||||
})
|
||||
|
||||
it('reports a key with no expiry as null', async () => {
|
||||
mocks.read.mockResolvedValue({ v2Enabled: false, keyType: 'workspace', expiresAt: null })
|
||||
mocks.read.mockResolvedValue({ v2Enabled: true, keyType: 'workspace', expiresAt: null })
|
||||
|
||||
const response = await GET(request())
|
||||
|
||||
await expect(response.json()).resolves.toEqual({
|
||||
data: { v2Enabled: false, keyType: 'workspace', expiresAt: null },
|
||||
data: { v2Enabled: true, keyType: 'workspace', expiresAt: null },
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* The whole point of the endpoint: a caller outside the rollout cohort gets an
|
||||
* answer here rather than the same 404 every other v2 route hands it. A change
|
||||
* that routes this through the default gated path fails here.
|
||||
*/
|
||||
it('answers while the rollout gate would refuse, without consulting it', async () => {
|
||||
v2RouteMocks.gate.mockResolvedValue(
|
||||
NextResponse.json({ error: { code: 'NOT_FOUND', message: 'Not found' } }, { status: 404 })
|
||||
)
|
||||
mocks.read.mockResolvedValue({ v2Enabled: false, keyType: 'personal', expiresAt: null })
|
||||
|
||||
const response = await GET(request())
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
expect(v2RouteMocks.gate).not.toHaveBeenCalled()
|
||||
await expect(response.json()).resolves.toMatchObject({ data: { v2Enabled: false } })
|
||||
})
|
||||
|
||||
it('is exempt from the gate but never from authentication', async () => {
|
||||
it('requires authentication', async () => {
|
||||
v2RouteMocks.authenticate.mockRejectedValue(
|
||||
new MockV2ApiKeyUnauthenticatedError('API key required')
|
||||
)
|
||||
@@ -120,12 +98,6 @@ describe('GET /api/v2/meta', () => {
|
||||
expect(mocks.read).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
/**
|
||||
* The rollout subject and the key's expiry both come from the row
|
||||
* `authenticateV2ApiKey` already read and validated. Passing them as input is
|
||||
* what keeps the application layer out of the `api_key` table and off a
|
||||
* second billing-owner lookup.
|
||||
*/
|
||||
it('passes the credential facts the authenticator resolved, not a re-read', async () => {
|
||||
const authenticated = request()
|
||||
await GET(authenticated)
|
||||
@@ -133,7 +105,6 @@ describe('GET /api/v2/meta', () => {
|
||||
expect(mocks.read).toHaveBeenCalledWith({
|
||||
principal: auth.principal,
|
||||
input: {
|
||||
rolloutUserId: 'user-1',
|
||||
keyType: 'personal',
|
||||
expiresAt: new Date('2027-01-01T00:00:00.000Z'),
|
||||
},
|
||||
|
||||
@@ -11,32 +11,14 @@ import {
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const revalidate = 0
|
||||
|
||||
/**
|
||||
* GET /api/v2/meta — Report the calling key's rollout cohort and lifecycle.
|
||||
*
|
||||
* The only route in `/api/v2` that is exempt from the rollout gate, and the
|
||||
* exemption is the point: every other endpoint answers a 404 that is
|
||||
* byte-identical to the unknown-path catch-all's, so a caller outside the cohort
|
||||
* cannot tell "not in the rollout" from "no such endpoint" and has nothing to
|
||||
* act on. Gating this endpoint too would give it the same ambiguity and leave
|
||||
* the question permanently unanswerable.
|
||||
*
|
||||
* Exempting it does not weaken that concealment. Authentication still runs
|
||||
* first, so the only fact disclosed is one about the caller's own credential,
|
||||
* disclosed to a caller who has already proved it holds that credential. It is
|
||||
* not a cross-tenant signal, not a resource-existence signal, and says nothing
|
||||
* about any other account. A request with no key, or a key for another account,
|
||||
* learns nothing it did not already hold.
|
||||
*/
|
||||
/** GET /api/v2/meta — Report the calling key's API availability and lifecycle. */
|
||||
export const GET = defineV2JsonRoute({
|
||||
contract: v2GetMetaContract,
|
||||
auth: v2ApiKeyAuth,
|
||||
operation: v2MetaOperations.read,
|
||||
gate: 'exempt',
|
||||
rateLimit: v2RateLimits.publicApi,
|
||||
errorPolicy: v2OrchestrationErrorPolicy,
|
||||
mapInput: (_request, credential) => ({
|
||||
rolloutUserId: credential.rolloutUserId,
|
||||
keyType: credential.keyType,
|
||||
expiresAt: credential.keyExpiresAt,
|
||||
}),
|
||||
|
||||
@@ -11,7 +11,6 @@ const { mocks, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
set: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
},
|
||||
@@ -42,7 +41,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/secrets/application/use-cases', () => ({
|
||||
setSecretUseCase: { operation: { id: 'secrets.set' }, execute: mocks.set },
|
||||
deleteSecretUseCase: { operation: { id: 'secrets.delete' }, execute: mocks.remove },
|
||||
@@ -56,7 +54,6 @@ const SECRET_NAME = 'STRIPE_API_KEY'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-personal' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -111,7 +108,6 @@ describe('/api/v2/secrets/[name]', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.set.mockResolvedValue({ secret, userId: 'user-1', created: true })
|
||||
mocks.remove.mockResolvedValue({ name: SECRET_NAME, scope: 'workspace' })
|
||||
})
|
||||
|
||||
@@ -11,7 +11,6 @@ const { mocks, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
list: vi.fn(),
|
||||
},
|
||||
MockV2ApiKeyUnauthenticatedError,
|
||||
@@ -41,7 +40,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/secrets/application/use-cases', () => ({
|
||||
listSecretsUseCase: { operation: { id: 'secrets.list' }, execute: mocks.list },
|
||||
}))
|
||||
@@ -54,7 +52,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-personal' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -90,7 +87,6 @@ describe('GET /api/v2/secrets', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.list.mockResolvedValue({
|
||||
secrets: [secret],
|
||||
values: {},
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -21,7 +20,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: mocks.capture }))
|
||||
vi.mock('@/lib/skills/application/use-cases', () => ({
|
||||
listSkillEditorsUseCase: {
|
||||
@@ -45,7 +43,6 @@ const SKILL_ID = 'skill-1'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -81,7 +78,6 @@ describe('/api/v2/skills/[skillId]/editors', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({
|
||||
|
||||
@@ -15,7 +15,6 @@ const { mocks, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
get: vi.fn(),
|
||||
update: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
@@ -48,7 +47,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: mocks.capture }))
|
||||
vi.mock('@/lib/skills/application/use-cases', () => ({
|
||||
getSkillUseCase: { operation: { id: 'skills.read' }, execute: mocks.get },
|
||||
@@ -62,7 +60,6 @@ const WORKSPACE_ID = 'workspace-1'
|
||||
const PRINCIPAL = { kind: 'personal_api_key' as const, userId: 'user-1', keyId: 'key-personal' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'user-1',
|
||||
rateLimitSubjectIds: ['user:user-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'personal' as const,
|
||||
@@ -110,7 +107,6 @@ describe('/api/v2/skills/[skillId]', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.get.mockResolvedValue({ skill })
|
||||
mocks.update.mockResolvedValue({ skill })
|
||||
mocks.remove.mockResolvedValue({ skill })
|
||||
|
||||
@@ -11,7 +11,6 @@ const { mocks, MockV2ApiKeyUnauthenticatedError } = vi.hoisted(() => {
|
||||
authenticate: vi.fn(),
|
||||
preauthRate: vi.fn(),
|
||||
operationRate: vi.fn(),
|
||||
gate: vi.fn(),
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
capture: vi.fn(),
|
||||
@@ -43,7 +42,6 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
generateRequestId: vi.fn().mockReturnValue('request-1'),
|
||||
getClientIp: vi.fn().mockReturnValue('127.0.0.1'),
|
||||
}))
|
||||
vi.mock('@/app/api/v2/lib/gate', () => ({ v2ApiGateError: mocks.gate }))
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: mocks.capture }))
|
||||
vi.mock('@/lib/skills/application/use-cases', () => ({
|
||||
listSkillsUseCase: { operation: { id: 'skills.list' }, execute: mocks.list },
|
||||
@@ -83,7 +81,6 @@ function skillCursor({
|
||||
const PRINCIPAL = { kind: 'workspace_api_key' as const, workspaceId: WORKSPACE_ID, keyId: 'key-1' }
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['workspace:workspace-1'] as const,
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -123,7 +120,6 @@ describe('/api/v2/skills', () => {
|
||||
mocks.authenticate.mockResolvedValue(AUTH)
|
||||
mocks.preauthRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.operationRate.mockResolvedValue(RATE_LIMIT_OK)
|
||||
mocks.gate.mockResolvedValue(null)
|
||||
mocks.list.mockResolvedValue({ skills: [skill], hasMore: false, offset: 0, limit: 50 })
|
||||
mocks.create.mockResolvedValue({ skill })
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
}))
|
||||
@@ -44,7 +42,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -66,7 +63,6 @@ describe('POST /api/v2/tables/[tableId]/cancel-runs', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.cancelRuns.mockResolvedValue({ table: { id: 'table-1' }, cancelled: 4 })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -22,7 +21,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/columns', () => ({
|
||||
addTableColumnUseCase: { operation: { id: 'tables.columns.add' }, execute: mocks.add },
|
||||
updateTableColumnUseCase: { operation: { id: 'tables.columns.update' }, execute: mocks.update },
|
||||
@@ -40,7 +38,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -68,7 +65,6 @@ describe('/api/v2/tables/[tableId]/columns', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.add.mockResolvedValue({ table })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({ readDispatch: vi.fn(), cancelDispatch: vi.fn()
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/runs', () => ({
|
||||
readTableDispatch: { operation: { id: 'tables.runs.read' }, execute: mocks.readDispatch },
|
||||
cancelTableDispatch: { operation: { id: 'tables.runs.cancel' }, execute: mocks.cancelDispatch },
|
||||
@@ -35,7 +33,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -90,7 +87,6 @@ describe('GET /api/v2/tables/[tableId]/dispatches/[dispatchId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.readDispatch.mockResolvedValue({ dispatch: dispatch('dispatching') })
|
||||
@@ -167,7 +163,6 @@ describe('DELETE /api/v2/tables/[tableId]/dispatches/[dispatchId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.cancelDispatch.mockResolvedValue({ dispatch: dispatch('cancelled') })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -24,7 +23,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
}))
|
||||
@@ -43,7 +41,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -81,7 +78,6 @@ describe('GET /api/v2/tables/[tableId]/dispatches', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.listDispatches.mockResolvedValue({ table: { id: 'table-1' }, dispatches: [DISPATCH] })
|
||||
@@ -132,7 +128,6 @@ describe('POST /api/v2/tables/[tableId]/dispatches', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.startRun.mockResolvedValue({ table: { id: 'table-1' }, dispatchId: 'dispatch-1' })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -22,7 +21,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/app/api/v2/tables/presenters', () => ({
|
||||
presentV2TableExport: (tableExport: unknown) => ({ data: tableExport }),
|
||||
}))
|
||||
@@ -49,7 +47,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -71,7 +68,6 @@ describe('v2 table exports', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/groups', () => ({
|
||||
listTableGroupsUseCase: { operation: { id: 'tables.groups.list' }, execute: mocks.list },
|
||||
createTableGroupUseCase: { operation: { id: 'tables.groups.create' }, execute: mocks.create },
|
||||
@@ -42,7 +40,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -84,7 +81,6 @@ describe('/api/v2/tables/[tableId]/groups', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({ table, groups: [group] })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -33,7 +32,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
queryTableRows: { operation: { id: 'tables.rows.query' }, execute: mocks.queryRows },
|
||||
@@ -49,7 +47,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -82,7 +79,6 @@ describe('POST /api/v2/tables/[tableId]/query/count', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.queryRows.mockResolvedValue({
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -33,7 +32,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
queryTableRows: { operation: { id: 'tables.rows.query' }, execute: mocks.queryRows },
|
||||
@@ -57,7 +55,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -90,7 +87,6 @@ describe('POST /api/v2/tables/[tableId]/query', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.queryRows.mockResolvedValue({ table: TABLE, rows: [ROW], nextCursor: null })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -22,7 +21,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/tables', () => ({
|
||||
restoreTableUseCase: { operation: { id: 'tables.restore' }, execute: mocks.restore },
|
||||
}))
|
||||
@@ -44,7 +42,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -86,7 +83,6 @@ describe('POST /api/v2/tables/[tableId]/restore', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.getUserEmailsByIds.mockResolvedValue(new Map([['owner-1', 'owner@example.com']]))
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -25,7 +24,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/posthog/server', () => ({ captureServerEvent: mocks.capture }))
|
||||
vi.mock('@/lib/table/application/tables', () => ({
|
||||
readTableUseCase: { operation: { id: 'tables.read' }, execute: mocks.read },
|
||||
@@ -52,7 +50,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -98,7 +95,6 @@ describe('/api/v2/tables/[tableId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.getUserEmailsByIds.mockResolvedValue(new Map([['owner-1', 'owner@example.com']]))
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -27,7 +26,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
readTableRowEnrichmentDetail: {
|
||||
@@ -50,7 +48,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -77,7 +74,6 @@ describe('POST /api/v2/tables/[tableId]/rows/[rowId]/enrichment/[groupId]', () =
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.startRun.mockResolvedValue({ table: { id: 'table-1' }, dispatchId: 'dispatch-1' })
|
||||
@@ -174,7 +170,6 @@ describe('GET /api/v2/tables/[tableId]/rows/[rowId]/enrichment/[groupId]', () =>
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.readEnrichment.mockResolvedValue({ table: { id: 'table-1' }, detail: DETAIL })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -28,7 +27,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
readTableRow: { operation: { id: 'tables.rows.read' }, execute: mocks.readRow },
|
||||
@@ -48,7 +46,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -84,7 +81,6 @@ describe('/api/v2/tables/[tableId]/rows/[rowId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.readRow.mockResolvedValue({ table: TABLE, row: ROW })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -21,7 +20,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
batchUpdateTableRows: {
|
||||
@@ -40,7 +38,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -62,7 +59,6 @@ describe('POST /api/v2/tables/[tableId]/rows/bulk-update', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.batchUpdate.mockResolvedValue({
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -29,7 +28,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
listTableRows: { operation: { id: 'tables.rows.list' }, execute: mocks.listRows },
|
||||
@@ -60,7 +58,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -93,7 +90,6 @@ describe('/api/v2/tables/[tableId]/rows', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.listRows.mockResolvedValue({ table: TABLE, rows: [ROW], nextCursor: null })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,13 +25,11 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
searchTableRows: { operation: { id: 'tables.rows.search' }, execute: mocks.searchRows },
|
||||
}))
|
||||
|
||||
import { v2Error } from '@/app/api/v2/lib/response'
|
||||
import { POST } from '@/app/api/v2/tables/[tableId]/rows/search/route'
|
||||
|
||||
const WORKSPACE_ID = 'workspace-1'
|
||||
@@ -43,7 +40,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -70,7 +66,6 @@ describe('POST /api/v2/tables/[tableId]/rows/search', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.searchRows.mockResolvedValue({
|
||||
@@ -114,15 +109,6 @@ describe('POST /api/v2/tables/[tableId]/rows/search', () => {
|
||||
expect(mocks.searchRows).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('stops at the rollout gate before the shared use case', async () => {
|
||||
v2RouteMocks.gate.mockResolvedValue(v2Error('NOT_FOUND', 'Not found'))
|
||||
|
||||
const response = await call({ workspaceId: WORKSPACE_ID, q: 'ada' }).response
|
||||
|
||||
expect(response.status).toBe(404)
|
||||
expect(mocks.searchRows).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('rejects an unauthenticated request', async () => {
|
||||
v2RouteMocks.authenticate.mockRejectedValueOnce(new MockV2ApiKeyUnauthenticatedError())
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -26,7 +25,6 @@ const { mocks, MockTableRowsValidationError } = vi.hoisted(() => {
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/rows', () => ({
|
||||
TableRowsValidationError: MockTableRowsValidationError,
|
||||
upsertTableRow: { operation: { id: 'tables.rows.upsert' }, execute: mocks.upsertRow },
|
||||
@@ -42,7 +40,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -63,7 +60,6 @@ describe('POST /api/v2/tables/[tableId]/rows/upsert', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.upsertRow.mockResolvedValue({ table: TABLE, row: ROW, operation: 'update' })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/views', () => ({
|
||||
readTableViewUseCase: { operation: { id: 'tables.views.read' }, execute: mocks.read },
|
||||
updateTableViewUseCase: { operation: { id: 'tables.views.update' }, execute: mocks.update },
|
||||
@@ -41,7 +39,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -81,7 +78,6 @@ describe('/api/v2/tables/[tableId]/views/[viewId]', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.read.mockResolvedValue({ view, columns })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/views', () => ({
|
||||
listTableViewsUseCase: { operation: { id: 'tables.views.list' }, execute: mocks.list },
|
||||
createTableViewUseCase: { operation: { id: 'tables.views.create' }, execute: mocks.create },
|
||||
@@ -44,7 +42,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -66,7 +63,6 @@ describe('/api/v2/tables/[tableId]/views', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({ views: [view], columns })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({ restore: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/folders', () => ({
|
||||
restoreTableFolderUseCase: {
|
||||
operation: { id: 'tables.folders.restore' },
|
||||
@@ -37,7 +35,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -81,7 +78,6 @@ describe('POST /api/v2/tables/folders/restore', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.restore.mockResolvedValue(restored('Reports', '/Reports'))
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -23,7 +22,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/folders', () => ({
|
||||
listTableFoldersUseCase: { operation: { id: 'tables.folders.list' }, execute: mocks.list },
|
||||
createTableFolderUseCase: { operation: { id: 'tables.folders.create' }, execute: mocks.create },
|
||||
@@ -41,7 +39,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -76,7 +73,6 @@ describe('/api/v2/tables/folders', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.list.mockResolvedValue({ folders: [folder], index })
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/app/api/v2/tables/presenters', () => ({
|
||||
presentV2TableImport: (tableImport: unknown) => ({ data: tableImport }),
|
||||
}))
|
||||
@@ -41,7 +39,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -51,7 +48,6 @@ describe('POST /api/v2/tables/imports/[importId]/complete', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -20,7 +19,6 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/app/api/v2/tables/presenters', () => ({
|
||||
presentV2CreateTableImport: (tableImport: unknown) => ({ data: tableImport }),
|
||||
}))
|
||||
@@ -38,7 +36,6 @@ const principal = {
|
||||
}
|
||||
const auth = {
|
||||
principal,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -49,7 +46,6 @@ describe('POST /api/v2/tables/imports', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(auth)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
V2_OPERATION_RATE_LIMIT_ALLOWED,
|
||||
V2_PREAUTH_RATE_LIMIT_ALLOWED,
|
||||
v2ApiKeyAuthModuleMock,
|
||||
v2GateModuleMock,
|
||||
v2RateLimiterModuleMock,
|
||||
v2RouteMocks,
|
||||
} from '@sim/testing'
|
||||
@@ -18,7 +17,6 @@ const mocks = vi.hoisted(() => ({ move: vi.fn(), remove: vi.fn() }))
|
||||
|
||||
vi.mock('@/lib/api/server/routes/v2-api-key-auth', () => v2ApiKeyAuthModuleMock)
|
||||
vi.mock('@/lib/core/rate-limiter', () => v2RateLimiterModuleMock)
|
||||
vi.mock('@/app/api/v2/lib/gate', () => v2GateModuleMock)
|
||||
vi.mock('@/lib/table/application/bulk', () => ({
|
||||
bulkMoveTables: { operation: { id: 'tables.bulk_move' }, execute: mocks.move },
|
||||
bulkDeleteTables: { operation: { id: 'tables.bulk_delete' }, execute: mocks.remove },
|
||||
@@ -36,7 +34,6 @@ const PRINCIPAL = {
|
||||
}
|
||||
const AUTH = {
|
||||
principal: PRINCIPAL,
|
||||
rolloutUserId: 'owner-1',
|
||||
rateLimitSubjectIds: ['api-key:key-1', `workspace:${WORKSPACE_ID}`],
|
||||
rateLimitSubscription: null,
|
||||
keyType: 'workspace' as const,
|
||||
@@ -56,7 +53,6 @@ describe('POST /api/v2/tables/move', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.move.mockResolvedValue({
|
||||
@@ -161,7 +157,6 @@ describe('POST /api/v2/tables/bulk-delete', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
v2RouteMocks.authenticate.mockResolvedValue(AUTH)
|
||||
v2RouteMocks.gate.mockResolvedValue(null)
|
||||
v2RouteMocks.preauthRate.mockResolvedValue(V2_PREAUTH_RATE_LIMIT_ALLOWED)
|
||||
v2RouteMocks.operationRate.mockResolvedValue(V2_OPERATION_RATE_LIMIT_ALLOWED)
|
||||
mocks.remove.mockResolvedValue({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user