Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1577904
test(sync): reproduce cloud global dry-run stall
Jul 11, 2026
90bee2f
fix(sync): bound global dry-run path failures
Jul 11, 2026
3228fa3
fix(sync): keep legacy report fingerprint reads read-only
Jul 11, 2026
3194585
test(sync): reproduce dry-run discovery safety gaps
Jul 11, 2026
0664659
fix(sync): bound dry-run prompt discovery
Jul 11, 2026
ba8e9d2
test(sync): reproduce dry-run rereview gaps
Jul 11, 2026
06026f2
fix(sync): keep dry-run discovery project-contained
Jul 11, 2026
0c1aa69
test(sync): reproduce missing-artifact repair traversal gap
Jul 11, 2026
5b8de48
fix(sync): bound missing-artifact repair traversal
Jul 11, 2026
54f0417
fix: reject symlinked sync artifacts
Jul 11, 2026
c198c72
test(sync): cover unsafe legacy include deps
Jul 11, 2026
4014d58
fix(sync): reject unsafe legacy include deps
Jul 11, 2026
2b8ad90
test(sync): cover round-7 metadata safety gaps
Jul 11, 2026
a5d62c8
fix(sync): fail closed on unsafe legacy metadata
Jul 11, 2026
d29561e
test(sync): cover round-8 dry-run safety gaps
Jul 11, 2026
1e0a9b7
test(sync): exercise parsed live include paths
Jul 11, 2026
53aa730
fix(sync): close round-8 dry-run safety gaps
Jul 11, 2026
c3faf38
test(sync): cover round-9 dry-run resolver gaps
Jul 11, 2026
1f68fef
fix(sync): unify safe dry-run path resolution
Jul 11, 2026
09625fc
test(sync): cover round-10 trust boundaries
Jul 11, 2026
6b20857
fix(sync): enforce shared dry-run trust boundaries
Jul 11, 2026
f21924b
test(sync): reproduce round-11 dry-run resolver gaps
Jul 11, 2026
763644b
fix(sync): preserve bounded dry-run ownership
Jul 11, 2026
c248c0e
test(sync): reproduce round-12 resolver safety gaps
Jul 11, 2026
aa0ce66
fix(sync): close round-12 resolver safety gaps
Jul 11, 2026
55b1bfa
test(sync): reproduce round-13 report safety gaps
Jul 11, 2026
b9a117e
fix(sync): enforce round-13 report safety boundaries
Jul 11, 2026
81f3c0a
test(sync): reproduce round-14 liveness gaps
Jul 11, 2026
8d4697d
fix(sync): close round-14 liveness gaps
Jul 11, 2026
604c5b3
fix(sync): resolve Sol liveness review findings
Jul 12, 2026
8abacb2
test(sync): reproduce synthetic interpreter runtime leak
Jul 13, 2026
637b27a
fix(sync): bind supervisor to real interpreter
Jul 13, 2026
8153b89
fix(sync): preserve legacy path identity
Jul 13, 2026
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
1,321 changes: 1,200 additions & 121 deletions pdd/continuous_sync.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pdd/core/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ def _restore_estimate_env(_snapshot=_estimate_env_snapshot):
pass

