Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c24acef
fix(slackbotv2): hide Codex effort and speed (#1095)
decofe Jul 15, 2026
dcb2bf8
fix(console): use GitHub login for PR attribution (#1087)
goksu Jul 15, 2026
d972061
fix: improve console dropdown labels (#1097)
mslipper Jul 16, 2026
6e636e4
fix: preserve postgres proxy credentials on resume (#1099)
Zygimantass Jul 16, 2026
7e7e823
feat: Make the chat agent platform-aware (Slack/Discord/Linear/Github…
0xdiid Jul 16, 2026
dd984af
fix(linearbot): don't start an assignment turn when the bot assigns i…
0xdiid Jul 16, 2026
71b6e96
fix(linearbot): Prevent Linearbot from marking issues as "done" when …
0xdiid Jul 16, 2026
ce93b89
fix(harness-server): downscale oversized image attachments before the…
0xdiid Jul 16, 2026
05b20f7
fix: omit Slack client secret for PKCE login (#1100)
akshaan Jul 16, 2026
3cf4b35
fix: use confidential Slack OIDC login (#1101)
akshaan Jul 16, 2026
1a79a51
fix(console): separate chat discovery from access (#1102)
goksu Jul 16, 2026
0fa2525
feat: add LLM message override strategy (#1096)
mslipper Jul 16, 2026
321dc9c
fix: reduce slack override strategy log noise (#1104)
mslipper Jul 16, 2026
39c4e7b
feat: render attached images in console chat (#1105)
decofe Jul 16, 2026
ad88a20
fix(console): clean up chat detail rows (#1108)
goksu Jul 16, 2026
9d19013
feat: add workflow-scoped principals (#1107)
mslipper Jul 16, 2026
7294798
fix(console): speed up chat loading (#1109)
goksu Jul 16, 2026
a4b0976
feat(slackbotv2): dispatch Block Kit actions (#1110)
goksu Jul 17, 2026
a4f56e9
fix: update vulnerable console sanitizers (#1118)
mslipper Jul 17, 2026
62c4fa6
fix: attach Laminar traces to thread roots (#1106)
mslipper Jul 17, 2026
751e4b9
ci: run console gem audit on main (#1119)
mslipper Jul 17, 2026
4743d49
feat(sandbox): install Google Cloud CLI (#1124)
mslipper Jul 18, 2026
a49ea3e
fix: install workflow analytics dependencies (#1125)
mslipper Jul 18, 2026
22a036b
chore: bump iron-proxy image (#1126)
mslipper Jul 19, 2026
064a26d
Merge Paradigm Centaur upstream through #1126
fineas-bot[bot] Jul 19, 2026
88a58b6
Use an async mutex for session context env isolation
fineas-bot[bot] Jul 19, 2026
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
3 changes: 0 additions & 3 deletions .github/workflows/console-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ jobs:
- name: Scan for common Rails security vulnerabilities using static analysis
run: bin/brakeman --no-pager

- name: Scan for known security vulnerabilities in gems used
run: bin/bundler-audit

scan_js:
runs-on: ubuntu-latest
needs: console_changes
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/console-gem-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Console Gem Audit

on:
push:
branches: [ main ]

permissions:
contents: read

defaults:
run:
working-directory: services/console

jobs:
scan_gems:
runs-on: depot-ubuntu-24.04-16

steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1.312.0
with:
working-directory: services/console
bundler-cache: true

- name: Scan for known security vulnerabilities in gems used
run: bin/bundler-audit
8 changes: 8 additions & 0 deletions centaur_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

from centaur_sdk.tool_sdk import (
ToolContext,
current_chat_destination,
current_discord_thread,
current_github_thread,
current_linear_thread,
current_session_context,
current_slack_thread,
current_thread_key,
Expand All @@ -21,6 +25,10 @@

__all__ = [
"ToolContext",
"current_chat_destination",
"current_discord_thread",
"current_github_thread",
"current_linear_thread",
"current_session_context",
"current_slack_thread",
"current_thread_key",
Expand Down
221 changes: 221 additions & 0 deletions centaur_sdk/tests/test_tool_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

from centaur_sdk import (
ToolContext,
current_chat_destination,
current_discord_thread,
current_github_thread,
current_linear_thread,
current_session_context,
current_slack_thread,
reset_tool_context,
Expand Down Expand Up @@ -157,6 +161,223 @@ def read(self) -> bytes:
reset_tool_context(token)


def _fake_context_response(payload: bytes):
class FakeResponse:
def __enter__(self):
return self

def __exit__(self, exc_type, exc, tb):
return False

def read(self) -> bytes:
return payload

return FakeResponse


def _discord_context(thread_key: str, monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"' + thread_key.encode() + b'","platform":"discord",'
b'"discord":{"guild_id":"111","channel_id":"222","thread_id":"333"}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
return set_tool_context(
ToolContext(
name="fake-tool",
thread_key=thread_key,
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)


def test_current_discord_thread_returns_api_discord_destination(
monkeypatch: pytest.MonkeyPatch,
):
token = _discord_context("discord:111:222:333", monkeypatch)
try:
assert current_discord_thread() == {
"guild_id": "111",
"channel_id": "222",
"thread_id": "333",
}
finally:
reset_tool_context(token)


def test_current_chat_destination_tags_platform(monkeypatch: pytest.MonkeyPatch):
token = _discord_context("discord:111:222:333", monkeypatch)
try:
assert current_chat_destination() == {
"platform": "discord",
"guild_id": "111",
"channel_id": "222",
"thread_id": "333",
}
finally:
reset_tool_context(token)


def _linear_context(thread_key: str, monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"' + thread_key.encode() + b'","platform":"linear",'
b'"linear":{"issue_id":"ISSUE","comment_id":"CMT","agent_session_id":"SESS"}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
return set_tool_context(
ToolContext(
name="fake-tool",
thread_key=thread_key,
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)


def test_current_linear_thread_returns_api_linear_destination(
monkeypatch: pytest.MonkeyPatch,
):
token = _linear_context("linear:ISSUE:c:CMT:s:SESS", monkeypatch)
try:
assert current_linear_thread() == {
"issue_id": "ISSUE",
"comment_id": "CMT",
"agent_session_id": "SESS",
}
finally:
reset_tool_context(token)


def test_current_chat_destination_tags_linear_platform(monkeypatch: pytest.MonkeyPatch):
token = _linear_context("linear:ISSUE:c:CMT:s:SESS", monkeypatch)
try:
assert current_chat_destination() == {
"platform": "linear",
"issue_id": "ISSUE",
"comment_id": "CMT",
"agent_session_id": "SESS",
}
finally:
reset_tool_context(token)


def _github_context(thread_key: str, monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"' + thread_key.encode() + b'","platform":"github",'
b'"github":{"owner":"0xSplits","repo":"centaur","number":704,'
b'"kind":"pr","review_comment_id":99}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
return set_tool_context(
ToolContext(
name="fake-tool",
thread_key=thread_key,
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)


def test_current_github_thread_returns_api_github_destination(
monkeypatch: pytest.MonkeyPatch,
):
token = _github_context("github:0xSplits/centaur:704:rc:99", monkeypatch)
try:
assert current_github_thread() == {
"owner": "0xSplits",
"repo": "centaur",
"number": 704,
"kind": "pr",
"review_comment_id": 99,
}
finally:
reset_tool_context(token)


def test_current_chat_destination_tags_github_platform(monkeypatch: pytest.MonkeyPatch):
token = _github_context("github:0xSplits/centaur:704:rc:99", monkeypatch)
try:
assert current_chat_destination() == {
"platform": "github",
"owner": "0xSplits",
"repo": "centaur",
"number": 704,
"kind": "pr",
"review_comment_id": 99,
}
finally:
reset_tool_context(token)


def test_current_github_thread_rejects_slack_thread(monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"slack:C123:123.456","platform":"slack",'
b'"slack":{"channel_id":"C123","thread_ts":"123.456"}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
token = set_tool_context(
ToolContext(
name="fake-tool",
thread_key="slack:C123:123.456",
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)
try:
with pytest.raises(RuntimeError, match="not a GitHub thread"):
current_github_thread()
finally:
reset_tool_context(token)


def test_current_linear_thread_rejects_slack_thread(monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"slack:C123:123.456","platform":"slack",'
b'"slack":{"channel_id":"C123","thread_ts":"123.456"}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
token = set_tool_context(
ToolContext(
name="fake-tool",
thread_key="slack:C123:123.456",
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)
try:
with pytest.raises(RuntimeError, match="not a Linear thread"):
current_linear_thread()
finally:
reset_tool_context(token)


def test_current_discord_thread_rejects_slack_thread(monkeypatch: pytest.MonkeyPatch):
payload = (
b'{"thread_key":"slack:C123:123.456","platform":"slack",'
b'"slack":{"channel_id":"C123","thread_ts":"123.456"}}'
)
monkeypatch.setattr(
"urllib.request.urlopen", lambda _request, timeout: _fake_context_response(payload)()
)
token = set_tool_context(
ToolContext(
name="fake-tool",
thread_key="slack:C123:123.456",
secrets={"CENTAUR_API_URL": "http://api:8000", "CENTAUR_API_KEY": ""},
)
)
try:
with pytest.raises(RuntimeError, match="not a Discord thread"):
current_discord_thread()
finally:
reset_tool_context(token)


def test_save_attachment_writes_to_sandbox_uploads_dir(
monkeypatch: pytest.MonkeyPatch, tmp_path
):
Expand Down
Loading
Loading