Run the CLI from Slack over Socket Mode, behind an admission gate - #23
Merged
Conversation
`python -m grapharc.slack` holds one outbound WebSocket to Slack, so a laptop behind NAT is a viable host: no public URL, no open port. A workspace member types `/grapharc metrics t.jsonl r1` or mentions the bot, and the piped-mode bytes come back in a code fence — the CLI's stable form, not a third dialect. Anyone in the workspace can talk to the bot, so what Slack text may become an argv is an admission decision: subcommands are allowlisted (`agent` and `serve` are not in the list), flags are allowlisted per subcommand (`--registry`, `--config`, `--json` are not reachable), every path must resolve inside the bot's working directory, and `--model` is refused unless the operator opts in — the default answer to "can Slack cost me money?" is no. Only `bot.py` touches slack-bolt, lazily, so the wheel imports without the new `slack` extra; the gate, runner and formatter are stdlib-only and tested without a token or a network in tests/test_slack_gateway.py. A module entry rather than a `grapharc slack` subcommand, because the parser's help is printed verbatim in README.md and byte-compared. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A Slack front door for the
grapharcCLI, hostable on a laptop:python -m grapharc.slackholds one outbound Socket Mode WebSocket, so there is no public URL, no open port, no reverse proxy./grapharc metrics t.jsonl r1(or an @mention) from any Slack client runs the command on the host and posts the piped-mode bytes back in a code fence — the CLI's stable form, not a third output dialect.The gate
Anyone in the workspace can talk to the bot, so what text may become an argv is an admission decision, in the repo's own idiom:
demo run plan models replay diff trace metrics viz.agent(arbitrary tool execution on the host) andserveare not in the list.--registry(imports an arbitrary module),--config,--json,--no-colorare unreachable from Slack.--flag valueor--flag=valueform — must resolve inside the bot's working directory, refused before any process spawns.--model/--reviewer-modelare refused unless the operator setsGRAPHARC_SLACK_ALLOW_MODEL=1in the shell that starts the bot. Default spend from Slack: zero — every reachable command runs the scripted path.Modularity
A module entry rather than a
grapharc slacksubcommand, because the parser help is printed verbatim in README.md and byte-compared by the suite; a daemon also doesn't belong in a parser whose every other command terminates.Packaging and docs
slackextra (slack-bolt>=1.20), joined to[all]so the CI wheel-check imports the module with the dependency present; every module exceptbot.pyimports without it.docs/cookbook/07-slack.md: Slack app manifest (scopescommands,app_mentions:read,chat:write), token setup, run instructions, the allow/refuse table, and the honest caveats (bot dies with the laptop lid; the workspace is the trust boundary).Testing
tests/test_slack_gateway.py— 21 tests, no token, no network: the gate's allow/deny/confinement decisions, an end-to-end run of the real CLI through the runner+formatter (success, exit-2, and the timeout kill), announced truncation, fence-escape defusal, config validation, and the missing-extra install hint (import failure faked, not skipped).Full suite green locally,
ruff check .clean.🤖 Generated with Claude Code