# Warn users who have not completed interactive setup unless they are running it now
if not estimate_mode and _should_show_onboarding_reminder(ctx):
if not estimate_mode and not json_mode and _should_show_onboarding_reminder(ctx):
console.print(
"[warning]Complete onboarding with `pdd setup` to install tab completion and configure API keys.[/warning]"
)
Expand Down
8 changes: 7 additions & 1 deletion pdd/sync_core/fingerprint_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,18 @@ def read_legacy(self, path: Path) -> LegacyFingerprintRecord:
candidate = Path(path)
if not candidate.is_absolute():
candidate = self.checkout_root / candidate
try:
candidate_mode = candidate.lstat().st_mode
except OSError as exc:
raise FingerprintStoreError("legacy fingerprint is not a regular file") from exc
if stat.S_ISLNK(candidate_mode) or not stat.S_ISREG(candidate_mode):
raise FingerprintStoreError("legacy fingerprint is not a regular file")
resolved = candidate.resolve(strict=True)
try:
resolved.relative_to(self.checkout_root)
except ValueError as exc:
raise FingerprintStoreError("legacy fingerprint escapes checkout") from exc
if candidate.is_symlink() or not resolved.is_file():
if not resolved.is_file():
raise FingerprintStoreError("legacy fingerprint is not a regular file")
try:
payload = json.loads(resolved.read_text(encoding="utf-8"))
Expand Down
16 changes: 11 additions & 5 deletions pdd/sync_core/supervisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
import sysconfig


# Capture the executable that loaded this trusted module. Tests and callers may
# replace ``sys.executable`` to model argv-prefix portability; that synthetic
# spelling must never become a measured file or sandbox mount source.
_SUPERVISOR_EXECUTABLE = Path(sys.executable)


@dataclass(frozen=True)
class SupervisorLimits:
"""Hard limits applied to every untrusted validator process tree."""
Expand Down Expand Up @@ -86,7 +92,7 @@ def _runtime_directories() -> tuple[tuple[str, Path], ...]:
def released_runtime_closure_paths() -> tuple[tuple[str, Path], ...]:
"""Return every regular file exposed by the sandbox with logical names."""
entries: dict[str, Path] = {}
native: set[Path] = {Path(sys.executable).resolve()}
native: set[Path] = {_SUPERVISOR_EXECUTABLE.resolve()}
for label, directory in _runtime_directories():
for path in sorted(directory.rglob("*")):
if path.is_file() and not path.is_symlink():
Expand All @@ -105,7 +111,7 @@ def released_runtime_closure_paths() -> tuple[tuple[str, Path], ...]:
path = Path(value).resolve()
entries[f"sandbox/{name}"] = path
native.add(path)
entries["interpreter/python"] = Path(sys.executable).resolve()
entries["interpreter/python"] = _SUPERVISOR_EXECUTABLE.resolve()
for path in sorted(native):
for library in _linked_libraries(path):
entries.setdefault(
Expand All @@ -120,7 +126,7 @@ def _runtime_roots(command: list[str], cwd: Path) -> tuple[Path, ...]:
directories = tuple(directory for _label, directory in _runtime_directories())
roots.update(directories)
executables = (
Path(sys.executable), Path(shutil.which(command[0]) or command[0]),
_SUPERVISOR_EXECUTABLE, Path(shutil.which(command[0]) or command[0]),
)
for executable in executables:
resolved_executable = executable.resolve()
Expand Down Expand Up @@ -163,7 +169,7 @@ def _limited_command(command: list[str], limits: SupervisorLimits) -> list[str]:
"resource.setrlimit(resource.RLIMIT_NOFILE,(v[4],v[4]));"
"os.execvpe(sys.argv[6],sys.argv[6:],os.environ)"
)
return [sys.executable, "-c", script, str(limits.max_memory_bytes),
return [str(_SUPERVISOR_EXECUTABLE), "-c", script, str(limits.max_memory_bytes),
str(limits.max_cpu_seconds), str(limits.max_processes),
str(limits.max_output_bytes), "256", *command]

Expand All @@ -189,7 +195,7 @@ def _staged_bwrap(argv: list[str], sources: list[Path]) -> list[str]:
" shutil.rmtree(base,ignore_errors=True)",
"raise SystemExit(result.returncode)",
))
return ["sudo", "-n", "-E", sys.executable, "-c", helper,
return ["sudo", "-n", "-E", str(_SUPERVISOR_EXECUTABLE), "-c", helper,
json.dumps(argv), json.dumps([str(path) for path in sources])]

def _supervised_descendants(token: str) -> set[int]:
Expand Down
Loading
Loading