Skip to content

Replace 10s warning pause with an interactive confirmation prompt for non-local targets #1

@lhocor

Description

@lhocor

Motivation

The current safety guard for non-local write targets (main.go:113-119warnIfNonLocal) just prints a warning and sleeps 10 seconds before auto-proceeding. In practice that's easy to miss:

  • The warning scrolls past in a busy terminal.
  • chcopy keeps going on its own, so an unattended invocation will happily TRUNCATE + INSERT against whatever CHCOPY_LOCAL_HOST points to — including a remote/prod cluster if someone fat-fingers the env.
  • The current message doesn't actually show which host is about to be written to, so even an attentive operator can't sanity-check the target without re-reading their shell env.

We should fail closed: when the target doesn't look local, require explicit confirmation that names the host.

Proposed behavior

When CHCOPY_LOCAL_HOST does not resolve to localhost or a private / docker-bridge range, prompt before running anything:

WARNING: target ClickHouse "ch-prod-eu-1.example.com" does not look local.
You are about to write to this server. Type 'yes' to proceed:
  • Must include the resolved hostname (the value of CHCOPY_LOCAL_HOST as configured) so the user can verify the target.
  • Only the literal answer yes proceeds. Anything else (including empty line, no, EOF, Ctrl-C) aborts with a non-zero exit code.
  • Local targets: no prompt, behavior unchanged.
  • --dry-run: no prompt (nothing is written).

Non-interactive / CI escape hatch

If stdin is not a TTY and the target is non-local, abort with a clear error unless the user opts in:

  • New flag --yes (or --force) to skip the prompt.
  • Without --yes on a non-TTY non-local run, exit with something like:
    error: target "X" is non-local and stdin is not a TTY; pass --yes to confirm non-interactively.

This keeps scripted/CI usage explicit rather than silently auto-confirming after 10s.

Acceptance criteria

  • Local target → no prompt, no change.
  • Non-local target + TTY → prompt shows host, blocks until yes, aborts on anything else.
  • Non-local target + non-TTY without --yes → abort with clear error.
  • Non-local target + --yes → proceed without prompting.
  • --dry-run always skips the prompt.
  • README "Safety guards" section updated to describe the new behavior.
  • e2e test covers both the --yes path and the abort-without-TTY path.

Out of scope

  • Per-table or per-host allowlists (could be a follow-up).
  • Changing the local/private-range heuristic itself (isLocal stays as-is).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions