Skip to content

Draft stable candidate: optional password and Slack code sign-in - #208

Draft
makeitfutureDev wants to merge 54 commits into
mainfrom
fix/password-slack-login
Draft

makeitfutureDev wants to merge 54 commits into
mainfrom
fix/password-slack-login

Conversation

@makeitfutureDev

@makeitfutureDev makeitfutureDev commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Exact stable candidate: 3be38e5. Integrates the optional password/private-Slack-code sign-in with current main cffe662 and preserves company-domain autoapproval, manual approval opt-out, linked-user dashboard authorization, and code-channel reply routing. Conflicts resolved without removing either function. The domain browser fixture now uses a real linked administrator session and authentication router.

This promotion still includes the existing beta changes beyond the sign-in checkbox: user-linked passkeys/recovery, admin/security hardening, SSH author runtime selection, Slack code channels/status alias, linked work folders, effort/activity labels, harness defaults, shared admin controls and Composio Workbench fixes. This is not a standalone hotfix. No tag, published release artifact or daemon restart is part of this PR.

Current candidate verification:

  • Local full coverage: 4,126 passed, 39 opt-in skipped, zero failed; coverage 93.90/86.56/90.28% lines/branches/functions.
  • Combined Chromium: 16 passed, zero skipped, including actual passkey signatures, bootstrap, alternate login/reauth/sign-out and domain preview/apply/manual revocation. Slack delivery is simulated.
  • Static, security coverage, secret scan, DCO and production audit at high threshold passed. Four moderate root dependency advisories remain; documentation audit has zero vulnerabilities.
  • Documentation build: 152 checked pages, 27,245 internal links and all 121 gateway controls documented.
  • Exact-candidate CI passed on 2026-10-30: full regression on Node 22.13 and 24, DCO and hygiene (CI, branch CI); documentation build; disposable Linux guest installation, actual reboot and uninstall, 7m10s. All six PR checks are green. Automated CI and browser fixtures do not substitute for the outstanding live acceptance or private QA registry.

Outstanding release gates:

  • Human real Slack-code/RustDesk and physical-authenticator acceptance has not been run. Applicable live beta gates have not been rerun for this stable promotion; 39 opt-in skips are not passes.
  • Private QA registry update remains missing: on 2026-10-30 requester personal Airtable discovery still reports no active connection. No identity substitution or connection initiation was performed.
  • User requested publication conditional on no adverse effects. This is not explicit deferral of the missing live checks. AGENTS.md/AGENTS.local.md require confirmation of this exact candidate and explicit deferral decisions for pending live checks before main publication.

The main PR is now mergeable. Its draft status reflects missing release gates, not unresolved merge conflicts. The served canonical checkout remains on beta with its unrelated original working changes untouched.

tbiyss and others added 30 commits October 23, 2026 12:05
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Security audit follow-up, first batch (no functionality removed for anyone
acting within policy):

- Slack Settings mode control: only an organization admin can switch a
  channel INTO Admin mode (the rule /mode admin and set_channel_admin_mode
  already enforce). A channel manager keeps every other control in an
  Admin-mode channel and may step it down; the picker lists "Admin" only to
  an admin or when it is the current mode.
- Case-variant URLs: Express case-sensitive routing plus lowercase-aware
  path guards, so /API/settings is refused like /api/settings instead of
  slipping past the Host/Origin guard, the lockdown and the 401 branch.
- Security headers: nosniff, X-Frame-Options DENY and Referrer-Policy on
  every response; a no-inline-script Content-Security-Policy on the admin
  shell (import map admitted by content hash) and the login page, whose
  handler moves to public/login.js.
- One Express error handler (bare status, no stack trace), NODE_ENV=production
  in the systemd unit, /resume behind the admin session, constant-time
  compare of the internal IPC secret.
- Background-job "Check status" button gated like /status and scoped to its
  channel; status() reports the job's slug.
- File explorer share / send-to-me / preview / edit re-prove the opened file
  under the channel root (O_NOFOLLOW + /proc/self/fd), closing the
  symlink-swap race the agent-side export tools already closed.
- License card escapes platform-supplied text.
- npm audit fix: undici, zod, hono, fast-uri, body-parser, ip-address.

Tests: test/web-hardening.test.js (new), test/access-settings.test.js
(updated for the admin-only rule). FEATURES, TEST-PLAN and CHANGELOG updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
… policy to Settings runtime controls

Security audit follow-up, batch 4 (Slack access consistency):

- Narrowing a channel's use policy from "approved" to "admins" or "none"
  now drops the approved members that were seeded into allowedUsers under
  the "approved" policy, keeping only explicit (un-approved) guests. Done
  inside the same metadata transaction by both the Slack Access control
  (save notice with the count, channel_access_members_evicted audit event)
  and the admin UI channel meta PUT. Widening back re-admits nobody by
  itself; the org-wide reset still clears the whole list. isAuthorized and
  the seeding under "approved" are unchanged.
- The Slack Settings runtime controls (channel engine / model / effort,
  thread pins, thread reset) follow the gateway's model-change policy like
  /model, the wizard, the shortcuts and the platform controls: a DM owner
  always; elsewhere a non-admin only under the "users" policy. The page
  renders the current values with the policy line instead of pickers, and
  the handlers refuse a crafted payload before any write.

Tests: test/access-policy-eviction-web.test.js and
test/settings-runtime-policy.test.js (new), test/access-settings.test.js
(appended), test/channel-settings-modal.test.js (runtime option now follows
the policy). FEATURES, TEST-PLAN and CHANGELOG updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…l failures

