Skip to content

🤖 feat: per-project trust confirmation for hooks and scripts#2598

Merged
ibetitsmike merged 67 commits intomainfrom
mike/project-trust-confirmation
Feb 27, 2026
Merged

🤖 feat: per-project trust confirmation for hooks and scripts#2598
ibetitsmike merged 67 commits intomainfrom
mike/project-trust-confirmation

Conversation

@ibetitsmike
Copy link
Contributor

@ibetitsmike ibetitsmike commented Feb 24, 2026

Summary

Replace the passive trust banner with an interactive confirmation dialog at workspace creation time. When a user creates a workspace for an untrusted project, a modal asks for explicit trust confirmation before proceeding. Adds defense-in-depth trust gates across all workspace creation paths: the primary UI hook, the backend workspaceService, and the taskService (sub-agent task spawning).

Background

The existing trust system silently skipped hooks for untrusted projects — the user saw "Skipping .mux/init hook (project not trusted)" buried in init logs with no prior warning. This is confusing UX and doesn't enforce the security boundary at the point of action.

Implementation

Frontend: Interactive trust dialog

  • useCreationWorkspace.ts — Adds a promise-based trust gate in handleSend. When the project is untrusted, execution pauses via await new Promise<boolean>() while a ConfirmationModal asks the user to confirm. The stored resolve function is invoked on user action (Trust/Cancel).
  • ChatInput/index.tsx — Renders creationState.trustDialog in the component tree.
  • ProjectPage.tsx — Removes the passive ProjectTrustBanner (replaced by the dialog).
  • Race condition guard — Skips the frontend trust check while ProjectContext is still loading project data, preventing false-positive trust dialogs. The backend gate provides defense-in-depth.
  • Reconnect resilience — The modal stays mounted even if api becomes null during a backend reconnect. The onConfirm handler's try/catch handles stale API references gracefully.

Backend: Defense-in-depth trust gates

  • workspaceService.tscreate() and fork() reject with a structured error if the project is untrusted, catching secondary creation paths (slash commands, forking).
  • taskService.ts — Trust gates in both create() (immediate task path) and maybeStartQueuedTasks() (dequeue path) block sub-agent task workspace creation for untrusted projects, including pre-existing queued tasks from before the gate was added.
  • initHook.ts — Downgrades the "skipping init hook" log to debug since it's now only a defense-in-depth path.

Test infrastructure

  • Comprehensive test harness updates: createSharedRepo(), createAppHarness(), ACP integration tests, smoke test script, and 6 standalone test files now explicitly trust projects before workspace creation.
  • Unit tests for the backend trust gates in workspaceService.test.ts and trust dialog behavior in useCreationWorkspace.test.tsx.
  • taskService.test.ts updated with trusted: true in all project config mocks.

CLI

  • mux run ephemeral config now copies only the projects map with trusted state, stripping workspace/task metadata to avoid stale task count interference.

Risks

  • Low: The backend trust gates return structured errors that existing !result.success toast handlers already surface. No new error display paths needed.
  • Medium: The taskService trust gate blocks sub-agent task spawning for untrusted projects. In upgraded installs with pre-existing workspaces created before this change, any queued tasks for untrusted projects will be silently skipped with a warning log. This is the intended security behavior.

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $77.65

@ibetitsmike
Copy link
Contributor Author

@codex review

@ibetitsmike ibetitsmike force-pushed the mike/project-trust-confirmation branch from fbf9a51 to 5bbff1d Compare February 24, 2026 16:25
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbf9a5193f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Addressed both review comments:

  1. WorktreeManager.ts — Already resolved during rebase. Now uses execFileAsync with env option (GIT_NO_HOOKS_ENV object) instead of shell prefix. No Windows shell compatibility issue.

  2. DockerRuntime.ts — Added gitNoHooksPrefix to both checkout paths:

    • provisionContainer checkout (initWorkspace flow)
    • forkWorkspace checkout (fork flow)

    Both use shell strings via this.exec() / runDockerCommand() running in bash inside Docker containers, so the POSIX env prefix is appropriate here.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 240477bb49

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Addressed the remaining thread:

  • WorktreeManager.forkWorkspace: Now passes params.trusted to this.createWorkspace()
  • WorktreeRuntime.createWorkspace: Now passes params.trusted to worktreeManager.createWorkspace()
  • DevcontainerRuntime.createWorkspace: Now passes params.trusted to worktreeManager.createWorkspace()

All callers of worktreeManager.createWorkspace() now thread trusted through correctly.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f81ab8867

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Addressed: .mux/init hook is now gated on project trust in all runtime implementations:

  • WorktreeRuntime, SSHRuntime, DockerRuntime, DevcontainerRuntime

When untrusted, the init hook is skipped with a clear log message ("Skipping .mux/init hook (project not trusted)").

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02d7ada9fa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Addressed both outstanding threads:

  1. SSHRuntime.forkWorkspace (P1) — Added gitNoHooksPrefix to both git worktree add (line ~1500) and fallback git checkout (line ~1607) commands, suppressing post-checkout hooks for untrusted projects.

  2. LocalRuntime.initWorkspace (P2) — Added trust check alongside skipInitHook so .mux/init is suppressed for untrusted projects in local runtime mode, matching the pattern in all other runtimes.

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Add a trust gate that prevents repo-controlled scripts and git hooks
from executing until the user explicitly trusts the project.

