Files
open-harness/.pi/extensions/slack/allowlist.ts
T
OpenHarness BotandClaude Opus 4.7 e7e96ccfdd feat: add Slack support to .pi/ as a Pi extension
Adds .pi/extensions/slack/ with Socket Mode bridge, allowlist gating,
and 4 LLM-callable tools (slack_post/reply/react/upload). Inbound
messages bridge into pi.sendUserMessage() with ctx.isIdle() guard;
turn_end posts the assistant's reply back to Slack via SlackContext.
session_shutdown tears down the Socket Mode connection.

Customizations preserved from portfolio-advisor reference:
- threadTs field on event types (7 sites in events.ts)
- threadParent routing in createSlackContext (context.ts:45)
- exported parseEventContent + buildSyntheticEvent

Tests: 27 new (3 files); 78 pre-existing tests still green; 114 total.

Plan: .claude/plans/context-study-https-github-com-ryaneggz-binary-hartmanis.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:03:04 -06:00

36 lines
1.3 KiB
TypeScript

// Fail-safe channel/user allowlist: denies all events if both env vars are unset; grants access only to listed IDs when set.
// Fail-safe: if BOTH SLACK_ALLOW_CHANNELS and SLACK_ALLOW_USERS are unset, isAllowed returns false for everything.
// If at least one is set, a request passes when (channel matches OR allow-channels-unset) AND (user matches OR allow-users-unset).
export interface Allowlist {
isAllowed(channelId: string, userId: string): boolean;
}
export function createAllowlist(): Allowlist {
const rawChannels = process.env.SLACK_ALLOW_CHANNELS;
const rawUsers = process.env.SLACK_ALLOW_USERS;
// Both unset → deny everything (fail-safe default)
const bothUnset = rawChannels === undefined && rawUsers === undefined;
const allowedChannels = rawChannels
? new Set(rawChannels.split(",").map((s) => s.trim()).filter(Boolean))
: null; // null means "no channel filter" (allow any channel)
const allowedUsers = rawUsers
? new Set(rawUsers.split(",").map((s) => s.trim()).filter(Boolean))
: null; // null means "no user filter" (allow any user)
return {
isAllowed(channelId: string, userId: string): boolean {
if (bothUnset) return false;
const channelOk = allowedChannels === null || allowedChannels.has(channelId);
const userOk = allowedUsers === null || allowedUsers.has(userId);
return channelOk && userOk;
},
};
}