Skip to content

Commit 871f7e8

Browse files
committed
broker: migrate runtime registration identity to org id
1 parent df1c479 commit 871f7e8

17 files changed

+268
-106
lines changed

.env.schema

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,18 @@ GATEWAY_BROKER_URL=
137137
# @sensitive=false @type=url
138138
SLACK_BROKER_URL=
139139

140-
# Gateway workspace/team ID registered with broker (preferred)
140+
# Gateway org ID registered with broker (preferred)
141+
# @sensitive=false @type=string
142+
GATEWAY_BROKER_ORG_ID=
143+
144+
# Legacy alias for GATEWAY_BROKER_ORG_ID
145+
# @sensitive=false @type=string
146+
SLACK_BROKER_ORG_ID=
147+
148+
# Deprecated workspace/team ID aliases (still accepted for migration)
141149
# @sensitive=false @type=string(startsWith=T)
142150
GATEWAY_BROKER_WORKSPACE_ID=
143151

144-
# Legacy alias for GATEWAY_BROKER_WORKSPACE_ID
145152
# @sensitive=false @type=string(startsWith=T)
146153
SLACK_BROKER_WORKSPACE_ID=
147154

CONFIGURATION.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ If you're using the Slack broker OAuth flow, register this server after install:
5353
```bash
5454
sudo baudbot broker register \
5555
--broker-url https://your-broker.example.com \
56-
--workspace-id T0123ABCD \
56+
--org-id org_1234abcd \
5757
--registration-token <token-from-dashboard-callback>
5858
```
5959

@@ -121,8 +121,10 @@ Set by `sudo baudbot broker register` when using brokered Slack OAuth flow.
121121
|----------|-------------|
122122
| `GATEWAY_BROKER_URL` | **Preferred** broker base URL |
123123
| `SLACK_BROKER_URL` | Legacy alias for `GATEWAY_BROKER_URL` (still supported) |
124-
| `GATEWAY_BROKER_WORKSPACE_ID` | **Preferred** Slack workspace/team ID (`T...`) |
125-
| `SLACK_BROKER_WORKSPACE_ID` | Legacy alias for `GATEWAY_BROKER_WORKSPACE_ID` |
124+
| `GATEWAY_BROKER_ORG_ID` | **Preferred** broker org ID |
125+
| `SLACK_BROKER_ORG_ID` | Legacy alias for `GATEWAY_BROKER_ORG_ID` |
126+
| `GATEWAY_BROKER_WORKSPACE_ID` | Deprecated workspace/team ID alias (still accepted for migration) |
127+
| `SLACK_BROKER_WORKSPACE_ID` | Deprecated alias for `GATEWAY_BROKER_WORKSPACE_ID` |
126128
| `GATEWAY_BROKER_SERVER_PRIVATE_KEY` | **Preferred** server X25519 private key (base64) |
127129
| `SLACK_BROKER_SERVER_PRIVATE_KEY` | Legacy alias for `GATEWAY_BROKER_SERVER_PRIVATE_KEY` |
128130
| `GATEWAY_BROKER_SERVER_PUBLIC_KEY` | **Preferred** server X25519 public key (base64) |
@@ -254,7 +256,7 @@ SENTRY_CHANNEL_ID=C0987654321
254256

255257
# Gateway broker registration (optional, set by: sudo baudbot broker register)
256258
GATEWAY_BROKER_URL=https://broker.example.com
257-
GATEWAY_BROKER_WORKSPACE_ID=T0123ABCD
259+
GATEWAY_BROKER_ORG_ID=org_1234abcd
258260
# Optional broker auth token fields (set by broker register when provided)
259261
# GATEWAY_BROKER_ACCESS_TOKEN=...
260262
# GATEWAY_BROKER_ACCESS_TOKEN_EXPIRES_AT=2026-02-22T22:15:00.000Z

bin/baudbot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,11 +476,11 @@ case "$COMMAND_NAME" in
476476
exec "$NODE_BIN" "$BAUDBOT_ROOT/bin/broker-register.mjs" "$@"
477477
;;
478478
--help|-h|"")
479-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
479+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--org-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
480480
;;
481481
*)
482482
echo "Unknown broker subcommand: ${1:-}"
483-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
483+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--org-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
484484
exit 1
485485
;;
486486
esac

