@@ -0,0 +1,193 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// Actual app caller and native readiness protocol over a synthetic transport; no live service proof.
|
||||
|
||||
import { loadAppEnv, platformClients } from "@app/config"
|
||||
import { type Actor, buildRegistry, Container, createCaller } from "@conusai-kit/core"
|
||||
import { createMemoryDataSource, DATA_SOURCE, entitiesOf, SYSTEM_DATA } from "@conusai-kit/data"
|
||||
import { SUPPORT_PLATFORM, SUPPORT_PROCESSING_STATUS, supportModule } from "@conusai-kit/support"
|
||||
import { createTenancyHooks, orgMemberships, TENANCY, tenancyModule, users } from "@conusai-kit/tenancy"
|
||||
import { afterEach, expect, it, vi } from "vitest"
|
||||
import { bindWebPorts, nativeHelpSelectors } from "../apps/web/src/server/ports.js"
|
||||
import { businessServiceComposition } from "../config/src/business-services.js"
|
||||
|
||||
const selection = vi.hoisted(() => ({ documents: false }))
|
||||
vi.mock("@app/modules", async (original) => ({
|
||||
...(await original<Record<string, unknown>>()),
|
||||
moduleSelected: (id: string) =>
|
||||
id === "documents" ? selection.documents : ["agent", "guides", "support"].includes(id),
|
||||
}))
|
||||
afterEach(() => {
|
||||
selection.documents = false
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
const descriptor = `sha256:${"a".repeat(64)}`
|
||||
const source = "b".repeat(40)
|
||||
const deployment = {
|
||||
CONUSAI_API_URL: "https://platform.example.test/api",
|
||||
CONUSAI_API_TOKEN: "synthetic-token",
|
||||
CONUSAI_ORG_ID: "1",
|
||||
CONUSAI_PROJECT_ID: "9",
|
||||
CONUSAI_ENVIRONMENT_ID: "3",
|
||||
CONUSAI_ORG_SLUG: "org",
|
||||
CONUSAI_WORKSPACE_SLUG: "workspace",
|
||||
CONUSAI_PROJECT_SLUG: "project",
|
||||
CONUSAI_PLATFORM_RELEASE_DESCRIPTOR: descriptor,
|
||||
CONUSAI_PLATFORM_SOURCE_COMMIT: source,
|
||||
}
|
||||
const observation = () => ({
|
||||
component: {
|
||||
id: "support",
|
||||
observed_at: new Date().toISOString(),
|
||||
facts: {
|
||||
installed: "true",
|
||||
enabled: "true",
|
||||
entitled: "true",
|
||||
configured: "true",
|
||||
ready: "true",
|
||||
},
|
||||
},
|
||||
authorized: "true",
|
||||
environment_bound: "true",
|
||||
compatible: "true",
|
||||
dependencies_ready: "true",
|
||||
policy_epoch: 2,
|
||||
descriptor_digest: descriptor,
|
||||
source_commit: source,
|
||||
organization_id: 1,
|
||||
project_id: 9,
|
||||
environment_id: 3,
|
||||
app_scope: "org",
|
||||
authorization_checked_at: new Date().toISOString(),
|
||||
})
|
||||
|
||||
function composition() {
|
||||
const modules = [tenancyModule, supportModule]
|
||||
const registry = buildRegistry(modules)
|
||||
const data = createMemoryDataSource({ entities: entitiesOf(registry, "postgres") })
|
||||
const base = new Container()
|
||||
base.value(DATA_SOURCE, data)
|
||||
base.value(SYSTEM_DATA, data)
|
||||
const env = loadAppEnv("web", {
|
||||
...deployment,
|
||||
NODE_ENV: "test",
|
||||
POSTGRES_URL: "postgresql://app_runtime:fixture@db/app",
|
||||
POSTGRES_READER_URL: "postgresql://app_reader:fixture@db/app",
|
||||
})
|
||||
bindWebPorts(base, platformClients(env, registry), registry)
|
||||
const root = base.child()
|
||||
root.value(SUPPORT_PLATFORM, { mode: "platform", channel: "spk_actual", client: {} } as never)
|
||||
const hooks = businessServiceComposition({ deployment }, modules, "postgres", nativeHelpSelectors)
|
||||
const caller = (actor: Actor) => {
|
||||
const tenancy = createTenancyHooks({ data, registry })
|
||||
const container = root.child()
|
||||
container.value(TENANCY, tenancy)
|
||||
return createCaller({ registry, container, tenancy, ...hooks }, { actor })
|
||||
}
|
||||
return { data, root, caller }
|
||||
}
|
||||
|
||||
it("returns empty without touching Documents when that module is not selected", async () => {
|
||||
const app = composition()
|
||||
const scope = {
|
||||
level: "project" as const,
|
||||
orgId: "local-org",
|
||||
workspaceId: "local-workspace",
|
||||
projectId: "local-project",
|
||||
actor: { userId: "member" },
|
||||
}
|
||||
const read = vi.spyOn(app.data, "forScope")
|
||||
expect(await app.root.resolve(SUPPORT_PROCESSING_STATUS).read(scope)).toEqual({
|
||||
state: "empty",
|
||||
processing: 0,
|
||||
extracted: 0,
|
||||
failed: 0,
|
||||
})
|
||||
expect(read).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// kit:documents:begin
|
||||
it("reads the requested project's processing counts when Documents is selected", async () => {
|
||||
selection.documents = true
|
||||
const app = composition()
|
||||
const scope = {
|
||||
level: "project" as const,
|
||||
orgId: "local-org",
|
||||
workspaceId: "local-workspace",
|
||||
projectId: "local-project",
|
||||
actor: { userId: "member" },
|
||||
}
|
||||
const list = vi.fn(async () => ({ items: [{ status: "processing" }, { status: "extracted" }, { status: "failed" }] }))
|
||||
const read = vi.spyOn(app.data, "forScope").mockReturnValue({ of: () => ({ list }) } as never)
|
||||
expect(await app.root.resolve(SUPPORT_PROCESSING_STATUS).read(scope)).toEqual({
|
||||
state: "failed",
|
||||
processing: 1,
|
||||
extracted: 1,
|
||||
failed: 1,
|
||||
})
|
||||
expect(read).toHaveBeenCalledWith(scope)
|
||||
})
|
||||
|
||||
// kit:documents:end
|
||||
|
||||
it("admits the containing org service after actual project authorization and preserves native denials", async () => {
|
||||
const app = composition()
|
||||
const user = await app.data.global(users).insert({
|
||||
issuer: "https://identity.example.test",
|
||||
subject: "owner",
|
||||
email: "owner@example.test",
|
||||
displayName: "Owner",
|
||||
locale: "en",
|
||||
})
|
||||
const actor = { userId: user.id }
|
||||
const caller = app.caller(actor)
|
||||
const org = (await caller.callByName("tenancy.org.create", { slug: "alpha", name: "Alpha" })) as { orgId: string }
|
||||
await caller.callByName("tenancy.project.create", {
|
||||
org: "alpha",
|
||||
workspace: "general",
|
||||
slug: "main",
|
||||
name: "Main",
|
||||
moduleKey: "support",
|
||||
})
|
||||
const input = { org: "alpha", workspace: "general", project: "main" }
|
||||
let current = observation()
|
||||
let status = 200
|
||||
const fetch = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockImplementation(async () => (status === 200 ? Response.json(current) : new Response(null, { status })))
|
||||
const dispatch = (query = input) => app.caller(actor).callByName("support.projectProcessingStatus.get", query)
|
||||
await expect(dispatch({ ...input, project: "missing" })).rejects.toMatchObject({ status: 404 })
|
||||
expect(fetch).not.toHaveBeenCalled()
|
||||
await expect(dispatch()).resolves.toEqual({ state: "empty", processing: 0, extracted: 0, failed: 0 })
|
||||
const first = fetch.mock.calls[0]
|
||||
if (!first) throw new Error("Expected native readiness request")
|
||||
const [url, request] = first
|
||||
expect(String(url)).toBe(
|
||||
"https://platform.example.test/api/v1/orgs/org/workspaces/workspace/projects/project/environments/3/platform-services/support/readiness",
|
||||
)
|
||||
expect(request?.redirect).toBe("error")
|
||||
expect(request?.headers).toMatchObject({ authorization: "Bearer synthetic-token" })
|
||||
expect(JSON.parse(String(request?.body))).toEqual({
|
||||
api_range: "=1.0.0-preview.20261103",
|
||||
scopes: ["support:widget-sessions"],
|
||||
app_scope: "org",
|
||||
channel: "spk_actual",
|
||||
})
|
||||
for (const changed of [{ project_id: 10 }, { app_scope: "project" }, { environment_id: 4 }]) {
|
||||
current = { ...observation(), ...changed }
|
||||
await expect(dispatch()).rejects.toMatchObject({ code: "service_permission_missing" })
|
||||
}
|
||||
current = { ...observation(), source_commit: "c".repeat(40) }
|
||||
await expect(dispatch()).rejects.toMatchObject({ code: "service_incompatible" })
|
||||
status = 403
|
||||
await expect(dispatch()).rejects.toMatchObject({ code: "service_permission_missing" })
|
||||
const beforeRevocation = fetch.mock.calls.length
|
||||
await app.data.unitOfWork.run({ level: "org", orgId: org.orgId, actor }, async (tx) => {
|
||||
const membership = (await tx.of(orgMemberships).list({ where: [{ field: "userId", op: "eq", value: user.id }] }))
|
||||
.items[0]
|
||||
if (!membership) throw new Error("Expected owner membership")
|
||||
await tx.of(orgMemberships).delete(membership.id)
|
||||
})
|
||||
await expect(dispatch()).rejects.toMatchObject({ status: 404 })
|
||||
expect(fetch).toHaveBeenCalledTimes(beforeRevocation)
|
||||
})
|
||||
Reference in New Issue
Block a user