Skip to content

Commit 63a7043

Browse files
committed
Don't crash when stdin has no interactive input for permission prompts
Previously, running the Docker image without -it would make sys.stdin.isatty() return False and raise RuntimeError, aborting the whole postprocessing run. Replace the isatty() check with catching EOFError on input(), which is the actual signal that stdin has no data to offer. This means prompts still work with just `docker run -i` (no pty needed), and with no flags at all the run degrades gracefully by denying the risky permission and logging a warning instead of crashing.
1 parent 47bc972 commit 63a7043

1 file changed

Lines changed: 21 additions & 15 deletions

File tree

ogc/bblocks/permissions.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
from __future__ import annotations
22

33
import json
4-
import sys
4+
import logging
55
from pathlib import Path
66

77
import yaml
88

99
from ogc.bblocks.transform import _PERMISSION_CHECKED_TYPES as _RISKY_TRANSFORM_TYPES, read_plugin_entries
10+
11+
logger = logging.getLogger(__name__)
12+
1013
_PERMISSIONS_FILE = 'permissions.json'
1114

1215

@@ -27,19 +30,23 @@ def _save_cache(sandbox_dir: Path, cache: dict) -> None:
2730
json.dump(cache, f, indent=2)
2831

2932

30-
def _require_tty() -> None:
31-
if not sys.stdin.isatty():
32-
raise RuntimeError(
33-
"Transform permission check required but stdin is not a TTY. "
34-
"Run with --skip-permissions true to bypass permission checks "
35-
"in non-interactive environments (e.g. CI)."
36-
)
37-
38-
3933
def _ask_yes_no(prompt: str) -> bool:
40-
_require_tty()
34+
"""Ask a y/n question.
35+
36+
If stdin has no interactive input to offer (e.g. `docker run` without `-i`),
37+
`input()` hits EOF immediately rather than blocking, so we treat that as a
38+
denial instead of crashing the whole run.
39+
"""
4140
while True:
42-
answer = input(f"{prompt} [y/N] ").strip().lower()
41+
try:
42+
answer = input(f"{prompt} [y/N] ").strip().lower()
43+
except EOFError:
44+
logger.warning(
45+
"No interactive input available to answer this prompt (stdin is closed) "
46+
"- denying by default. Run `docker run -i ...` to answer prompts interactively, "
47+
"or pass --skip-permissions true to bypass permission checks entirely."
48+
)
49+
return False
4350
if answer in ('y', 'yes'):
4451
return True
4552
if answer in ('', 'n', 'no'):
@@ -113,7 +120,6 @@ def _check_plugin_permissions(
113120
allowed.add(module)
114121
continue
115122

116-
_require_tty()
117123
print()
118124
print(f"╔══ {label} plugin permission required")
119125
print(f"║ Plugin: {module}")
@@ -141,7 +147,8 @@ def check_permissions(
141147
allowed_transform_types: set of approved type strings
142148
allowed_plugin_modules: set of approved transform plugin module paths
143149
allowed_validator_modules: set of approved validator plugin module paths
144-
Raises RuntimeError if stdin is not a TTY and permissions are needed.
150+
Denies (with a warning) any permission that can't be answered interactively,
151+
e.g. when stdin is closed because `docker run` was invoked without `-i`.
145152
"""
146153
cache = _load_cache(sandbox_dir)
147154
cache_dirty = False
@@ -153,7 +160,6 @@ def check_permissions(
153160
unapproved_types = {t: blocks for t, blocks in needed_types.items() if t not in cached_types}
154161

155162
if unapproved_types:
156-
_require_tty()
157163
print()
158164
print("╔══ Transform permission required")
159165
print("║ The following building blocks contain transforms that can execute arbitrary code on your machine:")

0 commit comments

Comments
 (0)