mock_paths patched TARGET_DIR/PENDING_DIR/etc but not MOUNT_ROOT, so tests leaked the host's real ~/pCloudDrive mount_root config and failed probe_target's mountpoint check. Also drop redundant equality clause since is_relative_to already covers equal paths, and document the mount precondition.
pCloud was never a hard dependency - the tool writes to any local directory.
Renaming makes the tool clearly generic before publishing.
- PCLOUD_TARGET → TARGET_DIR
- probe_pcloud → probe_target
- place_into_pcloud → place_into_target
- pcloud_target config key → target_dir
- COE_MIRROR_PCLOUD_TARGET env var → COE_MIRROR_TARGET_DIR
- Hardcoded default: ~/pCloudDrive/Hacking/ChurchOfMalware → ~/coe-mirror
- Log messages and docstrings updated
- Tests updated to match
DevTrack #1286
- ~/.config/coe-mirror/config.toml (tomllib, Python 3.11+ required)
- Precedence uniform for every key: env var > config file > hardcoded default
- API_BASE, OWNERS, PCLOUD_TARGET, PENDING_DIR, matrix homeserver/room resolved
via _resolve() helper
- Matrix homeserver/room now default to empty; _send_matrix short-circuits when
either is blank so forks don't spam the original author's room
- _fetch_creds falls back to COE_MIRROR_MATRIX_USER/PASSWORD env vars when the
Infisical creds binary is unavailable (required for external distribution)
- CLI subcommands: config init (writes example TOML, won't overwrite), config path
Bare invocation and 'run' still work unchanged for the systemd timer
- README rewritten as a public quick-start with the precedence table and Matrix
as opt-in
- Tests: 3 new for config precedence, 1 for Matrix silent no-op when blank,
2 for creds env fallback (26 total, all pass)
DevTrack #1285
- OWNERS list replaces single OWNER: Nightmare_Eclipse, shai_hulud, bikini_mirror, ek0mssavi0r
- PCLOUD_TARGET moves to ChurchOfMalware/ parent, per-owner subdirs at runtime
- Owner threaded through fetch_repos, fetch_branch_sha, download_repo_zip
- Pending filenames get owner__ prefix to prevent cross-owner collisions
- flush_pending strips owner prefix when routing to owner subdir
- Per-owner fetch failure logs and continues; failed_owners reported in notify
- notify groups new files by owner; also picks up flushes done at run start
- Tests: parametrize on OWNERS via monkeypatch, add multi-owner collision and
per-owner failure isolation tests
DevTrack #1284
Replaces shared @intel-bot credentials with a Matrix user created
specifically for this tool. Reads Infisical keys via constants
COE_MIRROR_BOT_USER_KEY and COE_MIRROR_BOT_PASSWORD_KEY so test
assertions track the code rather than hardcoded strings.
- Add precise type hints: Optional[Tuple[str, str]] for _fetch_creds(),
List[Tuple[str, str, str]] for notify()
- Wrap requests.Session in context manager for proper cleanup
- Remove unreachable return False after retry loop in _send_matrix()
PEP 668 Debian 13 systems error out on 'pip install --user'. Runtime
only needs requests; pytest+requests-mock are test-only. Detect the
runtime dep first and fall back to pip only when missing.
Standalone Python tool. Hits git.churchofmalware.org public API every
12h (00:00/12:00), downloads any repo HEAD whose SHA hasn't already
been snapshotted to pCloud, with local-staging fallback when the FUSE
mount is unavailable. Matrix notification stub for when the home
server is back.
Devil's-advocate findings folded into the design:
- shutil.copy2 + size verify + unlink, not os.rename, for FUSE safety
- no pCloud daemon auto-start (no user unit; DISPLAY=:0 unreliable);
relies on Persistent timer + pending flush for recovery
- two-call API path retained because the repo list response does not
include commit.sha
Audit-driven security fixes:
- repo names whitelist-validated (^[a-zA-Z0-9._-]+$)
- urllib.parse.quote on all interpolated URL segments
- same-file no-op guard in place_into_pcloud
- existence check moved to main() so cached files don't generate
spurious notify entries
13 pytest tests passing.
- **Schedule**: 00:00 + 12:00 daily, catch-up on boot via Persistent timer + OnBootSec.
- **Design rationale**:
- FUSE-safe placement uses `shutil.copy2 + size verify + unlink`, not `os.rename`, to handle pCloud FUSE semantics.
- pCloud daemon auto-start was rejected — no user unit exists; DISPLAY=:0 spawning is unreliable. Tool relies on Persistent timer + pending-flush for recovery.
-`commit.sha` is NOT in the repo-list API response — two-call approach (list, then per-repo branch) is retained.
- **DevTrack**: Not created at creation time (oraculo offline, Tailscale last seen 2d ago, carbon roaming off home LAN). Add a `coe-mirror` project + item retroactively when oraculo returns.
- **Matrix notification**: Stub-only at creation time, Matrix server down. Real implementation deferred until home Matrix server is back.
## 2026-06-14 — Matrix notification swap
- Replaced `notify()` stub with real Synapse send. Targets General room (`!MBpPtYlQYMcngtpvJt:m.mealeyfamily.com`).
- Auth: password login via `MATRIX_USER` + `MATRIX_PASSWORD` from Infisical `matrix/` at refresh time. Token cache at `~/.local/share/coe-mirror/matrix-token.json` (chmod 0600), refreshed when <30 min left or on 401.
- Non-fatal failures — Matrix outage does not break the mirror.
- **Bug**: `probe_target()` did `TARGET_DIR.mkdir(parents=True, exist_ok=True)` unconditionally. When pCloud FUSE was unmounted, this created `~/pCloudDrive/...` as plain LOCAL dirs, occupying the mountpoint and blocking the pCloud client from mounting. Live state on carbon confirmed: `~/pCloudDrive` was a plain dir, not a mountpoint, with 22 stray zips inside.
- **Fix**: new optional config key `mount_root` (env `COE_MIRROR_MOUNT_ROOT`). When set, `probe_target()` requires `os.path.ismount(mount_root)` AND that `TARGET_DIR` is under `mount_root` before any mkdir; otherwise returns False (queues to pending). Never creates the mount root. Empty/unset = old behavior (local targets like `~/coe-mirror`).
- Local config sets `mount_root = "~/pCloudDrive"`.
- **Recovery run**: stopped/masked timer, staged the 22 zips aside, removed the local `~/pCloudDrive`, relaunched pCloud, verified mountpoint, moved zips onto the live mount, unmasked timer.
- DevTrack: #1307.
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.