mirror
mirror
¶
Host-side git gate (mirror) management and upstream comparison.
The git gate is a bare git repository stored on the host. Its role varies with how the caller configures it:
- Upstream set, gatekeeping mode — the gate is a mirror of upstream and is the only repository the container can access, enforcing human review before changes reach upstream.
- Upstream set, online mode — the gate mirrors upstream and serves as a read-only clone accelerator (faster than cloning over the network).
- No upstream —
sync()initialises the gate as a remoteless bare repo that the container can still push to. Nothing is fetched because there is no remote; subsequent syncs are no-ops.
GitGate is the main service class — wraps git CLI operations for
syncing, comparing, and querying the gate.
All constructor parameters are plain values (strings, paths) — no
terok-specific types like ProjectConfig.
Value types returned by GitGate methods:
GateSyncResult— full sync outcome (created, updated branches, errors;upstream_urlisNonefor remoteless gates)BranchSyncResult— selective branch sync outcomeCommitInfo— single commit metadata (hash, date, author, message)GateStalenessInfo— frozen comparison of gate HEAD vs upstream HEAD
logger = logging.getLogger(__name__)
module-attribute
¶
GateAuthNotConfigured(scope)
¶
Bases: RuntimeError
Raised when a scope has no vault key and personal-SSH fallback is not opted in.
Callers (the gate-sync CLI dispatch) turn this into a two-door
remediation hint:
- generate a terok-managed key with
terok ssh-init <project>and register it upstream, or - opt in to the user's own
~/.sshkeys with--use-personal-ssh(orssh.use_personal: truein the project YAML).
Source code in src/terok_sandbox/gate/mirror.py
scope = scope
instance-attribute
¶
GateSyncResult
¶
Bases: TypedDict
Result of a full gate sync operation.
upstream_url is None when the gate is initialised without a
remote — a local-only mirror that the container can push to but that
never fetches external commits.
BranchSyncResult
¶
CommitInfo
¶
GateStalenessInfo(branch, gate_head, upstream_head, is_stale, commits_behind, commits_ahead, last_checked, error)
dataclass
¶
GitGate(*, scope, gate_path, upstream_url=None, default_branch=None, use_personal_ssh=False, validate_gate_fn=None, clone_cache_base=None)
¶
Repository + Gateway for a host-side git gate mirror.
Manages the bare git mirror that containers clone from. Provides operations for initial creation, incremental sync from upstream, selective branch fetching, and staleness detection.
Constructor takes plain parameters — no terok-specific types.
Initialise with plain parameters.
Parameters¶
scope:
Credential scope for this gate's owner. Used to locate the
per-scope vault SSH-agent socket.
gate_path:
Path to the bare git mirror on the host.
upstream_url:
Git upstream URL to sync from.
default_branch:
Branch name used for staleness comparisons.
use_personal_ssh:
When True, skip the vault socket entirely and let git fall
through to the user's ~/.ssh keys / loaded agent. Default
False — "terok never touches your real keys" is the advertised
property. Opt in per-invocation (--use-personal-ssh) or
per-project (ssh.use_personal: true in project YAML).
validate_gate_fn:
Optional callback (scope) -> None that validates no other
scope uses the same gate with a different upstream. Injected by
the orchestration layer; omitted for standalone use.
clone_cache_base:
Base directory for non-bare clone caches. When set,
sync refreshes a working-tree cache at
clone_cache_base / scope after updating the bare mirror.
The cache accelerates task startup by enabling a host-side
file copy instead of a full git clone.
Source code in src/terok_sandbox/gate/mirror.py
cache_path
property
¶
Clone cache directory for this scope, or None if caching is disabled.
close()
¶
Stop the ephemeral signer this gate started, if any.
Idempotent. Long-lived processes (the TUI) should call this explicitly so the signer thread and temp socket don't outlive the gate's last use.
Source code in src/terok_sandbox/gate/mirror.py
__del__()
¶
sync(branches=None, force_reinit=False)
¶
Sync the host-side git mirror gate from upstream.
With an upstream configured, clones (or fetches) from it using the project's SSH setup. Without one, initialises a bare repo in place and returns a no-op sync — the gate then serves as a local-only remote that the container can push to, giving the agent somewhere to stage commits even when there is nothing external to mirror.
A remoteless gate that already exists is a proper no-op: nothing re-initialises, and the returned branch list is empty.
Source code in src/terok_sandbox/gate/mirror.py
sync_branches(branches=None)
¶
Sync specific branches in the gate from upstream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
branches
|
list[str] | None
|
List of branches to sync (default: all via remote update) |
None
|
Returns:
| Type | Description |
|---|---|
BranchSyncResult
|
Dict with keys: success, updated_branches, errors |
Source code in src/terok_sandbox/gate/mirror.py
compare_vs_upstream(branch=None)
¶
Compare gate HEAD vs upstream HEAD for a branch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
branch
|
str | None
|
Branch to compare (default: configured default_branch) |
None
|
Returns:
| Type | Description |
|---|---|
GateStalenessInfo
|
GateStalenessInfo with comparison results |
Source code in src/terok_sandbox/gate/mirror.py
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | |
last_commit()
¶
Get information about the last commit on the configured branch.
Returns None if the gate doesn't exist or is not accessible.
Source code in src/terok_sandbox/gate/mirror.py
is_ssh_url(url)
¶
Return True for SSH-scheme git URLs.
Accepts the two forms git itself accepts:
ssh://[user@]host[:port]/path— explicit URL scheme.[user@]host:path— scp-style shorthand. The user part is optional (git@github.com:foo.git,deploy@host:repo.git, baregithub.com:foo.git).
Shared with terok-main: both the gate's env builder and callers that branch on "does this project use SSH?" (e.g. deploy-key prompts, gate-sync fallback hints) must agree on one definition.