bin/broker-register.mjs

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
/**
33
* Slack broker registration CLI.
44
*
5-
* Registers this baudbot server with a Slack broker workspace using:
5+
* Registers this baudbot server with a broker org using:
66
* - broker URL
7-
* - workspace ID
7+
* - org ID
88
* - registration token from dashboard callback
99
*
1010
* On success, stores broker config and generated server key material in:
@@ -22,9 +22,10 @@ import { pathToFileURL } from "node:url";
2222

2323
const { subtle } = webcrypto;
2424

25-
const WORKSPACE_ID_RE = /^T[A-Z0-9]+$/;
25+
const ORG_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
2626
const ENV_KEYS = [
2727
"SLACK_BROKER_URL",
28+
"SLACK_BROKER_ORG_ID",
2829
"SLACK_BROKER_WORKSPACE_ID",
2930
"SLACK_BROKER_SERVER_PRIVATE_KEY",
3031
"SLACK_BROKER_SERVER_PUBLIC_KEY",
@@ -47,7 +48,8 @@ export function usageText() {
4748
"",
4849
"Options:",
4950
" --broker-url URL Broker base URL (e.g. https://broker.example.com)",
50-
" --workspace-id ID Slack workspace ID (e.g. T0123ABCD)",
51+
" --org-id ID Broker org ID (e.g. org_1234abcd)",
52+
" --workspace-id ID Deprecated alias for --org-id (supported for compatibility)",
5153
" --registration-token TOKEN Registration token from dashboard callback (required)",
5254
" --no-restart Skip automatic agent restart after registration",
5355
" -v, --verbose Show detailed registration progress",
@@ -60,7 +62,7 @@ export function usageText() {
6062
export function parseArgs(argv) {
6163
const out = {
6264
brokerUrl: "",
63-
workspaceId: "",
65+
orgId: "",
6466
registrationToken: "",
6567
verbose: false,
6668
help: false,
@@ -95,13 +97,24 @@ export function parseArgs(argv) {
9597
continue;
9698
}
9799

100+
if (arg.startsWith("--org-id=")) {
101+
out.orgId = arg.slice("--org-id=".length);
102+
continue;
103+
}
104+
if (arg === "--org-id") {
105+
i++;
106+
out.orgId = argv[i] || "";
107+
continue;
108+
}
109+
110+
// Backward-compatible CLI alias.
98111
if (arg.startsWith("--workspace-id=")) {
99-
out.workspaceId = arg.slice("--workspace-id=".length);
112+
out.orgId = arg.slice("--workspace-id=".length);
100113
continue;
101114
}
102115
if (arg === "--workspace-id") {
103116
i++;
104-
out.workspaceId = argv[i] || "";
117+
out.orgId = argv[i] || "";
105118
continue;
106119
}
107120

@@ -115,7 +128,6 @@ export function parseArgs(argv) {
115128
continue;
116129
}
117130

118-
119131
throw new Error(`unknown argument: ${arg}`);
120132
}
121133

@@ -145,8 +157,14 @@ export function normalizeBrokerUrl(raw) {
145157
return parsed.toString().replace(/\/$/, "");
146158
}
147159

160+
export function validateOrgId(orgId) {
161+
const normalized = String(orgId || "").trim();
162+
return normalized.length > 0 && normalized.length <= 128 && ORG_ID_RE.test(normalized);
163+
}
164+
165+
// Backward-compatible export for older imports/tests.
148166
export function validateWorkspaceId(workspaceId) {
149-
return WORKSPACE_ID_RE.test(String(workspaceId || ""));
167+
return validateOrgId(workspaceId);
150168
}
151169

152170
function decodeBase64Url(value) {
@@ -222,10 +240,10 @@ export function mapRegisterError(status, errorText) {
222240
return "registration token already used — re-run OAuth install and use a fresh token";
223241
}
224242
if (status === 409 && /already active/i.test(text)) {
225-
return "workspace already active — unregister the current server first";
243+
return "org already active — unregister the current server first";
226244
}
227-
if (status === 404 && /workspace not found/i.test(text)) {
228-
return "workspace not found — complete broker OAuth install first";
245+
if (status === 404 && /(workspace|org) not found/i.test(text)) {
246+
return "org not found — complete dashboard registration first";
229247
}
230248
if (status >= 500) {
231249
return `broker server error (${status}) — ${text}`;
@@ -235,7 +253,7 @@ export function mapRegisterError(status, errorText) {
235253

236254
export async function registerWithBroker({
237255
brokerUrl,
238-
workspaceId,
256+
orgId,
239257
registrationToken,
240258
serverKeys,
241259
fetchImpl = fetch,
@@ -246,13 +264,15 @@ export async function registerWithBroker({
246264

247265
const endpoint = new URL("/api/register", brokerUrl);
248266
const registerRequestBody = {
249-
workspace_id: workspaceId,
267+
org_id: orgId,
268+
// Keep workspace_id during migration so older broker APIs still accept this payload.
269+
workspace_id: orgId,
250270
server_pubkey: serverKeys.server_pubkey,
251271
server_signing_pubkey: serverKeys.server_signing_pubkey,
252272
registration_token: registrationToken,
253273
};
254274

255-
logger(`Registering workspace ${workspaceId} at ${endpoint}`);
275+
logger(`Registering org ${orgId} at ${endpoint}`);
256276

257277
let registerResponse;
258278
try {
@@ -262,7 +282,7 @@ export async function registerWithBroker({
262282
body: JSON.stringify(registerRequestBody),
263283
});
264284
} catch (err) {
265-
throw new Error(`network failure registering workspace: ${err instanceof Error ? err.message : "unknown error"}`);
285+
throw new Error(`network failure registering org: ${err instanceof Error ? err.message : "unknown error"}`);
266286
}
267287

268288
let registerResponseBody = {};
@@ -471,11 +491,15 @@ async function collectInputs(parsedArgs) {
471491

472492
const brokerUrl = parsedArgs.brokerUrl
473493
|| existing.SLACK_BROKER_URL
494+
|| existing.GATEWAY_BROKER_URL
474495
|| (await prompt("Broker URL: "));
475496

476-
const workspaceId = parsedArgs.workspaceId
497+
const orgId = parsedArgs.orgId
498+
|| existing.SLACK_BROKER_ORG_ID
499+
|| existing.GATEWAY_BROKER_ORG_ID
477500
|| existing.SLACK_BROKER_WORKSPACE_ID
478-
|| (await prompt("Workspace ID (starts with T): "));
501+
|| existing.GATEWAY_BROKER_WORKSPACE_ID
502+
|| (await prompt("Org ID: "));
479503

480504
const registrationToken = parsedArgs.registrationToken || (await prompt("Registration token: "));
481505

@@ -485,21 +509,21 @@ async function collectInputs(parsedArgs) {
485509

486510
return {
487511
brokerUrl: normalizeBrokerUrl(brokerUrl),
488-
workspaceId: workspaceId.trim(),
512+
orgId: orgId.trim(),
489513
registrationToken,
490514
configTargets,
491515
};
492516
}
493517

494518
export async function runRegistration({
495519
brokerUrl,
496-
workspaceId,
520+
orgId,
497521
registrationToken,
498522
fetchImpl = fetch,
499523
logger = () => {},
500524
}) {
501-
if (!validateWorkspaceId(workspaceId)) {
502-
throw new Error("workspace ID must match Slack team ID format (e.g. T0123ABCD)");
525+
if (!validateOrgId(orgId)) {
526+
throw new Error("org ID is required and must use only letters, numbers, '.', '_', ':', or '-'");
503527
}
504528

505529
if (!registrationToken) {
@@ -512,7 +536,7 @@ export async function runRegistration({
512536
const serverKeys = await generateServerKeyMaterial();
513537
const registration = await registerWithBroker({
514538
brokerUrl: normalizedBrokerUrl,
515-
workspaceId,
539+
orgId,
516540
registrationToken,
517541
serverKeys,
518542
fetchImpl,
@@ -521,7 +545,9 @@ export async function runRegistration({
521545

522546
const updates = {
523547
SLACK_BROKER_URL: normalizedBrokerUrl,
524-
SLACK_BROKER_WORKSPACE_ID: workspaceId,
548+
SLACK_BROKER_ORG_ID: orgId,
549+
// Keep workspace key for backward compatibility with older runtimes.
550+
SLACK_BROKER_WORKSPACE_ID: orgId,
525551
SLACK_BROKER_SERVER_PRIVATE_KEY: serverKeys.server_private_key,
526552
SLACK_BROKER_SERVER_PUBLIC_KEY: serverKeys.server_pubkey,
527553
SLACK_BROKER_SERVER_SIGNING_PRIVATE_KEY: serverKeys.server_signing_private_key,
@@ -615,7 +641,7 @@ export async function main(argv = process.argv.slice(2)) {
615641

616642
logger("Collecting registration inputs...");
617643
const input = await collectInputs(parsed);
618-
logger(`Using broker ${input.brokerUrl} for workspace ${input.workspaceId}`);
644+
logger(`Using broker ${input.brokerUrl} for org ${input.orgId}`);
619645
logger(`Config targets: ${input.configTargets.map((t) => t.path).join(", ")}`);
620646

621647
const { updates } = await runRegistration({ ...input, logger });
@@ -646,4 +672,4 @@ if (isMainModule()) {
646672
console.error(`❌ ${message}`);
647673
process.exit(1);
648674
});
649-
}
675+
}

0 commit comments

Comments
 (0)