-
-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy path.env.selfhost.example
More file actions
164 lines (150 loc) · 10.6 KB
/
Copy path.env.selfhost.example
File metadata and controls
164 lines (150 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Gittensory self-host — focused starter env (#1938)
#
# This is the SHORT path: the required secrets plus a conservative first-boot config, with nothing
# about the Cloudflare Worker deploy. Copy it to `.env` (gitignored) and fill in the placeholders.
#
# cp .env.selfhost.example .env
#
# For the EXHAUSTIVE list of every self-host env var (optional services, observability, backup,
# every AI provider) see `.env.example`'s "Self-host (Docker) — runtime config" section, or the
# generated reference table at https://loopover.ai/docs/self-hosting-configuration.
# Every value below is a SAMPLE placeholder — never commit real secrets.
# =============================================================================
# 1. Required secrets — the app will not start without these
# =============================================================================
#
# RECOMMENDED: use native Docker Compose secret files instead of pasting values below. Run
# `./scripts/selfhost-init-secrets.sh` once (#4928) — it generates a real random value for every
# secret below EXCEPT the GitHub App private key (that one is issued by GitHub, not something this
# host can generate; write it into secrets/github_app_private_key.pem yourself, see
# secrets/README.md) — docker-compose.yml already wires the matching <NAME>_FILE var for every
# secret in this section, so if you go that route you can leave the plain vars below commented out
# entirely. Either path works; an inline value here always wins over a secret file if both are set.
GITHUB_APP_ID=123456
GITHUB_APP_SLUG=my-loopover-app
GITHUB_APP_PRIVATE_KEY_FILE=/run/secrets/github-app-private-key.pem # or GITHUB_APP_PRIVATE_KEY= inline
GITTENSOR_REGISTRY_URL=https://example.invalid/registry.json
# The four secrets below are commented out ON PURPOSE — do not paste a placeholder string here.
# Generate a real random value for EACH ONE individually (e.g. `openssl rand -hex 32`) and uncomment
# it; the app's boot-time preflight check refuses to start with a known-placeholder or too-short
# value, so copy-pasting the same string into more than one of these will also fail preflight. Or
# skip uncommenting these entirely and write the value into secrets/<name>.txt instead (see above).
# GITHUB_WEBHOOK_SECRET= # the sole HMAC key GitHub webhook deliveries are verified against
# LOOPOVER_API_TOKEN= # server-to-server API bearer token — bypasses per-repo write checks
# GITTENSORY_API_TOKEN= # no longer read (removed by #4777)
# LOOPOVER_MCP_TOKEN= # shared MCP bearer token
# GITTENSORY_MCP_TOKEN= # no longer read (removed by #4777)
# INTERNAL_JOB_TOKEN= # gates internal-only routes
# REQUIRED for the first-run /setup wizard that creates the GitHub App manifest, AND required ongoing:
# this exact origin is embedded as the <img src> for every visual-capture screenshot posted to a PR
# comment, so it MUST be reachable from GitHub's own servers, not just from this machine or your
# tailnet — a private/internal hostname here (e.g. a Tailscale MagicDNS `*.ts.net` address with no
# Funnel) makes every screenshot render as a broken image with no other warning besides this instance's
# own boot log (see PUBLIC_ORIGIN_ACKNOWLEDGED below).
PUBLIC_API_ORIGIN=https://reviews.example.com
# SELFHOST_SETUP_TOKEN= # generate a real random value the same way as above before setting this (or use secrets/selfhost_setup_token.txt, see above)
# REQUIRED for control-panel access. Comma/whitespace-separated GitHub logins. FAIL-CLOSED: unset
# means nobody (not even you) can sign into the dashboard.
ADMIN_GITHUB_LOGINS=your-github-login
# =============================================================================
# 2. Storage — sane defaults, no action needed for a trial/single-node instance
# =============================================================================
# SQLite is the default database (this file on the mounted data volume; migrations auto-apply).
# It's fine for a single maintainer instance. Move to Postgres (--profile postgres, see
# .env.example) once you're running multiple instances or a serious volume of repos.
DATABASE_PATH=/data/loopover.sqlite
# Redis is REQUIRED and starts automatically with the default compose stack (webhook dedup, rate
# limiting, the GitHub GET-response cache). Only override this if you're pointing at an external
# Redis instead of the bundled container.
REDIS_URL=redis://redis:6379
# =============================================================================
# 3. Start conservative — leave AI, RAG, and REES off until webhook delivery and the
# deterministic review are working (see the Quickstart "boot the stack" step)
# =============================================================================
SELFHOST_DEPLOYMENT_MODE=dry-run
LOOPOVER_REVIEW_REPOS=owner/repo
# GITTENSORY_REVIEW_REPOS=owner/repo # no longer read (removed by #4777)
LOOPOVER_REVIEW_SAFETY=true
# GITTENSORY_REVIEW_SAFETY=true # no longer read (removed by #4777)
LOOPOVER_REVIEW_GROUNDING=true
# GITTENSORY_REVIEW_GROUNDING=true # no longer read (removed by #4777)
LOOPOVER_REVIEW_RAG=false
# GITTENSORY_REVIEW_RAG=false # no longer read (removed by #4777)
LOOPOVER_REVIEW_ENRICHMENT=false
# GITTENSORY_REVIEW_ENRICHMENT=false # no longer read (removed by #4777)
# =============================================================================
# 4. AI provider — pick ONE block below and uncomment it (deterministic-only review if you skip
# this section entirely). See /docs/self-hosting-ai-providers for the full reference.
# =============================================================================
# --- Claude Code only (subscription) -----------------------------------------
# AI_PROVIDER=claude-code
# CLAUDE_CODE_OAUTH_TOKEN= # from `claude setup-token`
# --- Codex only (ChatGPT subscription) ----------------------------------------
# Codex is fail-closed by default for self-host PR review (its OAuth credential lives on the same
# filesystem prompt-influenced reviews can read) -- the explicit opt-in below is required, and you
# must mount your Codex auth at /data/codex (the image exposes it as ~/.codex).
# AI_PROVIDER=codex
# LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER=1 # strict "1"-only opt-in; any other value stays fail-closed
# --- Both, synthesized into one decision --------------------------------------
# AI_PROVIDER=claude-code,codex
# AI_COMBINE=synthesis
# CLAUDE_CODE_OAUTH_TOKEN=
# LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER=1
# =============================================================================
# 5. Telemetry — informational only, no action needed
# =============================================================================
# Running this image contributes anonymized gate-calibration data (verdict, outcome, cycle time --
# never repo/PR names, code, or logins) to loopover's central collector once your App is
# configured -- this starts automatically, it's the self-hosting contract, not a flag you turn on.
# The one way to disable it is the explicit air-gap flag below; see .env.example's Orb section for
# full privacy detail.
# ORB_AIR_GAP=true # air-gapped/OFFLINE deployments only: compute locally, never send
# =============================================================================
# 6. Decision-ledger anchoring — optional, and the one place self-host has that
# the hosted deployment does not
# =============================================================================
# Every verdict this instance persists appends to a hash-chained ledger, which already makes
# tampering WITHIN the chain detectable. Anchoring additionally publishes a signed checkpoint of the
# chain's tip somewhere you do not control, so rewriting history back past a published anchor means
# forging a signature at an external log too -- not just editing your own database.
#
# This is genuinely self-host territory: the hosted deployment does not execute reviews, so its
# decision_ledger is empty and there is nothing there to anchor. Your instance's ledger is YOURS --
# only your decisions, never other operators'.
#
# Generate both halves with the encodings the runtime expects:
#
# npm run ledger:anchor-keygen
#
# OPT-IN, but ALL-OR-NOTHING: setting only one half makes anchoring silently never run (preflight
# flags this, see src/selfhost/preflight.ts). Leave both unset to keep anchoring off.
# LOOPOVER_LEDGER_ANCHOR_KEYS= # public half: the JSON array, served by /v1/public/decision-ledger/anchor-key
# LOOPOVER_LEDGER_ANCHOR_PRIVATE_KEY= # SECRET, PKCS8 PEM. Must be ONE line, with the newlines
# written as literal backslash-n escapes: a real multi-line
# value breaks Docker's env_file parsing.
#
# Rekor shards ANNUALLY as log<year>-<rev>.rekor.sigstore.dev, and the built-in default can only ever
# lag behind the live one. If anchors record `status: failed` with a message naming this endpoint,
# the shard has rotated -- point this at the current one and no code change is needed.
# LOOPOVER_LEDGER_ANCHOR_REKOR_SHARD_URL=https://log2025-1.rekor.sigstore.dev
#
# Second backend, independent of Rekor: a git commit in a repo you own, cross-mirrored by GH Archive
# and Software Heritage the moment it is pushed. Unset means this backend simply does not run.
# LOOPOVER_LEDGER_ANCHOR_GIT_OWNER=
# LOOPOVER_LEDGER_ANCHOR_GIT_REPO= # a dedicated, public, otherwise-empty repo is the intended shape
# LOOPOVER_LEDGER_ANCHOR_GIT_BRANCH=main
# LOOPOVER_LEDGER_ANCHOR_GIT_PATH=anchors.jsonl
# LOOPOVER_LEDGER_ANCHOR_GIT_INSTALLATION_ID=
# --- Declaring unrecoverable rows (rare) ---------------------------------------------------------
# If your ledger carries rows whose record preimage is genuinely gone -- e.g. written by a version with
# the record-overwriting bug fixed in #9123 -- /v1/public/decision-ledger/verify will report ok:false
# forever. Rewriting those records so the digests match would be exactly the tampering the ledger exists
# to detect, so the honest alternative is to DECLARE them.
#
# Format "<fromSeq>-<toSeq>:<reason>". Both bounds and a reason are mandatory; the range and the count of
# rows it excuses are published by /verify even on a clean chain, so the exclusion is disclosed rather
# than hidden. Bounded by SEQ, never by time -- a date boundary would silently swallow new damage as the
# clock moved. CHAIN checks are never waived: a declared row that is mis-chained still fails.
#
# Malformed values waive NOTHING (preflight flags them) rather than widening the exclusion on a typo.
# LOOPOVER_LEDGER_CONTENT_WAIVER=5-257:rows written before the #9123 record-overwrite fix