Security audit follow-up, batch 3. `clientKey` (the identity the admin login
and approval-link backoffs bucket on) used to believe CF-Connecting-IP and
the FIRST X-Forwarded-For hop for any request on a loopback socket — which is
every request behind nginx, caddy, cloudflared or ssh -L. A caller could mint
a fresh bucket per request by writing its own header: unlimited online
password guessing plus a free scrypt per attempt.

- New setting `trustProxy` (Settings → Connection → "Behind a reverse proxy";
  env CG_TRUST_PROXY; the setting wins): "" trusts nothing (the socket is the
  client), "cloudflare" reads CF-Connecting-IP only, "xff" reads the LAST
  X-Forwarded-For hop (the proxy's, never the client's first one). Legacy
  CG_TRUST_PROXY=1 maps to "xff"; unknown values trust nothing and the admin
  API refuses them with 400.
- createLoginLimiter gains a key-independent global cap (default 50 failures
  per 10 minutes → every attempt waits the maximum delay until the window
  drains), injectable for tests and switchable off.
- The /approve limiter inherits both through the shared helper. Nothing else
  authorizes on forwarded headers; the Secure-cookie decision still reads
  x-forwarded-proto (it only ever makes the cookie stricter).
- docs/OPERATIONS.md and INSTALL.md: declare the proxy, or all remote logins
  share one backoff bucket.

Tests: web-security (clientKey per mode, settings/env precedence, global
cap), settings-save-version (route validation + UI wiring),
approval-links (end-to-end through the approve router with and without a
declared proxy). FEATURES, TEST-PLAN, CHANGELOG updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…ons)

Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…ns only or Locked

Only the seeded approved NON-admin members are evicted. Admins are admitted by
role under "Admins only", and under "Locked" the admin who locks the channel
must not lock themselves out of its Slack controls.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
A code channel is a dedicated Slack channel for one task, opened through
Slack's agents.conversations API only when the requester asks for it and
only after they confirm an approval card. It is registered as a child of
the origin channel: the origin's folder, access policy, secrets, skills,
engine and switches are re-projected onto it on every message and spawn,
while it keeps its own Slack identity, sessions and container.

The whole channel is one session (key `code-channel`, never a Slack ts),
so replies post top-level or in the thread a person used, the mention
gate admits every message there, the session status is addressed by
channel id without the legacy thread bridge, and a thread-less
agent_session_stopped sweeps everything running in the channel.

When the origin folder is a git repository the daemon creates branch
code/<slug> in a worktree at .worktrees/<slug> (from the upstream, else
the exact HEAD commit) and publishes its diff to the Code tab after each
turn, leaving out the gateway's managed instruction block; otherwise the
channel works in place. The requester may force either mode. The first
turn is started by the daemon with the task as the brief and the origin
thread as context. update_code_channel publishes html/block_kit/canvas/
pull_request tabs, context-bar items and the title; archive_code_channel
posts the wrap-up and archives behind an open-tier card.

Manifest: features.code_channels + the code_channels:manage scope.
Slack-only capability `codeChannels`; Slack-only guide reference.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…sections)

Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…es on public links

Security audit follow-up, batch 2.

Work-folder boundary (src/gateway/workdir-boundary.js): whatever the
allowlisted fsRoot admits, a channel's custom work folder may not be the
gateway account's home itself, the gateway runtime root or anything inside
it, ~/.ssh, ~/.claude, ~/.codex, the container engine's config or storage,
the hidden runtime artifact trees, the ChannelGate workspace root or one of
its platform folders, another conversation's work folder (default or
custom), or a parent of any of those. A subfolder of another conversation's
folder and the channel's own folders stay allowed. Enforced with a named
reason by set_channel_workdir, the admin UI workDir field and the runtime
resolver (an already-stored forbidden value fails every spawn closed with
the remedy); folder provisioning falls back to the default folder; one boot
warning per offending channel.

Protected export names: the shared export door (openConfinedFile) refuses a
hidden file or directory anywhere in the path, the managed .claude tree and
credential-shaped names, by requested AND physical path, for both public
link purposes, slack_share_file, Composio staging and previously minted
links. In-conversation previews (Slack explorer, Teams and Google Chat file
windows) are unchanged.

Two tests moved their custom work-folder fixtures beside the scratch gateway
root instead of under it, which is what the boundary now refuses.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
… door

Keep functionality admins rely on while closing the audit holes:

- Another conversation's CUSTOM work folder (two channels on one repository),
  its parent and its subfolders stay allowed; only the gateway-made default
  folders, the gateway's own trees and the home itself are refused.
- The protected-name export policy gets two strengths: strict for public
  links (hidden paths, managed instruction/memory files, credential-shaped
  and secret-mentioning names) and lenient for slack_share_file, the footer
  download, Composio staging and mail attachments (hidden paths and
  credential-shaped files only), so MEMORY.md or a token-usage report can
  still be sent where an authorized person already reaches.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…c sections)

Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
tbiyss and others added 24 commits October 25, 2026 23:38
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Slack rejects /status in some app manifests as a built-in command. The
same handler now answers /status-cg, so a named agent's manifest can
register that name and keep the channel status report.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
# Conflicts:
#	CHANGELOG.md
#	FEATURES.md
#	TEST-PLAN.md
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
A code channel shares its origin's folder, so the shared-folder grant
guard compared the two channels' skill sets; catalog skills scoped to the
origin's channel id were missing on the child's id and the first live
open_code_channel failed after Slack had created the channel. Scoped
skills now resolve through the origin for a code channel.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
…l docs

Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>
Signed-off-by: Tiberiu Socaci <tsocaci@makeitfuture.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants