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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/main/__tests__/integration-event-bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function makeHarness(agents = ['alice', 'bob']): {
const bridge = new IntegrationEventBridge({
getWorkspaceHandle: async () => ({
workspaceId: 'workspace-id',
localMountWorkspaceId: 'workspace-id',
client: () => ({
subscribe(globs, onChange, options) {
subscribeCalls.push({ globs: [...globs], onChange, options })
Expand Down Expand Up @@ -152,6 +153,24 @@ test('channel notification targets do not fall back to all project agents', asyn
assert.deepEqual(harness.listAgentsCalls, [])
})

test('offline notification agents fall back to current project agents', async () => {
const harness = makeHarness(['alice', 'bob'])

await harness.bridge.reconcile('project-1', [
integration({
provider: 'slack',
integrationId: 'slack-1',
mountPaths: ['/slack/channels'],
scope: { notifyAgents: ['claude-1'] }
})
])

await harness.emit(changeEvent('/slack/channels/general/messages/123.json', 'slack'))

assert.deepEqual(harness.sent.map((message) => message.input.to), ['alice', 'bob'])
assert.deepEqual(harness.listAgentsCalls, ['project-1'])
})

test('integration events watch selected relayfile mount paths', async () => {
const harness = makeHarness()
const slackIntegration = integration({
Expand All @@ -168,9 +187,11 @@ test('integration events watch selected relayfile mount paths', async () => {
await harness.bridge.reconcile('project-1', [slackIntegration])

assert.deepEqual(harness.subscribeCalls[0].globs, [
'/slack/channels/C123ABC/**',
'/slack/channels/C123ABC__proj-cloud/**'
])
assert.deepEqual(integrationSubscriptionSummaries([slackIntegration])[0].watches, [
'.integrations/slack/channels/C123ABC/**',
'.integrations/slack/channels/C123ABC__proj-cloud/**'
])

Expand All @@ -179,6 +200,32 @@ test('integration events watch selected relayfile mount paths', async () => {
assert.deepEqual(harness.sent.map((message) => message.input.to), ['alice'])
assert.match(harness.sent[0].input.text, /Path: \.integrations\/slack\/channels\/C123ABC__proj-cloud\/messages\/1713220123_001100\/meta\.json/u)
assert.match(harness.sent[0].input.text, /Relayfile path: \/slack\/channels\/C123ABC__proj-cloud\/messages\/1713220123_001100\/meta\.json/u)

harness.sent.splice(0)
await harness.emit(changeEvent('/slack/channels/C123ABC/messages/1713220124_001100/meta.json', 'slack'))
assert.deepEqual(harness.sent.map((message) => message.input.to), ['alice'])
})

test('integration events preserve discovery mount paths', async () => {
const harness = makeHarness()
const slackIntegration = integration({
provider: 'slack',
integrationId: 'slack-1',
mountPaths: ['/discovery/slack']
})

await harness.bridge.reconcile('project-1', [slackIntegration])

assert.deepEqual(harness.subscribeCalls[0].globs, [
'/discovery/slack/**'
])
assert.deepEqual(integrationSubscriptionSummaries([slackIntegration])[0].watches, [
'.integrations/discovery/slack/**'
])

await harness.emit(changeEvent('/discovery/slack/actions/create-message/.schema.json', 'slack'))
assert.deepEqual(harness.sent, [])
assert.deepEqual(harness.listAgentsCalls, [])
})

test('resource alias mount paths inject the same relative event only once', async () => {
Expand Down
64 changes: 64 additions & 0 deletions src/main/__tests__/integration-remote-paths.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import assert from 'node:assert/strict'
import { test } from 'node:test'

import {
canShowRemoteDirectoryEntryForMountPaths,
canListRemoteDirectoryForMountPaths,
normalizeRemoteDirectoryPath,
remotePathName
} from '../integration-remote-paths.ts'

test('remote directory paths reject traversal segments', () => {
assert.equal(normalizeRemoteDirectoryPath('/slack/channels'), '/slack/channels')
assert.equal(normalizeRemoteDirectoryPath('/slack/../channels'), null)
assert.equal(normalizeRemoteDirectoryPath('/slack/./channels'), null)
assert.equal(remotePathName('/slack/channels/C123'), 'C123')
})

test('remote directory listing is limited to configured mount roots', () => {
assert.equal(canListRemoteDirectoryForMountPaths('/slack/channels/C123', [
'/slack/channels/C123'
]), true)
assert.equal(canListRemoteDirectoryForMountPaths('/slack/channels/C123/messages', [
'/slack/channels/C123'
]), true)
assert.equal(canListRemoteDirectoryForMountPaths('/slack/channels', [
'/slack/channels/C123'
]), true)
assert.equal(canListRemoteDirectoryForMountPaths('/slack', [
'/slack/channels/C123'
]), false)
assert.equal(canListRemoteDirectoryForMountPaths('/slack/channels/C999', [
'/slack/channels/C123'
]), false)
})

test('remote directory listing permits provider discovery only for that provider', () => {
assert.equal(canListRemoteDirectoryForMountPaths('/discovery/slack/actions', [
'/discovery/slack'
]), true)
assert.equal(canListRemoteDirectoryForMountPaths('/discovery', [
'/discovery/slack'
]), false)
assert.equal(canListRemoteDirectoryForMountPaths('/discovery/github/actions', [
'/discovery/slack'
]), false)
})

test('remote directory entries are filtered to configured mount roots', () => {
assert.equal(canShowRemoteDirectoryEntryForMountPaths('/slack/channels/C123', [
'/slack/channels/C123'
]), true)
assert.equal(canShowRemoteDirectoryEntryForMountPaths('/slack/channels/C123/messages', [
'/slack/channels/C123'
]), true)
assert.equal(canShowRemoteDirectoryEntryForMountPaths('/slack/channels/C999', [
'/slack/channels/C123'
]), false)
assert.equal(canShowRemoteDirectoryEntryForMountPaths('/discovery', [
'/discovery/slack'
]), true)
assert.equal(canShowRemoteDirectoryEntryForMountPaths('/discovery/github', [
'/discovery/slack'
]), false)
})
Loading
Loading