Prune Slack, Telegram, headscale from CE

Task 11147 · Done · Coder · created · updated

Epic: Security audit of development keys and container artifacts. This child = Architecture C4 (PRD R4 for the slack/telegram/headscale families, API and console; operator A2 included the console). ## Original requirement (verbatim, epic body) - "2. The mirror build should prune the `aws/`, Slack, Telegram and headscale code it does not need. That reduces both the copying surface and what attackers learn." - "It should not break anything in prod or dev" This child cuts Slack, Telegram and headscale. `aws/` is cut by later children: one drops the CE S3/KMS options, and the aws cut runs in phase 2. ## Approach (Architecture C4) The prune is a feature-map change. `build_tree.derive` already excludes lacking features' `paths` (`tools/community_edition/build_tree.py:68-78`), and `check_tree.py`'s import walk honours `edition_features.enabled` guards (:143-162). - `packages/editions/features.toml`: - `[feature.slack]` paths += `apps/api/app/slack_*.py`, `apps/api/app/durable/slack_echo.py`, `apps/web/src/lib/slackWorkspace.ts`, `apps/web/src/components/SlackConnect.tsx`, `apps/web/src/components/SlackWorkspaceCard.tsx`. - `[feature.telegram]` paths = `apps/api/app/telegram_*.py`, `apps/web/src/pages/settings/telegram/**`. - `[feature.tailnet]` paths += `apps/api/app/headscale_*.py`. - Keep one feature per path. - Drop `headscale_bootstrap.py` from the `carried` list (`tools/community_edition/manifest.toml:394`). - Guard every shared importer under `edition_features.enabled("<slug>")`, or use an early return at the call site: - Telegram, top-level: `alert_record.py:24`, `user_notify.py:31`, `comment_notify.py:22`, `budgets.py:33`, `trigger_notices.py:28`, `governance/notify.py:22`, `routes/settings.py:23`, `routes/credentials/writes.py:21`, `routes/auth.py:37-38`. - Telegram, lazy: `notify_targets.py:711,839`, `durable/notify_outbox.py:442`, `routes/public.py:292,334`. - Slack, top-level: `alert_relay.py:26,31`, `routes/auth.py:36`, `routes/access_requests.py:23`, `routes/tasks/answers.py:20`. - Slack, lazy: `notify_targets.py:667,758,1084`, `trigger_intake.py:556,673`, `site_enquiry.py:413`, `org_names.py:45`, `routes/tasks/qa_render.py:682`, `routes/tasks/answers.py:326,346`. - Headscale: `routes/nodes/register.py:14`, plus `durable/cloud_node.py:280`, `durable/bootstrap_key.py:34` and `vnodes.py:928-946` if they ship. `cron_system_activities.py:611,974,1034` go under `enabled("tailnet")`. - Small pure helpers that shared code needs (`slack_blocks._has_glyph`, `slack_egress.NO_UNFURL`) move into the shared module that uses them. - Console: - Shared pages: `ProfilePage.tsx:25`, `settings/ownOrg/OwnOrgPanels.tsx:10`, `Settings.tsx:32`, `settings/KnobSection.tsx:36`, `components/NotificationsPanel.tsx`. - Load cut files only where present (`apps/web/src/lib/cloudSurfaces.ts`, as `settingsCloud.tsx` does), or move them into `settingsCloud.tsx`/`routesCloud.tsx`. A static import of a cut file breaks `tsc -b` on the tree. - `KnobSection`'s `TELEGRAM_BOT_KEY`/`isTokenRefused` move to a shared lib, or the knob row hides behind `isEnabled('telegram')`. - `notify_targets` must skip a stored `methods` entry whose channel type is disabled or unknown (slack/telegram on CE) rather than raise. - Kept as one child: the Architect settled C4 as one boundary, and the API and console cuts share the same `features.toml` paths, so splitting them would leave one half unbuildable. ## PRD R4 — CE mirror prunes aws/, Slack, Telegram, headscale (N2; D2, D5) — this child's ACs, verbatim - AC4.1 The built CE tree contains no file under `apps/api/app/aws/`, no `apps/api/app/slack_*`, `telegram_*`, `headscale_*` module, and nothing that exists only to serve them (e.g. `apps/api/app/bedrock/`, which needs `aws/` and serves cloud-only `jaah_ai_credit`). (This child: the slack_*/telegram_*/headscale_* part.) - AC4.2 No shipped file imports a pruned module (the CE import-closure check / CE tests pass). - AC4.5 The cloud edition loses nothing: Slack, Telegram, tailnet, cloud nodes, S3, KMS, Bedrock still work on dev. Credentials & reach: - Quick/full gate, pytest, CE tree build + `check_tree`, installer harness, tree console build | Worktree only (`./dc`, `tools/community_edition/*.py` present) | verified — files present on h2; no credential needed - Tree console build `npm ci` (C4) | npm registry | verified — `registry.npmjs.org` answered 200 from h2 - PR checks / merge lane / Jaah Deploy run status | `jaah-forge` (pre-authenticated for the task) | verified — read verb `pr list` succeeded from h2 - Dev console boots, sign-in, Slack/Telegram settings, attachment upload (AC2.3, AC4.5, AC9.2) | `org/console/dev-login` (credential_get succeeded); environment: dev control plane | **deferred** to a node with reach. dev timed out from h2 (prod `app.jaah.ai` answered 200). Operator answer A5: a green Jaah Deploy is the gate, and the browser check runs on a node that reaches dev; a builder without reach records it deferred Out of scope: PRD §5, verbatim: - Do NOT change `infra/community-edition/node/install_clis.sh`'s vendor `curl https://claude.ai/install.sh | bash` (D8; deferred follow-up). - Do NOT sign or digest-pin the cloud deploy images pushed by Jaah Deploy, nor add deploy-time verification (D3 chose CE + base images only). - Do NOT add a CI/terraform guard over ECS env (D7 verify-only). - Do NOT cosign-sign `SHA256SUMS` (D4). - Do NOT remove Slack, Telegram, headscale, AWS, KMS, S3 or Bedrock from the cloud edition — the prune is CE-tree only. - Do NOT change the session-secret / dev-seed / insecure-agent refusals' semantics or the `FIXTURE_APP_ENVS` set. - Do NOT touch `infra/jaah/terraform` resources (only read them for R2). - Do NOT change port binds, setup-loopback rule, cookie flags or rate limits (A6 positives). - Architecture boundary: no `aws/` guards or `[feature.aws]` row (sibling children); no new build-tool mechanism or manifest `exclude` globs; never hide a module with `carried`, `[[sensitive.allow]]` or `try/except ImportError` (guard theatre). Done means: - AC4.1 — build the CE tree (`tools/community_edition/build_tree.py` via the mirror engine) and `find <tree> -name 'slack_*' -o -name 'telegram_*' -o -name 'headscale_*'` prints nothing; a new `tools/tests/test_community_edition.py` case pins it; `check_tree.py` fails if any reappears; no new `carried`/`[[sensitive.allow]]` entry and no `except ImportError` guard added. - AC4.2 — `check_tree.py` green (imports, features, orphans); the mirror engine's strict check for `jaah-ce` green; `pytest tools/tests/test_community_edition.py` green; in the built tree the console passes `npm ci && npm run build`; the tree's api migrates and answers `/api/health` (the `mirrors.yml` `ce-tree` job steps run locally). - CE robustness — pytest: a CE user with a stored slack/telegram `methods` row gets notifications on the remaining channels and nothing raises. - AC4.5 — full gate green; on dev, open Settings → Slack and Telegram sections render (browser part deferred — dev unreachable from h2; operator A5: green Jaah Deploy is the gate). - AC9.1 `./dc check quick` green on the branch; merge lane `./dc check full` green. - AC9.2 The PR's Jaah Deploy succeeds to dev; dev console loads and a user can sign in.

Outcome

CE tree now prunes slack_/telegram_/headscale_ modules + Slack/Telegram console files; shared importers guarded, cloud unchanged. CE check 0 findings, quick gate green, PR #7290 queued. Dev browser check deferred (A5). Memory: flagged mem-30201.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)