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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# VGI bridge configuration — one community, one bridge (design §5.7).
#
# You rarely need to start from this file: `vgi-bridge setup --vtc <VTC DID>
# --vta <VTA DID> --dir <folder> …` writes a complete bridge.toml in VTA mode
# — the registry and mediator read from the VTC's DID document, the
# verify-trust action pinned to its release commit, the web-flow key fetched,
# the VTA credential provisioned — plus a service file (docs/BRIDGE.md §2).
# This file documents every key, for editing that config or writing one by
# hand (docs/BRIDGE.md §8). Use absolute paths; the examples below use a
# folder in the operator's home, /home/ops/vgi-bridge.
#
# Nothing secret belongs in this file: keys, tokens and passwords live in the
# sealed store — or, in VTA mode (the `[vta]` section below), in the bridge's
# trust context of the VTC's VTA (`vgi-bridge secret set …`, the GitHub
# manifest flow). Unknown keys are refused at start-up.
# The one VTC this bridge serves. Jobs signed by any other DID are refused.
= "did:webvh:QmVtcScid7:acme-vtc.example"
# The git-ns/bridge/event version sent to that VTC: "0.3" (the default; it
# reports the bridge's role map, BRIDGE.md §6c), or "0.2" / "0.1" until the
# VTC understands 0.3 (BRIDGE.md §7, "Event versions"). Set "0.4" — never by
# default — once the VTC lists git-ns/bridge/event/0.4 in its discovery
# answer: it adds the pull requests opened and reopened, which the VTC's
# pull-request gate decides on (BRIDGE.md §6d). Below 0.4 no pull request
# is reported.
# event_version = "0.3"
# The community's Trust Registry (for the bootstrap and the bridge's check):
# the TrustRegistry service of the VTC's DID document (setup reads it there).
= "did:webvh:QmRegScid3:registry.acme-vtc.example"
# The mediator the bridge's DID is reachable through (the VTC's), for TSP
# and DIDComm alike: the TSPTransport / DIDCommMessaging service of the VTC's
# DID document (setup reads it there).
# The did:peer `vgi-bridge init` mints names it in the identifier: changing
# it later means minting a new identity and registering it at the VTC.
= "did:web:mediator.acme-vtc.example"
# Where the forges reach the bridge, through the TLS proxy in front of it.
= "https://bridge.acme-vtc.example/"
# Plain HTTP behind the proxy or tunnel: only it may reach this. Loopback
# with the proxy on the same host (what setup writes); all interfaces,
# "0.0.0.0:8080" (the built-in default), is right only inside a container
# whose port is published to the proxy alone.
= "127.0.0.1:8080"
# The state store (the built-in default, /var/lib/vgi-bridge, is the
# container image's volume).
= "/home/ops/vgi-bridge/data"
# Self-contained mode (`setup --self-contained`): the master key that seals
# every secret, an owner-only file (`init` creates it). Back it up apart from
# the data directory. Not used (and refused) in VTA mode.
= "/home/ops/vgi-bridge/master-key"
# …or an environment variable instead:
# master_key_env = "VGI_BRIDGE_MASTER_KEY"
# VTA mode (recommended; BRIDGE.md §2a): the bridge's DID, keys, secrets and
# state live in its own trust context of the VTC's VTA, and this host holds
# only a context-scoped credential. Losing the host then loses nothing: issue
# a new credential and start the bridge on an empty data directory. Remove
# `master_key_file` / `master_key_env` when you turn it on.
# [vta]
# context = "vgi-bridge"
# # The credential bundle the VTA issued (JSON; owner-only file). setup
# # provisions it into the folder.
# credential_file = "/home/ops/vgi-bridge/vta-credential.json"
# # …or an environment variable (cleared once read):
# # credential_env = "VGI_BRIDGE_VTA_CREDENTIAL"
# # The bridge reaches the VTA over TSP when the VTA advertises it, else
# # DIDComm — never REST (the VTA releases keys only end to end); through
# # this mediator, by default the bridge's own.
# # mediator_did = "did:web:mediator.acme-vtc.example"
# # url = "https://vta.acme-vtc.example"
# # The bridge's DID; default: the context's DID.
# # did = "did:webvh:…"
# # How long start-up waits for an unreachable VTA, and how often the bridge
# # asks it whether its keys were rotated (at least 30; SIGHUP asks at once).
# # start_timeout_secs = 300
# # key_refresh_secs = 60
# # How long a newly listed signing key must be in the DID document before
# # the bridge signs with it (verifiers' cached copies must have it first).
# # signing_switch_after_secs = 86400
# How long a resolved DID document is trusted (the VTC's, the registry's,
# commit signers'), in seconds; a failure is re-checked against a fresh one.
# did_cache_ttl_secs = 60
# Oldest job accepted, in seconds (plus a minute of clock skew).
# max_job_age_secs = 300
# Largest request body read, in bytes.
# max_body_bytes = 2097152
# Drift sweep for forges without webhooks, and the result/event retry.
# drift_sweep_secs = 3600
# resend_secs = 60
# How long a bind or account link waits for the person.
# flow_ttl_secs = 900
[]
# What the bootstrap writes into repositories (and the required workflow).
# setup pins this to the commit of its own release tag; by hand:
# gh api repos/OpenVTC/verifiable-git-infrastructure/commits/<version> --jq .sha
= "OpenVTC/verifiable-git-infrastructure/.github/actions/verify-trust@<40-hex commit>"
= "v0.16.0"
# Required by the Forgejo plan: SHA-256 of the release tarball.
# sha256 = "<64 hex>"
# required_check = "Verify commit trust"
# The Trust Registry binding: auto (default; no fallback), tsp, didcomm, or
# https. auto is TSP, then DIDComm, then HTTPS, whichever the registry
# advertises first — for the written workflows and for the check the bridge
# posts itself (which queries as the bridge's own DID, over its mediator
# link). Use "https" while the
# registry's mediator does not admit a CI run's throwaway DID
# (docs/RUNBOOK.md, "Registry discovery") or the bridge's DID.
# transport = "auto"
[]
# The check the bridge posts itself (GitHub, outside a required workflow).
# max_commits = 250
# max_signers = 16
# git = "git"
# fetch_timeout_secs = 120
# max_fetch_bytes = 67108864
# concurrency = 4
[]
# The Dependabot re-sign (docs/BRIDGE.md §6a): the committer on re-signed
# commits. The signer is the bridge's DID, named in the Signed-by-DID trailer.
# committer_name = "VGI bridge"
# committer_email = "vgi-bridge@noreply.invalid"
# Which forge role each repository right gets (docs/BRIDGE.md §6c). The
# defaults are shown; [github.role_map], [github.namespaces.<owner>.role_map]
# and [github.namespaces.<owner>.repos.<name>.role_map] (and the same under
# [forgejo…]) override them field by field, most specific first. Must stay
# own >= maintain >= commit, with commit at most "write", and only own may be
# "admin" (a map giving maintain or commit "admin" fails the start). There is
# no key for git.ns.admin: a namespace admin never gets a forge role.
[]
# own = "admin"
# maintain = "maintain" # on Forgejo: write + the merge allow-list
# commit = "none" # "write" lets committers push branches
# One [[github]] entry per organisation (or account) the community binds:
# GitHub installs a private App only on its owner, so each organisation gets
# its own App — registered with one click each — and this one bridge holds
# them all, keyed by (host, app_owner). Copy the entry for another org with
# its own app_owner and app_name.
[[]]
= "github.com"
# The App the manifest flow registers. Unique per GitHub instance: every
# entry names its own.
= "acme-vgi-bridge"
# Required: the org the App is registered under (and owned by). For a
# personal account, name it and set app_owner_is_user = true.
= "acme"
# app_owner_is_user = false
# Optional: GitHub's web-flow key, the exempt keyring for commits GitHub
# signs (web-UI merges, merge queues). The bridge-posted check works without
# it (such commits then fail); the in-repo and required-workflow plans need it,
# and the Dependabot re-sign checks Dependabot's commits against it (without
# it, nothing is re-signed).
# setup fetches it; by hand:
# curl -fsSL https://github.com/web-flow.gpg > /home/ops/vgi-bridge/web-flow.asc
= "/home/ops/vgi-bridge/web-flow.asc"
# Post the check from the bridge where no org required workflow is
# available (personal accounts, orgs without org rulesets). Leave on.
# bridge_checks = true
# Dependabot's account, as GitHub reports it (GET /users/dependabot[bot]).
# These are github.com's; a GHES instance has its own id.
# dependabot_login = "dependabot[bot]"
# dependabot_id = 49699333
# Re-signing Dependabot pull requests is on for every namespace; turn it off
# for one by its owner's login (lowercase):
# [github.namespaces.acme]
# resign_dependabot = false
# Role-map overrides for one namespace, and for one repository in it:
# [github.namespaces.acme.role_map]
# maintain = "write"
# [github.namespaces.acme.repos.widgets.role_map]
# commit = "write"
# [[forgejo]]
# base_url = "https://codeberg.org/"
# bot_login = "acme-vgi-bot"
# oauth_client_id = "<the bridge's OAuth2 application on the instance>"
# rotate_token_days = 30
# instance_signing_key_fallback = false
# The runner label the bootstrap's workflow asks for (runs-on:). Default
# "docker"; the job image needs glibc 2.39+.
# runs_on = "docker"
# Maintainers as plain write on this instance, without the merge allow-list:
# [forgejo.role_map]
# maintain = "write"