Summary
Add setup handlers to the webhook service that automate Slack app creation and OAuth installation. After setup, the service is ready to receive Slack events with no manual credential handling beyond the initial config token.
The flow:
- Operator generates a config token at
api.slack.com (manual, one-time).
GET /setup/slack — operator pastes config token into a form.
POST /setup/slack — server calls apps.manifest.create, writes credentials to Secret Manager, redirects operator to Slack's OAuth install page.
GET /slack/callback — exchanges OAuth code for a bot token, writes it to Secret Manager, renders success page.
Context
- No Terraform, Secret Manager client, or setup flow exists yet.
- Signature verification (
internal/slack/verify.go) already exists and is wired into the webhook service.
What to build
1. Terraform: Secret Manager secrets and IAM bindings
Create terraform/secrets.tf with five secrets:
threadops-slack-config-token
threadops-slack-client-id
threadops-slack-client-secret
threadops-slack-signing-secret
threadops-slack-bot-token
Grant the webhook service account secretAccessor and secretVersionAdder on all five. Expose SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET as env vars on the Cloud Run service (resolved from Secret Manager).
2. Secret Manager client wrapper
Create internal/secretsmanager/client.go with typed read/write methods for each Slack secret. Uses the cloud.google.com/go/secretmanager SDK.
3. Slack app manifest
Create internal/slacksetup/manifest.go — a Manifest(baseURL string) function returning the app manifest as map[string]any. Scopes: app_mentions:read, channels:history, groups:history, chat:write.
4. Setup HTTP handlers
Create internal/slacksetup/handler.go with three handlers:
ServeSetupForm (GET /setup/slack) — renders form for config token input. Protected by THREADOPS_SETUP_TOKEN.
ServeCreateApp (POST /setup/slack) — calls apps.manifest.create, writes credentials to Secret Manager, redirects to OAuth URL.
ServeOAuthCallback (GET /slack/callback) — exchanges code via oauth.v2.access, writes bot token to Secret Manager, renders success page.
5. Route registration
Modify services/webhook/main.go to register the three setup routes behind a THREADOPS_SETUP_ENABLED=true check.
6. Config token rotation (optional / follow-up)
internal/slacksetup/rotation.go — utility to rotate expiring config tokens via tooling.tokens.rotate. Requires an additional threadops-slack-config-refresh-token secret. Can be deferred to a follow-up issue.
Security considerations
- Setup routes gated by
THREADOPS_SETUP_TOKEN (query param or cookie).
/slack/callback is self-protecting (requires valid single-use OAuth code) but should also be behind the setup-enabled check.
- Operator must complete the full flow in one session while setup is enabled, then disable it and redeploy.
Test plan
Summary
Add setup handlers to the webhook service that automate Slack app creation and OAuth installation. After setup, the service is ready to receive Slack events with no manual credential handling beyond the initial config token.
The flow:
api.slack.com(manual, one-time).GET /setup/slack— operator pastes config token into a form.POST /setup/slack— server callsapps.manifest.create, writes credentials to Secret Manager, redirects operator to Slack's OAuth install page.GET /slack/callback— exchanges OAuth code for a bot token, writes it to Secret Manager, renders success page.Context
internal/slack/verify.go) already exists and is wired into the webhook service.What to build
1. Terraform: Secret Manager secrets and IAM bindings
Create
terraform/secrets.tfwith five secrets:threadops-slack-config-tokenthreadops-slack-client-idthreadops-slack-client-secretthreadops-slack-signing-secretthreadops-slack-bot-tokenGrant the webhook service account
secretAccessorandsecretVersionAdderon all five. ExposeSLACK_BOT_TOKENandSLACK_SIGNING_SECRETas env vars on the Cloud Run service (resolved from Secret Manager).2. Secret Manager client wrapper
Create
internal/secretsmanager/client.gowith typed read/write methods for each Slack secret. Uses thecloud.google.com/go/secretmanagerSDK.3. Slack app manifest
Create
internal/slacksetup/manifest.go— aManifest(baseURL string)function returning the app manifest asmap[string]any. Scopes:app_mentions:read,channels:history,groups:history,chat:write.4. Setup HTTP handlers
Create
internal/slacksetup/handler.gowith three handlers:ServeSetupForm(GET /setup/slack) — renders form for config token input. Protected byTHREADOPS_SETUP_TOKEN.ServeCreateApp(POST /setup/slack) — callsapps.manifest.create, writes credentials to Secret Manager, redirects to OAuth URL.ServeOAuthCallback(GET /slack/callback) — exchanges code viaoauth.v2.access, writes bot token to Secret Manager, renders success page.5. Route registration
Modify
services/webhook/main.goto register the three setup routes behind aTHREADOPS_SETUP_ENABLED=truecheck.6. Config token rotation (optional / follow-up)
internal/slacksetup/rotation.go— utility to rotate expiring config tokens viatooling.tokens.rotate. Requires an additionalthreadops-slack-config-refresh-tokensecret. Can be deferred to a follow-up issue.Security considerations
THREADOPS_SETUP_TOKEN(query param or cookie)./slack/callbackis self-protecting (requires valid single-use OAuth code) but should also be behind the setup-enabled check.Test plan
Manifest()output structure and URL construction