Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ else
fi

export PYTHONPATH="${PLUGIN_ROOT}${PYTHONPATH:+:${PYTHONPATH}}"

# ``python3 -m`` puts the process working directory first on sys.path, so a
# stray ``audio_recap/`` directory in the user's CWD (a checkout of this repo
# or a git worktree) would shadow the installed plugin and run stale code.
# cd into the plugin root so the installed package always wins. Production
# never derives its working directory from the process anyway: the Stop hook
# reads ``cwd`` from its stdin payload and the slash commands pass ``--cwd "$PWD"``.
cd "$PLUGIN_ROOT"

# ``python3`` resolves via the user's PATH — on macOS that is the
# system interpreter (/usr/bin/python3) unless they have installed
# another. Audio Recap is stdlib-only and floors at 3.9, so whatever
Expand Down
52 changes: 52 additions & 0 deletions tests/test_run_sh_cwd_isolation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""``scripts/run.sh`` must run the installed package, not a cwd decoy.

``python3 -m`` puts the process working directory first on ``sys.path``, so a
stray ``audio_recap/`` directory in the user's working directory (a checkout of
this repo, or a worktree) would shadow the installed plugin and run stale code.
``run.sh`` cd's to the plugin root before exec to stop that; this test locks in
the fix end to end.
"""

from __future__ import annotations

import shutil
import subprocess
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[1]
RUN_SH = REPO_ROOT / "scripts" / "run.sh"


def _plant_decoy(directory: Path) -> None:
"""Plant an ``audio_recap/`` package that exits 123 loudly if imported."""

pkg = directory / "audio_recap"
pkg.mkdir()
(pkg / "__init__.py").write_text("", encoding="utf-8")
(pkg / "__main__.py").write_text(
'import sys\nsys.stdout.write("DECOY\\n")\nsys.exit(123)\n',
encoding="utf-8",
)


@pytest.mark.skipif(shutil.which("bash") is None, reason="bash required to run run.sh")
def test_run_sh_decoy_in_cwd_does_not_shadow_installed_package(tmp_path: Path) -> None:
"""Invoked from a cwd holding a decoy ``audio_recap/``, run.sh runs the real one."""

_plant_decoy(tmp_path)

result = subprocess.run(
["bash", str(RUN_SH), str(REPO_ROOT)],
cwd=tmp_path,
capture_output=True,
text=True,
)

output = result.stdout + result.stderr
# The decoy prints DECOY and exits 123; the real package prints its usage
# banner and exits 2 when handed no subcommand.
assert "DECOY" not in output, f"cwd decoy shadowed the installed package:\n{output}"
assert result.returncode == 2, output
assert "usage: python -m audio_recap" in output
Loading