refactor(slack): single source of truth for app manifest scopes#2232
refactor(slack): single source of truth for app manifest scopes#2232amikofalvy merged 5 commits intomainfrom
Conversation
🦋 Changeset detectedLatest commit: 9b79185 The changes in this PR will be included in the next version bump. This PR includes changesets to release 10 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This PR successfully consolidates Slack OAuth bot scopes from three divergent sources into a single source of truth: slack-app-manifest.json. The implementation is clean, follows existing codebase patterns, and eliminates the drift risk that led to unwanted im:* scopes in the OAuth flow.
🟡 Minor (0) 🟡
No issues meet the Minor threshold. All findings are cosmetic improvements in the "Consider" category.
💭 Consider (3) 💭
Inline Comments:
- 💭 Consider:
slack-scopes.ts:3Add defensive access for clearer error messages on manifest structure issues - 💭 Consider:
setup-slack-dev.ts:458-460Log the actual parse error when .slack-dev.json is corrupted - 💭 Consider:
setup-slack-dev.ts:762-764Log the actual token rotation error instead of assuming expiration
🧹 While You're Here (0) 🧹
No pre-existing issues surfaced during review.
✅ APPROVE
Summary: This is a well-executed refactor that achieves its stated goal of eliminating scope drift. The code is clean, follows existing patterns (JSON import syntax, constant naming conventions, tsconfig settings match sibling packages), and the enhanced setup-slack-dev.ts provides valuable developer feedback on manifest changes and scope drift. The inline suggestions are minor quality-of-life improvements for error messages — none block approval. Ship it! 🚀
Discarded (12)
| Location | Issue | Reason Discarded |
|---|---|---|
slack-scopes.ts:3 |
BOT_SCOPES is readonly string[] not literal type |
Design tradeoff — literal types would duplicate manifest data, conflicting with single-source-of-truth goal |
setup-slack-dev.ts:267-292 |
SlackDevConfig has all optional fields | Script uses sequential flow that guarantees fields are set; discriminated union adds complexity for a dev tool |
setup-slack-dev.ts:353-361 |
loadManifest() uses type assertion | Script already checks file existence before calling; full Zod validation would be over-engineering for dev tool |
setup-slack-dev.ts:472-477 |
ManifestDiff interface not discriminated union | Cosmetic type refinement; current implementation handles all cases correctly |
setup-slack-dev.ts:454-461 |
loadDevConfig() uses type assertion without validation | Graceful fallback to {} already exists; additional validation adds complexity |
setup-slack-dev.ts:353-362 |
loadManifest() doesn't catch file read errors separately | Pre-check with existsSync(MANIFEST_PATH) mitigates this; file unreadable is rare edge case |
setup-slack-dev.ts:891-895 |
Non-null assertions on clientId/clientSecret | Code flow guarantees these are set (either from existing config or createApp response) |
setup-slack-dev.ts:364-366 |
getManifestBotScopes returns empty array silently | Intentional graceful degradation; zero scopes would fail at Slack OAuth with clear error |
setup-slack-dev.ts:346-351 |
openBrowser fires and forgets | Dev tool context; browser not opening triggers 120s timeout with clear message; also prints URL |
slack/index.ts |
New module not re-exported from barrel | Intentional — scopes are package-internal; setup script reads manifest directly |
tsconfig.json |
resolveJsonModule change | Informational — follows established pattern in 6+ other packages |
| Multiple | JSON import pattern, constant naming | Informational — all follow existing conventions |
Reviewers (5)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-errors |
7 | 0 | 0 | 0 | 3 | 0 | 4 |
pr-review-types |
5 | 0 | 0 | 0 | 0 | 0 | 5 |
pr-review-consistency |
5 | 0 | 0 | 0 | 0 | 0 | 5 |
pr-review-devops |
4 | 0 | 0 | 0 | 0 | 0 | 4 |
pr-review-standards |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 21 | 0 | 0 | 0 | 3 | 0 | 18 |
Note: pr-review-standards found no issues. The 3 inline comments are from pr-review-errors findings that were routed as Consider-level suggestions.
| @@ -0,0 +1,5 @@ | |||
| import manifest from './slack-app-manifest.json' with { type: 'json' }; | |||
|
|
|||
| export const BOT_SCOPES: readonly string[] = manifest.oauth_config.scopes.bot; | |||
There was a problem hiding this comment.
💭 Consider: Add defensive access for clearer error messages
Issue: Direct property access at module load time produces cryptic errors if the manifest structure changes.
Why: If oauth_config.scopes.bot is missing/renamed, the error is Cannot read properties of undefined with no indication of which file or field is wrong. Since this is version-controlled and would fail CI immediately, the risk is low — but the error message improvement costs little.
Fix: Optional defensive access:
const botScopes = manifest?.oauth_config?.scopes?.bot;
if (!Array.isArray(botScopes)) {
throw new Error(
'Invalid slack-app-manifest.json: oauth_config.scopes.bot must be an array'
);
}
export const BOT_SCOPES: readonly string[] = botScopes;Refs:
| } catch { | ||
| console.log(fmt.warn('Warning: .slack-dev.json is corrupted, starting fresh.')); | ||
| return {}; |
There was a problem hiding this comment.
💭 Consider: Log the actual parse error for easier debugging
Issue: When .slack-dev.json is corrupted, the warning doesn't include what went wrong.
Why: If the JSON has a specific issue (trailing comma, encoding problem), users can't diagnose it without manually inspecting the file.
Fix:
| } catch { | |
| console.log(fmt.warn('Warning: .slack-dev.json is corrupted, starting fresh.')); | |
| return {}; | |
| } catch (err) { | |
| const errMsg = err instanceof Error ? err.message : String(err); | |
| console.log(fmt.warn(`Warning: .slack-dev.json is corrupted (${errMsg}), starting fresh.`)); |
Refs:
- Similar error-with-context pattern used in loadManifest():357-360
|
This pull request has been automatically marked as stale because it has not had recent activity. If this PR is still relevant:
Thank you for your contributions! |
Bot OAuth scopes were hardcoded in three divergent locations (manifest JSON, oauth.ts, setup-slack-dev.ts) with the OAuth flows including unwanted im:* scopes not present in the manifest. This consolidates everything to derive from slack-app-manifest.json as the single canonical source. - Add slack-scopes.ts module that exports bot scopes from the manifest JSON - Replace hardcoded scope array in oauth.ts with manifest-derived import - Refactor setup-slack-dev.ts: typed SlackDevConfig interface, manifest-derived scopes, full manifest diff on re-run, auto-detect scope drift and trigger OAuth re-install when scopes change - Add resolveJsonModule to agents-work-apps tsconfig - Remove unwanted im:history, im:read, im:write scopes (never used) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fb7ae66 to
945806b
Compare
Rebased on latest mainThis PR is still highly relevant — the scope divergence problem has gotten worse since it was opened:
PRs #2366 and #2585 each updated some files but not all — exactly the drift pattern this PR prevents. After this merge, all three locations derive scopes from
|
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This PR successfully consolidates Slack OAuth bot scopes from three divergent sources into a single source of truth: slack-app-manifest.json. The implementation is clean, follows existing codebase patterns, and eliminates the drift risk that led to scope inconsistencies across oauth.ts, setup-slack-dev.ts, and the manifest.
🔴❗ Critical (0) ❗🔴
None.
🟠⚠️ Major (0) 🟠⚠️
None.
🟡 Minor (0) 🟡
None.
💭 Consider (0) 💭
None — no new findings.
🕐 Pending Recommendations (3)
Prior review suggestions that remain applicable:
- 💭
slack-scopes.ts:3Add defensive access for clearer error messages on manifest structure issues - 💭
setup-slack-dev.ts:459Log the actual parse error when.slack-dev.jsonis corrupted - 💭
setup-slack-dev.ts:763Log the actual token rotation error instead of assuming expiration
These remain "Consider" level suggestions — they improve error message clarity but don't block approval.
✅ APPROVE
Summary: This is a well-executed refactor that achieves its stated goal of eliminating scope drift. The rebased code is clean, all 5 dispatched reviewers found zero new issues, and the enhanced setup-slack-dev.ts provides valuable developer feedback on manifest changes and scope drift detection. The author's comment highlighting that scope divergence has gotten worse since the PR was opened (with specific examples of PRs #2366 and #2585 updating some files but not all) underscores the value of this consolidation. Ship it! 🚀
Discarded (0)
No findings were discarded.
Reviewers (5)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-standards |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-consistency |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-types |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-devops |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-errors |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Note: All reviewers confirmed the code is clean. The 3 pending recommendations are from the prior review run (2026-02-21) and remain valid but non-blocking.
Documents the single-source-of-truth pattern for bot scopes so developers and AI agents know to only edit slack-app-manifest.json when adding or removing scopes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
PR Review Summary
(1) Total Issues | Risk: Low
This delta review covers only the changes since the last automated review: a documentation addition to README.md describing the Slack bot scope management pattern. The documentation is accurate, well-structured, and correctly explains the single-source-of-truth pattern.
🔴❗ Critical (0) ❗🔴
None.
🟠⚠️ Major (0) 🟠⚠️
None.
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
README.md:196-199File Structure section missingslack-scopes.tsentry
💭 Consider (0) 💭
None.
🕐 Pending Recommendations (3)
Prior review suggestions that remain applicable:
- 💭
slack-scopes.ts:3Add defensive access for clearer error messages on manifest structure issues - 💭
setup-slack-dev.ts:459Log the actual parse error when.slack-dev.jsonis corrupted - 💭
setup-slack-dev.ts:763Log the actual token rotation error instead of assuming expiration
These remain "Consider" level suggestions — they improve error message clarity but don't block approval.
💡 APPROVE WITH SUGGESTIONS
Summary: The documentation addition is solid — it accurately describes the scope management pattern with a clear ASCII diagram and actionable instructions. The only finding is a minor internal consistency issue: the File Structure section should include slack-scopes.ts since it's introduced as a key file in the new section. This is a quick fix (add 1-2 lines to the file listing). The prior "Consider" suggestions from the first review remain valid but non-blocking. Ship it after the minor fix! 🚀
Discarded (0)
No findings were discarded.
Reviewers (2)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-docs |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-consistency |
1 | 0 | 0 | 0 | 1 | 0 | 0 |
| Total | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
Note: The 3 pending recommendations are from the prior review run (2026-02-21) and remain valid but non-blocking.
Agents always have CLAUDE.md in context but won't discover a deeply nested README. Keep the README as a brief pointer with the diagram. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
PR Review Summary
(1) Total Issues | Risk: Low
This delta review covers only the changes since the last automated review: documentation moved from README.md to AGENTS.md (commit 6c33ef56b). The documentation changes are well-structured and the AGENTS.md placement is appropriate.
🔴❗ Critical (0) ❗🔴
None.
🟠⚠️ Major (0) 🟠⚠️
None.
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
README.md:170-182File Structure section missingslack-scopes.tsentry
💭 Consider (0) 💭
None.
🕐 Pending Recommendations (3)
Prior review suggestions that remain applicable:
- 💭
slack-scopes.ts:3Add defensive access for clearer error messages on manifest structure issues - 💭
setup-slack-dev.ts:459Log the actual parse error when.slack-dev.jsonis corrupted - 💭
setup-slack-dev.ts:763Log the actual token rotation error instead of assuming expiration
These remain "Consider" level suggestions — they improve error message clarity but don't block approval.
ℹ️ Ito Test Report Note
The Ito test report shows 2 failures (EDGE-2, EDGE-3) related to tenant ID encoding in OAuth callback redirects. Both failures are flagged as pre-existing bugs not introduced by this PR — the affected code path (oauth.ts lines 187-199) wasn't modified in this PR. The tenant ID is interpolated into the redirect URL without proper encoding, which can cause path traversal issues with encoded slashes or reserved characters.
💡 APPROVE WITH SUGGESTIONS
Summary: The documentation restructuring is well-executed — moving the detailed scope management guidance to AGENTS.md (the canonical location for AI coding agent instructions) while keeping a brief summary in the README is the right approach. The one minor finding (File Structure section missing slack-scopes.ts) is a quick 1-line fix for internal consistency. The 3 prior "Consider" suggestions remain valid but non-blocking. Ship it after adding slack-scopes.ts to the file listing! 🚀
Discarded (0)
No findings were discarded.
Reviewers (1)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-docs |
1 | 0 | 0 | 0 | 1 | 0 | 0 |
| Total | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
Note: Delta review — only docs reviewer dispatched for documentation-only changes. The 3 pending recommendations are from the initial review run (2026-02-21) and remain valid but non-blocking.
Replace the AGENTS.md section and README scope guide with a proper skill that agents discover via trigger words (slack scope, bot scope, slack manifest, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This delta review covers only the changes since the last automated review (commit 6c33ef56b): moving Slack scope management documentation from inline locations (AGENTS.md, README.md) to a dedicated skill file (.agents/skills/slack-manifest/SKILL.md).
🔴❗ Critical (0) ❗🔴
None.
🟠⚠️ Major (0) 🟠⚠️
None.
🟡 Minor (0) 🟡
None.
💭 Consider (0) 💭
None.
🕐 Pending Recommendations (4)
Prior review suggestions that remain applicable:
- 💭
slack-scopes.ts:3Add defensive access for clearer error messages on manifest structure issues - 💭
setup-slack-dev.ts:459Log the actual parse error when.slack-dev.jsonis corrupted - 💭
setup-slack-dev.ts:763Log the actual token rotation error instead of assuming expiration - 🟡
README.mdFile Structure Addslack-scopes.tsentry to the File Structure section
These remain non-blocking suggestions — they improve error message clarity and documentation completeness but don't block approval.
ℹ️ Ito Test Report Note
The Ito test report shows 2 failures (EDGE-2, EDGE-3) related to tenant ID encoding in OAuth callback redirects. Both failures are flagged as pre-existing bugs not introduced by this PR — the affected code path (oauth.ts lines 187-199) wasn't modified in this PR.
✅ APPROVE
Summary: This delta is a clean documentation restructuring — moving Slack scope management guidance from inline docs (AGENTS.md, README.md) to a dedicated skill file (.agents/skills/slack-manifest/SKILL.md). The new skill is well-structured with clear trigger keywords, accurate file references, and actionable guidance. Both dispatched reviewers (docs, devops) found zero new issues. The 4 pending recommendations from prior reviews remain valid but non-blocking. Ship it! 🚀
Discarded (0)
No findings were discarded.
Reviewers (2)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-docs |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-devops |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Note: Delta review — only 2 reviewers dispatched for docs/skill-only changes. All reviewers confirmed the changes are clean. The 4 pending recommendations are from prior review runs and remain valid but non-blocking.
Ito Test Report ❌16 test cases ran. 15 passed, 1 failed. 🔍 Verification focused on Slack OAuth install/callback behavior and dashboard handling. Most included checks passed end-to-end, and one security defect was confirmed through source inspection: callback redirects build a tenant path from unvalidated state data, allowing tenant-path injection instead of constraining redirects to a safe dashboard route. ✅ Passed (15)
❌ Failed (1)
tenant_id injection payload cannot hijack redirect destination – Failed
📋 View Recording |








































Summary
slack-app-manifest.json,oauth.ts, andsetup-slack-dev.tsall had independent scope lists that had drifted (oauth.tsmissing 5 scopes,setup-slack-dev.tsmissing 8 scopes vs manifest)slack-scopes.tsmodule exports scopes from the manifest;oauth.tsimports from it;setup-slack-dev.tsreads from the parsed manifestsetup-slack-dev.tsnow stores the full applied manifest in.slack-dev.json, diffs on re-run, and shows developers exactly what changedinstalledBotScopesin.slack-dev.jsonand compares against the manifest on re-runslack-manifestskill — agentic documentation so AI coding agents know to edit onlyslack-app-manifest.jsonwhen modifying scopes, events, or commandsRecord<string, string>with a typedSlackDevConfiginterfaceFiles changed
packages/agents-work-apps/tsconfig.jsonresolveJsonModule: truepackages/agents-work-apps/src/slack/slack-scopes.tsBOT_SCOPESandBOT_SCOPES_CSVfrom manifestpackages/agents-work-apps/src/slack/routes/oauth.tsBOT_SCOPES_CSVimportscripts/setup-slack-dev.ts.agents/skills/slack-manifest/SKILL.mdTest plan
pnpm typecheckpasses (16/16 tasks)oauth.tsandsetup-slack-dev.ts)setup-slack-dev.tsfresh (delete.slack-dev.json) — verify scopes come from manifestsetup-slack-dev.tsagain with no changes — verify "up to date" message🤖 Generated with Claude Code