Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.2.60"
version = "2.2.61"
requires-python = ">= 3.10"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down
127 changes: 127 additions & 0 deletions session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Session Directions: Add Slack Bot Mode Support

## Context
The Socket Python CLI currently supports Slack notifications via incoming webhooks. We need to add an alternative "bot" mode that uses a Slack App with Bot Token for more flexible channel routing.

## Current Implementation
- File: `socketsecurity/plugins/slack.py`
- File: `socketsecurity/config.py`
- Env var: `SOCKET_SLACK_CONFIG_JSON`
- Current config uses `url` and `url_configs` for webhook routing

## Requirements

### 1. Add Mode Selection
- Add top-level `mode` field to Slack config
- Valid values: "webhook" (default), "bot"
- Mode determines which authentication and routing method to use

### 2. Webhook Mode (existing, default)
```json
{
"enabled": true,
"mode": "webhook",
"url": ["https://hooks.slack.com/..."],
"url_configs": {
"webhook_0": {"repos": ["repo1"], "severities": ["critical"]}
}
}
```
Keep all existing webhook functionality unchanged.

### 3. Bot Mode (new)
```json
{
"enabled": true,
"mode": "bot",
"bot_configs": [
{
"name": "critical_alerts",
"channels": ["security-alerts", "critical-incidents"],
"repos": ["prod-app"],
"severities": ["critical"],
"reachability_alerts_only": true
},
{
"name": "all_alerts",
"channels": ["dev-alerts"],
"severities": ["high", "medium"]
}
]
}
```

- New env var: `SOCKET_SLACK_BOT_TOKEN` (Bot User OAuth Token starting with `xoxb-`)
- Use `bot_configs` array instead of `url` + `url_configs`
- Each bot_config has:
- `name`: identifier for logging
- `channels`: array of Slack channel names or IDs to post to
- All existing filter options: `repos`, `severities`, `alert_types`, `reachability_alerts_only`, `always_send_reachability`

### 4. Channel Routing
- Slack API accepts both channel names (without #) and channel IDs (C1234567890)
- Recommend supporting both: try name first, fallback to ID if needed
- API endpoint: `https://slack.com/api/chat.postMessage`
- Request format:
```python
{
"channel": "channel-name", # or "C1234567890"
"blocks": blocks
}
```
- Headers: `{"Authorization": f"Bearer {bot_token}", "Content-Type": "application/json"}`

### 5. Implementation Tasks

#### config.py
- No changes needed (config is loaded from JSON env var)

#### slack.py
1. Update `send()` method:
- Check `self.config.get("mode", "webhook")`
- If "webhook": call existing `_send_webhook_alerts()` (refactor current logic)
- If "bot": call new `_send_bot_alerts()`

2. Create `_send_bot_alerts()` method:
- Get bot token from env: `os.getenv("SOCKET_SLACK_BOT_TOKEN")`
- Validate token exists and starts with "xoxb-"
- Get `bot_configs` from config
- For each bot_config, filter alerts same way as webhooks
- For each channel in bot_config's channels array, post message via chat.postMessage API

3. Create `_post_to_slack_api()` helper method:
- Takes bot_token, channel, blocks
- Posts to https://slack.com/api/chat.postMessage
- Returns response
- Log errors with channel name/ID for debugging

4. Error handling:
- Log if bot token missing when mode is "bot"
- Handle API errors (invalid channel, missing permissions, rate limits)
- Parse Slack API response JSON (it returns 200 with error in body)

5. Reuse existing:
- All filtering logic (`_filter_alerts`)
- All block building (`create_slack_blocks_from_diff`, `_create_reachability_slack_blocks_from_structured`)
- All reachability data loading

### 6. Testing Considerations
- Test both modes don't interfere with each other
- Test channel name resolution
- Test channel ID usage
- Test multiple channels per bot_config
- Test error handling when bot token invalid or missing
- Verify block count limits still respected (50 blocks)

### 7. Documentation Updates (README.md)
Add bot mode configuration examples and SOCKET_SLACK_BOT_TOKEN env var documentation.

## Key Files to Modify
1. `socketsecurity/plugins/slack.py` - main implementation
2. `README.md` - add bot mode documentation

## Notes
- Slack chat.postMessage returns HTTP 200 even on errors. Check response JSON for `"ok": false`
- Rate limit: 1 message per second per channel (more generous than webhooks)
- Channel names are case-insensitive, don't need # prefix
- Public and private channels both work if bot is invited
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__author__ = 'socket.dev'
__version__ = '2.2.60'
__version__ = '2.2.61'
USER_AGENT = f'SocketPythonCLI/{__version__}'
5 changes: 4 additions & 1 deletion socketsecurity/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,10 @@ def create_full_scan(self, files: List[str], params: FullScanParams, base_paths:

# Finalize tier1 scan if reachability analysis was enabled
if self.cli_config and self.cli_config.reach:
facts_file_path = self.cli_config.reach_output_file or ".socket.facts.json"
facts_file_path = os.path.join(
self.cli_config.target_path or ".",
self.cli_config.reach_output_file
)
log.debug(f"Reachability analysis enabled, finalizing tier1 scan for full scan {full_scan.id}")
try:
success = self.finalize_tier1_scan(full_scan.id, facts_file_path)
Expand Down
Loading
Loading