chore(boundary): PR 2 — Wave 1 closure + Lint #3 활성화

PYTHON_THINNING_PLAN §5 PR 2 — Bootstrap tree/list 청산.

scope 조정 (실측 기반):
- python_interpreter_browser.py는 *이미* helper exec_once 사용 중 (PR 2
  scope에서 코드 청산 불필요).
- ssh_runner.py의 `python3 -c` literal은 *로컬 askpass GUI* (Tkinter)용으로
  원격 무관 — boundary §17-19 위반 *아님*. 모듈 docstring의 stale
  "Temporary bootstrap" 문구만 갱신.
- 진짜 grandfather 위반 1건 (marimo_hosting.py:427 원격 port pick) 발견 —
  별도 슬라이스로 청산 미룸.

산출물:
- sublime/sessions/ssh_runner.py: 모듈 docstring 정정 (helper로 일원화 완료
  명시 + askpass exception 명시).
- scripts/lint_python_thinning.py: Lint #3 활성화. 패턴: `["']python3 -c `
  / `"python3", "-c"`. ssh_runner.py exempt (로컬 askpass 영역).
- .gitea/workflows/boundary-lint.yml: ban-list 단계에 `--lint 3` 추가.
- planning/boundary_inventory.yml: marimo grandfather 위반 등록.

검증:
- diff 모드 (CI 기본): 위반 0건.
- all-files 모드: marimo:427 grandfather 1건 검출 (예상대로).
- ssh_runner.py askpass 패턴은 exempt path로 통과.

boundary-claim:
  removes: []  # 코드 청산 없음 (이미 helper 사용 중인 영역)
  delete-count: 0
  ban-list: '#3 활성화 — 정밀 패턴, marimo grandfather 등록'
  note: |
    plan v1.1 §5 PR 2의 LOC 추정 ~180은 인벤토리 시점 stale.
    실측 결과 코드 청산 영역이 거의 부재 — Wave 1은 PR 2 *이전*에 사실상
    완료된 상태. 본 PR은 Lint #3 거버넌스 가드만 활성화.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 19:28:26 +09:00
parent b11802ad2e
commit 322fa26ac8
4 changed files with 64 additions and 14 deletions

View File

@@ -13,7 +13,7 @@ on:
jobs:
ban-list:
name: ban-list lint (Lint #1/#2.5/#4)
name: ban-list lint (Lint #1/#2.5/#3/#4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -28,7 +28,7 @@ jobs:
- name: run boundary lint
env:
CI: "true"
run: python3 scripts/lint_python_thinning.py --lint 1 --lint 2.5 --lint 4
run: python3 scripts/lint_python_thinning.py --lint 1 --lint 2.5 --lint 3 --lint 4
duplication-deadline:
name: duplication-deadline (Layer 1/2)

View File

@@ -181,3 +181,9 @@ grandfather_violations:
pattern: "time.monotonic"
lint: "#2.5"
cleanup_pr: "Track H2 분리 시 retry/timeout을 _rust_ffi/bridge로 이동"
- path: sublime/sessions/marimo_hosting.py
line: 427
pattern: "python3 -c (remote port pick)"
lint: "#3"
cleanup_pr: "별도 슬라이스 (marimo `--port 0` 직접 사용 가능 검증 후)"

View File

@@ -14,9 +14,11 @@ Usage:
- #4 Rust ABI 영문 자연어 ban (Rust 측)
- #6 PR boundary-claim 헤더 검증
후속 활성 룰 (env LINT_THINNING_ACTIVATE 로 켬):
활성 룰 (PR 2):
- #3 Python python3 -c SSH 폴백 ban (sublime/sessions/, askpass 예외)
후속 활성화 룰:
- #2 Python deque/Event/Lock task queue 신설 ban (PR 16에서 활성화)
- #3 Python python3 -c SSH 폴백 ban (PR 2에서 활성화)
- #5 boundary inventory metasync (Wave 2.5에서 자동화)
normative 출처: planning/PYTHON_RUST_BOUNDARY.md (Wave 1.5 amend),
@@ -62,6 +64,19 @@ LINT_2_5_RETRY_PATTERNS = [
]
LINT_2_5_PATH_PATTERN = re.compile(r"^sublime/sessions/commands_[^/]+\.py$")
# Lint #3 — Python `python3 -c` 원격 폴백 ban (boundary §1719 Wave 1 closure)
# 원격에서 실행될 명령에 `python3 -c` literal이 새로 추가되는 것을 차단.
# 진짜 ban 의도: ssh 인자 또는 helper exec_once payload 안의 `python3 -c`.
# Diff 모드라 grandfather 자동: ssh_runner.py 로컬 askpass + marimo port pick은
# 기존 코드라 통과; 새 PR이 같은 패턴을 추가하면 fail.
LINT_3_REMOTE_PYTHON_C = [
re.compile(r'["\']\s*python3\s+-c\s'),
re.compile(r'["\']\s*python3["\']\s*,\s*["\']-c["\']'),
]
LINT_3_PATH_PATTERN = re.compile(r"^sublime/sessions/")
# askpass 모듈은 *로컬* python3 -c (Tk GUI dialog) 용도라 예외.
LINT_3_EXEMPT_PATH_PATTERN = re.compile(r"^sublime/sessions/(ssh_runner\.py)$")
# Lint #4 — Rust ABI 영문 자연어 ban (Rust 측 sessions_native ABI 함수)
# 식별자 코드만 반환해야 함. ABI 응답에 영문 자연어 문장(공백 + 3+ 어휘) 포함 금지.
# 휴리스틱: ABI 함수 본문 string literal "Word word word..." 패턴 grep.
@@ -227,6 +242,32 @@ def _check_lint_2_5(added: Iterable[Tuple[Path, int, str]]) -> List[Violation]:
return violations
def _check_lint_3(added: Iterable[Tuple[Path, int, str]]) -> List[Violation]:
violations: List[Violation] = []
for path, line_no, content in added:
rel = str(path).replace("\\", "/")
if not LINT_3_PATH_PATTERN.match(rel):
continue
if LINT_3_EXEMPT_PATH_PATTERN.match(rel):
continue
for pattern in LINT_3_REMOTE_PYTHON_C:
if pattern.search(content):
violations.append(
Violation(
lint_id="#3",
path=path,
line_no=line_no,
content=content,
reason=(
"원격 명령에 `python3 -c` 폴백 신규 금지 "
"(boundary §1719) — helper 채널 사용 필요"
),
)
)
break
return violations
def _check_lint_4(added: Iterable[Tuple[Path, int, str]]) -> List[Violation]:
violations: List[Violation] = []
for path, line_no, content in added:
@@ -285,7 +326,7 @@ def _check_lint_6_pr_body(pr_body_path: Path) -> List[Violation]:
# ---------------------------------------------------------------------------
ALL_LINTS = ("1", "2.5", "4", "6")
ALL_LINTS = ("1", "2.5", "3", "4", "6")
def main() -> int:
@@ -318,13 +359,15 @@ def main() -> int:
selected = set(args.lint) if args.lint else set(ALL_LINTS)
violations: List[Violation] = []
if {"1", "2.5", "4"} & selected:
if {"1", "2.5", "3", "4"} & selected:
base_ref = None if args.all_files else _resolve_base_ref(args.base_ref)
added = _added_lines(base_ref)
if "1" in selected:
violations.extend(_check_lint_1(added))
if "2.5" in selected:
violations.extend(_check_lint_2_5(added))
if "3" in selected:
violations.extend(_check_lint_3(added))
if "4" in selected:
violations.extend(_check_lint_4(added))

View File

@@ -1,20 +1,21 @@
"""Thin SSH execution boundary between Sublime commands and remote operations.
This module centralizes non-interactive ``ssh`` subprocess invocations used for
host probing, remote path checks, and directory listing before the Rust session
helper exists. Call sites should stay limited to command orchestration; swap
this layer for a helper-backed transport later without rewriting UX flows.
host probing and connection preflight. Tree/file I/O and remote directory
listing route through the Rust session helper (``local_bridge`` +
``session_helper``); see ``ssh_file_transport.py`` and
``python_interpreter_browser.py``.
The ``python3 -c`` literal that remains in this module is a *local* askpass
GUI helper (it spawns Tk on the operator's workstation when the user typed in
a passphrase). It does not run on the remote host and is not the
boundary-document §1719 fallback that Wave 1 closed.
Debug tracing:
Set the environment variable ``SESSIONS_SSH_DEBUG`` to a non-empty value to
print argv, exit code, and a stderr preview for each *failed* SSH run to
``sys.stderr`` (visible in Sublime's Python console when running a dev
build, or in CI logs).
Temporary bootstrap:
Remote directory listing currently shells out to ``python3 -c`` on the
remote host. That is bootstrap behavior; long-term listing should move onto
the session helper protocol once stdio transport is wired from Sublime.
"""
from __future__ import annotations