gitops as CI
sip docs deployment.md
6.0 kB · 152 lines
Markdown

Deployment and Trust Boundaries #

This document describes the current deployment model for sip. The project is still a CI control-plane sketch, so treat these rules as the minimum safe shape for development and test deployments rather than a production hardening guide.

Installed Components #

Install the server-side hooks into each bare repository that should emit CI events:

bin/sip-install-hooks.rc /path/to/bare.git

The installer writes:

  • hooks/pre-receive: rejects client writes to CI-controlled and unsupported ref namespaces.
  • hooks/post-receive: queues accepted branch and tag events under $GIT_DIR/sip/queue, then invokes the worker when an orchestrator module is installed.

The worker and log reader are launched through thin wrappers:

bin/sip-worker.rc /path/to/bare.git
bin/sip-logs.rc /path/to/bare.git [job-id]

The worker currently shells out to git, sqlite3, and, for the unsafe shell executor, sh. These commands must be available in the trusted server PATH.

Trusted Environment #

Only the Git server wrapper, repository administrator, or service manager should set sip environment variables. Do not allow clients to control these values through push options or arbitrary receive-pack environment passthrough.

  • SIP_ACTOR: set by the trusted Git SSH/HTTP wrapper before git-receive-pack. The post-receive hook records a sanitized value in queue events. If unset, events record unknown.
  • SIP_WORKFLOW_REF: optional worker override for the protected workflow ref. The worker accepts only valid refs under refs/workflows/*; unsafe or malformed values are ignored. The default is refs/workflows/default.
  • SIP_EXECUTOR_MODULE: optional path to an executor WASM module. This is an administrator-controlled runtime setting. The current example executor can run host shell commands and must not be exposed to untrusted configuration.

The installer substitutes @SIP_ROOT@ in the post-receive hook with the local checkout path. That path is trusted configuration because the hook uses it to find bin/sip-worker.rc.

Privileged Refs #

Client pushes are accepted only for normal branch and tag activity. The pre-receive hook rejects direct client writes to:

  • refs/ci/*
  • refs/workflows/*
  • all refs/sip/* except refs/sip/orchestrator
  • refs/notes/*
  • refs/replace/*
  • unknown top-level ref namespaces

Server-side maintenance for protected refs must happen outside the client receive path, for example with local git update-ref or local git fetch commands run by an administrator or service account on the Git server.

refs/workflows/* stores protected workflow definitions. When a valid protected workflow ref exists and contains .sip/workflows, it wins over workflow files from the pushed worktree and records workflow_trust=protected.

refs/sip/orchestrator stores the service-owned workflow WASM module as a Git commit containing workflow.wasm or workflow.wat. Client pushes may update this ref today, so deployments that need stricter separation should install it only through trusted server-side maintenance or tighten the hook policy before accepting untrusted users.

refs/ci/* is service-owned output. The worker writes run manifests under refs/ci/runs/* and best-effort latest status refs under refs/ci/status/heads/* and refs/ci/status/tags/*.

Queue and Worker Operation #

The post-receive hook writes one tab-delimited event file per accepted branch or tag update under:

$GIT_DIR/sip/queue/*.event

The worker initializes and uses these state directories:

$GIT_DIR/sip/queue
$GIT_DIR/sip/done
$GIT_DIR/sip/failed
$GIT_DIR/sip/logs
$GIT_DIR/sip/tmp

It processes queued events in filename order. Successful events move to sip/done. Malformed events and events whose new object cannot resolve to a commit move to sip/failed. If the worker exits with an error before moving an event, the event remains in sip/queue and a later worker run will retry it.

Job state and logs live in:

$GIT_DIR/sip/logs/jobs.sqlite

Back up $GIT_DIR/sip with the bare repository. The queue, done, and failed directories are part of the audit trail and retry state. The logs directory contains workflow execution rows, job rows, dependency rows, and searchable job logs. The tmp directory contains transient checkouts and module copies and does not need durable backup.

Security Boundary #

The current boundary is split across three layers:

  • Git hooks are trusted receive-path glue. They reject protected refs and create event records, but should stay small and avoid complex policy.
  • The Rust worker is the trusted control plane. It validates queue records, resolves immutable object IDs, selects workflow sources, writes CI refs, records SQLite state, and embeds Wasmtime.
  • User workflow WASM is untrusted code. It can read selected workflow files and declare jobs only through the host ABI exposed by the worker.

The current Wasmtime host does not expose ambient WASI. Host functions mediate workflow file reads and job declaration. Future host capabilities for artifacts, network access, status updates, and secrets must enforce policy in Rust using immutable event/workflow metadata, actor identity, workflow trust, and explicit capability grants.

The unsafe-host-shell executor is outside the safe boundary. It intentionally runs declared commands with sh -c in an archived checkout and is suitable only for trusted development or test deployments until executor isolation and policy are added.

Current Gaps #

These are known deployment risks tracked as follow-up work:

  • Queue events are shape-validated but not authenticated. Protect $GIT_DIR/sip/queue with service-owned permissions and add event signing or a MAC before relying on queue provenance.
  • Pull and merge namespaces should remain rejected until their system-owned semantics are defined.
  • Wasmtime resource limits are not yet configured.