Gated vectors:
- .mux/tool_env (sourced before every bash command)
- .mux/tool_pre / tool_post / tool_hook (wraps tool calls)
- Git hooks (post-checkout, applypatch-msg, pre-applypatch, etc.)

Implementation:
- Add trusted field to ProjectConfigSchema
- Add projects.setTrust IPC endpoint
- Thread trust through tool system, runtimes, and git operations
- Neutralize git hooks via GIT_CONFIG env vars pointing core.hooksPath to /dev/null
- Add ProjectTrustBanner component with confirmation modal
- Add Security section in Settings for managing trust per-project
- Add tests for bash tool_env gating, git env vars, and schema
Address Codex review:
- Add gitNoHooksPrefix to provisionContainer checkout (initWorkspace path)
- Add gitNoHooksPrefix to forkWorkspace checkout (fork path)
- WorktreeManager already uses execFileAsync with env option (resolved in rebase)
Skip .mux/init hook when project is untrusted in:
- WorktreeRuntime
- SSHRuntime
- DockerRuntime
- DevcontainerRuntime
Integration tests expect hooks/scripts to run, so trust the project
before creating workspaces. Added trustProject helper and integrated
it into createWorkspace, createWorkspaceWithInit, and create.test.ts's
local helper.
…Workspace

- SSHRuntime.forkWorkspace: Add gitNoHooksPrefix to git worktree add
  and fallback git checkout commands for untrusted projects
- LocalRuntime.initWorkspace: Add trust check alongside skipInitHook
  so .mux/init is suppressed for untrusted projects in local runtime
The handler was a no-op when called before workspace.create since
the project didn't exist in config yet. Now creates a minimal
project entry ({workspaces:[]}) so trust can be established before
the first workspace is created — fixing integration tests that
call trustProject() before workspace.create().
The test was missing trusted:true so the init hook was being skipped
by the newly added trust gate in LocalRuntime.initWorkspace.
…merge ops

- fetchOriginTrunk, fastForwardToOrigin, renameWorkspace, deleteWorkspace
  all receive noHooksEnv and pass it to execFileAsync
- WorktreeRuntime forwards trusted from Runtime interface
- workspaceService retrieves trusted from config for delete/rename/fork
- Add GIT_CONFIG_PARAMETERS='' to GIT_NO_HOOKS_ENV to prevent bypass
… untrusted test

- Add nhp prefix to git am --abort and git worktree remove in finally block
- ProjectTrustBanner: try/catch with error display, shrink-0 on button
- SecuritySection: pending state, disabled during save, aria-labels
- Add 'skips init hook when untrusted' negative test in LocalRuntime
…skip bug

- New shouldSkipInitHook() in initHook.ts centralizes skip logic
- All 5 runtimes now use the shared helper (Local, Worktree, SSH, Docker, Devcontainer)
- Fix: DevcontainerRuntime was missing skipInitHook check (only checked trusted)
- Fix: SSHRuntime unused skipInitHook destructure
- Fix: workspaceService fork cleanup used undeclared trusted variable
- Fix: gitNoHooksEnv test updated for GIT_CONFIG_PARAMETERS field
@ibetitsmike ibetitsmike force-pushed the mike/project-trust-confirmation branch from bbe8329 to f9d2bcc Compare February 25, 2026 12:10
@ibetitsmike
Copy link
Contributor Author

@codex review

- workspaceService tests: add loadConfigOrDefault mock, update deleteWorkspace assertion
- ProjectPage autofocus test: use getProjectConfig instead of removed projects field
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f9d2bcc973

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2fa4e0cd66

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06e7275ba1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc7853d189

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e31b0430a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a70f64923

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

@ibetitsmike ibetitsmike force-pushed the mike/project-trust-confirmation branch from e04e436 to 9ddbed4 Compare February 25, 2026 23:56
@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c411a9da53

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

The SecurityMixedTrust story has 2 trusted projects, producing 2 'Revoke trust'
buttons. findByRole (singular) throws when multiple elements match. Switch to
findAllByRole and assert count, matching the pattern in SecurityAllTrusted.
Snapshot the projectPath that triggered the trust dialog into the trustPrompt
state. The onConfirm callback now reads trustPrompt.projectPath instead of the
outer closure's projectPath, so switching projects while the dialog is open
trusts the correct repository.

Addresses Codex P2 review comment.
@ibetitsmike
Copy link
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike ibetitsmike added this pull request to the merge queue Feb 27, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 27, 2026
@ibetitsmike ibetitsmike added this pull request to the merge queue Feb 27, 2026
Merged via the queue into main with commit c4a7bac Feb 27, 2026
23 checks passed
@ibetitsmike ibetitsmike deleted the mike/project-trust-confirmation branch February 27, 2026 06:02
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.

1 participant