Skip to content

Require authorization for mod-supplied external commands - #368

Draft
4Luke4 wants to merge 2 commits into
WeiDUorg:develfrom
4Luke4:agent/authorize-external-commands
Draft

Require authorization for mod-supplied external commands#368
4Luke4 wants to merge 2 commits into
WeiDUorg:develfrom
4Luke4:agent/authorize-external-commands

Conversation

@4Luke4

@4Luke4 4Luke4 commented Jul 24, 2026

Copy link
Copy Markdown

Summary

  • Adds a native, fail-closed authorization boundary for mod-supplied operating-system commands.
  • Requires explicit authorization before immediate, deferred, interactive, uninstall, or README-view commands can reach the host shell.
  • Preserves existing command handling, including EXACT and non-EXACT behavior.
  • Adds regression coverage and CI integration for Linux, macOS, and Windows.
  • Requires no Docker, Podman, Python, strace, command allowlist, or additional sandbox utility.

This partially addresses the external-command execution concerns discussed in #313 without imposing a single game-directory boundary or introducing additional runtime dependencies.

Authorization behavior

  • Interactive runs ask before executing external commands.
  • Each prompt displays:
    • The escaped requesting TP2 filename
    • WeiDU’s immutable component number, when applicable
    • The action type
    • The exact prepared command
    • A fresh confirmation token
  • Y <token> authorizes one command.
  • A <token> authorizes commands only for the same TP2 and component.
  • Non-interactive runs deny external commands by default.
  • The policy can be selected explicitly with:
    • --ask-external-commands
    • --allow-external-commands
    • --deny-external-commands
  • Only --allow-external-commands grants invocation-wide authorization.
  • --yes does not authorize external commands.
  • Deferred commands are authorized before being queued, and the already-authorized command is retained for later execution.

Denial and uninstall safety

External-command denial is represented as a dedicated fatal security decision. It cannot be caught or downgraded by:

  • ACTION_TRY
  • Uninstall ACTION_IF
  • --continue

During uninstall, an error or denial in an AT hook does not prevent WeiDU from attempting the remaining COPY, MOVE, and STRSET restoration categories.

After restoration:

  • WeiDU.log reflects the restored component state.
  • The denied or failed hook is still propagated as an uninstall failure.
  • WeiDU does not print a false successful-removal message.

Security scope

This is an authorization boundary, not an operating-system sandbox.

Authorized commands retain the user’s operating-system permissions and are not restricted to the game directory. WeiDU’s built-in file operations and other authority surfaces remain outside this PR’s scope.

Accordingly, this PR partially addresses #313 and is not intended to close the entire issue.

Validation

Local verification against the current head (db45223) includes:

  • Clean-checkout native OCaml build and link
  • Complete external-command policy integration suite
  • Windows-compatible non-FIFO test subset
  • Regression coverage for:
    • Default non-interactive denial
    • Explicit ask, allow, and deny policies
    • --yes isolation
    • One-command authorization followed by denial
    • TP2/component-scoped authorization
    • Immutable component provenance
    • Invalid and mod-supplied confirmation tokens
    • ACTION_TRY
    • --continue
    • Uninstall ACTION_IF
    • Nested uninstall through ACTION_TRY
    • COPY, MOVE, and STRSET restoration
    • WeiDU.log state after denied uninstall hooks
    • Immediate and deferred commands
    • README viewer commands
    • Non-EXACT commands
  • Reproduction of the pre-fix uninstall false-success defect against the earlier PR head (a88b69b)
  • OCaml parser checks for every modified module
  • POSIX shell syntax validation
  • git diff --check

The policy suite is wired into the repository’s Linux, macOS, and Windows jobs, and the main workflow now runs for pull requests. The current GitHub-hosted runs require upstream-maintainer approval before their jobs can execute.

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