Compare commits

...
Author SHA1 Message Date
beardthelion 66fb3ffc95 test(node): make the ownership guards actually observable
Re-running the mutation matrix after the ancestor check landed turned three
entries from load-bearing into inconclusive. The guards had not changed; the
tests had stopped being able to see them.

The ancestor walk masked both leaf checks. With the euid override armed the
whole path chain looks foreign, so a nested fixture tripped the ancestor error
first, and that message also contains "owned by uid", so the assertions matched
either way. Remove the leaf ownership check entirely and the tests stayed
green. They now target the tempdir itself, whose ancestors are /tmp: root-owned
and sticky, therefore trusted, so only the leaf is foreign.

The uid/gid mixup was invisible because uid equals gid on an ordinary
single-user machine, which makes reading the wrong field indistinguishable from
reading the right one. The fixture now chgrps to a supplementary group, which
needs no privilege, and degrades to the old behaviour where no such group
exists rather than quietly proving less.

With those two fixed and the ancestor and ordering mutations reshaped to name
the assertion that actually separates the cases, all eight entries come back
load-bearing.
2026-08-14 13:08:37 -05:00
beardthelion 5a93f2435c fix(review): close the ancestor path and the stat/read window
Review found the leaf checks were not the trust boundary. Both fixes come from
the same observation: what the guard inspects and what the node then uses were
not provably the same thing.

An ancestor the node does not control launders an unsafe path into a safe
looking one. A user owning /home/them/base can have the node use
/home/them/base/keys/p2p.key; the node creates keys and the key, so both are
node-owned, 0700 and 0600, and pass every check. That owner can then rename
keys aside, let the node generate a fresh identity, and move the old directory
back before a restart. They never own anything the leaf checks look at, and
they decide which identity the node presents and when it rolls back.
ensure_key_dir now walks the existing ancestors first, before creating
anything, since a directory the node made would pass afterwards by
construction.

Root counts as trusted, or /data under a root-owned / refuses on every normal
deployment. The mode rule is world-writable-without-sticky rather than group
too: group write is a narrower capability that needs group membership, and
refusing it would reject an ordinary umask-002 directory. Someone in an
ancestor's group can still rename the key directory; that residual is real and
stated rather than papered over.

read_p2p_keypair statted the path and then read the path again, so the file
approved by uid was not provably the file whose bytes became the identity. It
now opens once with O_NOFOLLOW, takes uid and mode from that handle, and reads
from it. The flag also refuses a symlink at the final component instead of
following it.

Two of the tests were weaker than their names. The ordering assertion passed
under either ordering, because a test-owned fixture makes the chmod succeed so
"could not be tightened" never appears; it now asserts the mode is untouched,
which is what actually separates them. The call-site assertions matched a
shared substring, so a swapped argument or a uid/gid mixup would have gone
unnoticed; they now name both uids in order and check which knob the
remediation points at.

Also moves a doc comment that had drifted onto the wrong test.
2026-08-14 12:19:53 -05:00
beardthelion 6dde36b02d fix(node): refuse a p2p key or key directory owned by another user
Mode bits were the only thing checked, and they do not make something
node-owned. A 0700 directory or a 0600 key file belonging to a different user
passes every permission check here while that user keeps the ability to replace
what is inside it, which means they choose the node's libp2p identity. That is
the capability the persisted key exists to take away.

Both sites now bail rather than warn. Unlike a loose mode this is not
repairable: chown needs privilege the node should not have, and taking
ownership of someone else's file would be wrong even if it could. In
ensure_key_dir the check runs before the mode repair, because a directory we do
not own fails its chmod with EPERM and reports "could not be tightened", which
describes the symptom and sends the operator at the wrong thing.

Testing this needed a seam. A test cannot chown a fixture to another user
without root, so a fixture-based test could only ever exercise the matching
case, which is a guard nobody has watched refuse anything. So the decision is a
pure function taking both uids, and a #[cfg(test)] euid override (the same
thread-local shape as the existing FAIL_KEY_WRITE injector) lets the wiring
tests drive the real read and directory paths while pretending to be a
different user. A further test pins that the seam defaults to the real geteuid,
since one that quietly stopped consulting it would leave every other ownership
test passing against nothing.

Found during review of the key-persistence change by two independent reviewers.
2026-08-14 11:41:55 -05:00
beardthelion 3a296485fb fix(node): scrub the serialized p2p private key from memory
Two buffers held the private key in its protobuf form and dropped without
scrubbing: the encoding produced when a new identity is generated, and the file
contents read back on every subsequent start. Both are now Zeroizing, matching
what gitlawb-core already does for its own key material.

Scope worth being honest about: this scrubs our copies of the serialized form,
not the libp2p Keypair itself, which owns the secret for the process lifetime
and exposes no way to zeroize it. The gain is that the encoded bytes do not
outlive the write and the read.

zeroize was already in the tree through gitlawb-core, so this promotes it to a
direct dependency of gitlawb-node and adds no packages; the lockfile change is
the one line recording that.
2026-08-14 07:11:22 -05:00
beardthelion f29235dc31 fix(review): reject .. in an absolute p2p key path too
The previous commit closed this for relative paths and exempted absolute ones,
reasoning that an absolute path cannot depend on the working directory. That is
true and it is not the hazard. `key_parent` hands `ensure_key_dir` the lexical
parent, so `/data/keys/../p2p.key` chmods `/data` rather than the `keys`
directory the path appears to name, and `/data/../p2p.key` run as root would
try to tighten `/` to 0700. The exemption also had a test asserting the first of
those was fine, so the gap was written down as intended behaviour.

`..` is now rejected wherever it appears. An absolute path's root counts as
naming a directory, so `/p2p.key` still validates and `/data/keys/p2p.key` is
unaffected.

Found by a second-model review pass after the in-process reviewers had cleared
the relative half.
2026-08-14 01:56:43 -05:00
beardthelion 1948d3d31b fix(review): close a .. escape from the p2p key-path check
Two reviewers found the same hole independently: the check rejected a path
naming no directory, but a relative parent that walks back out through `..`
named one and still landed in the working directory. `a/../p2p.key` and
`./keys/../p2p.key` resolve to the cwd itself and `../p2p.key` resolves above
it, so all three put the key exactly where the check exists to keep it out of,
and had ensure_key_dir chmod that directory to 0700 on the way. Verified by
running the paths through the predicate and printing where each parent lands.

The rule is now that a relative key path must name a directory and must not
walk back out: at least one Normal component, no ParentDir. `..` inside an
absolute path stays accepted, since it cannot depend on where the process
started. The predicate moves into names_no_usable_directory next to key_parent,
and the config gate and the load_or_create_p2p_keypair backstop both call it, so
they cannot drift apart.

Also fixes two smaller gaps found in the same pass:

- The permission fixture could report "1 passed" while asserting nothing. Its
  env gate returns early, and an early return is a passing test, so a renamed
  variable would look green. It now prints a sentinel after its assertions and
  the parent requires it. Confirmed by pointing the child at a different
  variable and watching the parent fail.
- A GITLAWB_P2P_KEY starting with `~/` is refused when no home directory
  resolves, instead of creating a literal `~` directory relative to wherever
  the node happened to start.

The backstop had no test, so it has one now, along with a both-directions test
for the predicate. That test cleans up after itself: with the guard removed it
really does write a key next to the source, which broke a later run once.
2026-08-14 01:44:07 -05:00
beardthelion 77331acbdb docs(node): scope the p2p key permission claim and note the rotation
The old wording said the key file is "created with owner-only permissions"
without qualification, which is only true on Unix: every permission path in
p2p/mod.rs is cfg(unix), so on other platforms the file inherits whatever the
directory gives it and nothing is enforced. Say what is actually enforced and
where.

Also document what operators now have to do rather than leaving them to
discover it:

- GITLAWB_P2P_KEY must name a directory, since a bare filename is refused at
  startup.
- The PeerId rotates once on the first start after upgrading, so a
  GITLAWB_P2P_BOOTSTRAP multiaddr pinning a peer's old id with a /p2p/<PeerId>
  suffix needs updating or dropping. Suffix-less addresses and the HTTP seed
  list are unaffected.
- If the node reports tightening a loose key directory, the key that was in it
  should be treated as possibly exposed and deleted so a fresh one is
  generated.
2026-08-13 23:49:16 -05:00
beardthelion 806c262fae test(node): run the key-permission probe in its own process
The probe zeroes the umask so the assertion means something: under a
restrictive ambient umask the bits are masked to 0600 regardless of whether
the code pins the mode, and the check passes either way.

Zeroing it in the shared test process is the problem. umask is process-global
and cargo runs these tests on threads, so any test creating a file in that
window inherits 000. Measured before this change: an unrelated concurrent
test's file was created 0666.

The probe now runs in a child process, where the zeroed umask cannot reach a
sibling and dies with the child. The parent is an ordinary test that runs
concurrently with everything else. Double-gated with #[ignore] plus an env
check so a bare --ignored sweep does not zero the umask in the shared process
after all.

The parent asserts the child ran exactly one test and that it passed, not
just that it exited 0. A libtest filter matching nothing runs zero tests and
still exits 0, so without that assertion a renamed fixture would read as a
green permission check while asserting nothing. Verified by pointing the
filter at a name that does not exist and watching the parent fail.
2026-08-13 23:47:06 -05:00
beardthelion 31b1176467 fix(node): require the p2p key path to name a directory
A bare filename in GITLAWB_P2P_KEY put the key in whatever directory the
process started from, and the directory guard was skipped entirely on that
path: Path::parent returns Some("") for a bare filename, which the caller
filtered out before ever reaching ensure_key_dir. The key file was created
0600 inside a directory that kept whatever mode it already had.

Config::validate now rejects a p2p key path that names no directory, so the
node says so at boot instead of starting with a key it cannot protect. That
placement is the point: an error raised in the p2p start path is logged and
stepped over, leaving the node running without p2p and reporting healthy.

The check is lexical on the tilde-resolved path. canonicalize would fail on a
parent that does not exist yet, which is the shipped ~/.gitlawb default and
every container's first boot, and comparing against the working directory
would reject /data/p2p.key under the image's WORKDIR, an absolute directory
the operator did name.

Three sites answered the parent question differently, which is how the gap
arose: one filtered the empty case out, one already normalized it, and one
opened "" and silently skipped its fsync. They now share key_parent, and
Config::validate calls it rather than adding a fourth answer.

load_or_create_p2p_keypair also refuses a path naming no directory. That is a
backstop behind the config gate, not the gate, so a later caller that skips
validation cannot quietly restore the old behaviour.
2026-08-13 23:04:23 -05:00
beardthelion 2a69a0bdfc style(node): comma instead of a dash in the key-load warning
House style avoids em dashes in text we write. The swarm-failure warning
beside it predates this branch and is left alone.
2026-08-13 21:40:26 -05:00
beardthelion f7fcd5edf5 fix(node): publish the p2p key atomically and pin its directory
Write the key to a scratch file in the same directory and hard-link it
onto the final path. The bytes are durable before any name points at
them, so a crash cannot leave a partial key that fails to load on the
next start and takes the node off the network until someone reads the
logs. A concurrent reader can no longer observe a half-written file
either, since the final name appears complete or not at all.

hard_link rather than rename: rename replaces its destination silently,
so refusing to clobber an existing key would depend on a check followed
by a separate rename, and a concurrent start can land in that gap.
hard_link is atomic and refuses an occupied path, including a symlink,
which it does not follow.

Create the key directory 0700 and tighten it when an existing one grants
group or other access. A 0600 key under a writable directory can still be
replaced or unlinked. Tightening rather than refusing to start, because
existing installs already have 0755 there and refusing would take p2p
down on all of them through a path that only warns.

Formatting on the branch is swept up here; it was already failing
cargo fmt --check before this change.
2026-08-13 21:40:26 -05:00
beardthelion 532ffc7202 fix(node): create the p2p key with 0600 at creation and reject a loose one
Open the key file with create_new and the mode set at creation, then
fsync, instead of writing it and narrowing the mode afterwards. The
secret is never on disk under a wider mode, an interrupted start cannot
leave it readable, and the exclusive open also refuses a pre-existing
entry at the path and makes a concurrent start take the key that landed
rather than clobber it.

Refuse to load a key file whose mode grants group or other access, and
name the observed mode so the operator can fix it. Report an empty key
file as empty rather than surfacing a protobuf decode error that blames
a missing rsa feature.

Pin GITLAWB_P2P_KEY onto the mounted volume in the Docker and fly
configs and document it, so the key does not depend on home-directory
resolution to land on persistent storage.
2026-08-13 21:40:26 -05:00
beardthelion f75b0f4afa fix(node): load the libp2p identity from the persistent key file
p2p::start now takes the Ed25519 keypair loaded by
load_or_create_p2p_keypair instead of computing one from the node DID,
so a node's network identity is generated once from the OS RNG and kept
on disk rather than recomputed from a public value on every start.

The node DID parameter is gone from start; the call site loads the key
first and continues without p2p if the key file cannot be read, matching
how a swarm-start failure is already handled.

The gossipsub message_id_fn is untouched and keeps its own hasher.
2026-08-13 21:40:26 -05:00
beardthelion 15d81c530c feat(node): add a persistent libp2p identity key file
Add p2p_key_path (--p2p-key-path / GITLAWB_P2P_KEY, default
~/.gitlawb/p2p.key) with a resolver mirroring resolved_key_path, and
load_or_create_p2p_keypair, which generates an Ed25519 keypair on first
start, persists it 0600, and loads it thereafter. Mirrors the existing
load_or_create_keypair idiom for the node identity PEM.

A corrupt or unreadable key file is a hard error naming the path rather
than a silent regeneration, so a disk problem cannot quietly rotate the
node's network identity.

Not yet wired into p2p::start; that follows.
2026-08-13 21:40:26 -05:00
11 changed files with 1394 additions and 36 deletions

No files matched your search

+11
View File
@@ -7,6 +7,17 @@
# Generate with: gl identity new
GITLAWB_KEY=/data/keys/identity.pem
# Path to the node's persistent libp2p identity key file. Must include a
# directory; the node refuses to start on a bare filename, because it will not
# keep its p2p identity key in the working directory. On Unix it is created
# 0600 inside a 0700 directory, and a loose key directory is tightened to 0700
# on start; on other platforms no permissions are enforced. If the node logs
# that it tightened a loose key directory, treat the key that was sitting there
# as possibly exposed: delete it so a fresh identity is generated on the next
# start. Keep it on a persistent volume so the PeerId survives redeploys.
# Default: ~/.gitlawb/p2p.key
#GITLAWB_P2P_KEY=/data/keys/p2p.key
# Publicly reachable URL of this node (used in peer announcements)
GITLAWB_PUBLIC_URL=https://your-node.example.com
Generated
+1
View File
@@ -3484,6 +3484,7 @@ dependencies = [
"tracing-subscriber",
"unicode-normalization",
"uuid",
"zeroize",
"zstd",
]
+1
View File
@@ -75,6 +75,7 @@ WORKDIR /data
ENV GITLAWB_REPOS_DIR=/data/repos \
GITLAWB_KEY=/data/keys/identity.pem \
GITLAWB_P2P_KEY=/data/keys/p2p.key \
GITLAWB_HOST=0.0.0.0 \
GITLAWB_PORT=7545 \
GITLAWB_P2P_PORT=7546
+22
View File
@@ -339,6 +339,7 @@ Important node settings:
| `GITLAWB_P2P_PORT` | libp2p QUIC/UDP port. Use `0` to disable. |
| `GITLAWB_BOOTSTRAP_PEERS` | Comma-separated HTTP peer URLs. |
| `GITLAWB_P2P_BOOTSTRAP` | Comma-separated libp2p multiaddrs. |
| `GITLAWB_P2P_KEY` | Path to the node's persistent libp2p identity key file, which fixes the PeerId across restarts. Must include a directory, such as `/data/keys/p2p.key` or `./keys/p2p.key`; the node refuses to start on a bare filename, because it will not keep its p2p identity key in the working directory. On Unix the file is created `0600` inside a `0700` directory, and a loose key directory is tightened to `0700` on start; on other platforms no permissions are enforced. Default `~/.gitlawb/p2p.key`; point it at a persistent volume when running in a container. |
| `GITLAWB_BOOTSTRAP_DISABLE_SEEDS` | Disable embedded seed peers for isolated dev/test networks. |
| `GITLAWB_REQUIRE_SIGNED_PEER_WRITES` | Require signed peer announce/sync writes. |
| `GITLAWB_AUTO_SYNC` | Enable automatic sync from known peers. |
@@ -362,6 +363,27 @@ Important node settings:
Production note: change the default Postgres password before exposing a node publicly.
### Upgrading: the PeerId rotates once
This node's libp2p identity is now a keypair generated on first start and kept
at `GITLAWB_P2P_KEY`, rather than one derived from the node DID. Every node
therefore gets a new PeerId once, on the first start after upgrading, and keeps
it from then on as long as that key file survives (put it on a persistent volume
in a container).
Two things to check before upgrading:
- Any `GITLAWB_P2P_BOOTSTRAP` multiaddr that pins a peer's old PeerId with a
`/p2p/<PeerId>` suffix stops matching once that peer upgrades. Update the
suffix, or drop it and let identify supply the current one. Addresses without
the suffix keep working untouched.
- `GITLAWB_P2P_KEY` must name a directory. A bare filename is refused at
startup, since the node will not keep its identity key in the working
directory.
Peers found over `GITLAWB_BOOTSTRAP_PEERS` and the embedded seed list are
unaffected, since those are HTTP URLs and carry no PeerId.
---
## Optional node staking
+1
View File
@@ -33,6 +33,7 @@ sqlx = { version = "0.8", features = ["postgres", "runtime-tokio-rustls", "chron
clap = { version = "4", features = ["derive", "env"] }
bytes = "1"
libc = "0.2"
zeroize = "1"
cid = { workspace = true }
hex = { workspace = true }
sha2 = { workspace = true }
+134 -1
View File
@@ -1,5 +1,5 @@
use clap::Parser;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
/// Upper bound on `git_service_timeout_secs` and `ipfs_request_budget_secs`, in seconds
/// (100 years).
@@ -104,6 +104,10 @@ pub struct Config {
#[arg(long, env = "GITLAWB_P2P_PORT", default_value_t = 7546)]
pub p2p_port: u16,
/// Path to the persistent libp2p identity key
#[arg(long, env = "GITLAWB_P2P_KEY", default_value = "~/.gitlawb/p2p.key")]
pub p2p_key_path: String,
/// libp2p bootstrap multiaddrs (comma-separated)
/// Example: /ip4/1.2.3.4/udp/7546/quic-v1/p2p/12D3KooW...
#[arg(long, env = "GITLAWB_P2P_BOOTSTRAP", value_delimiter = ',')]
@@ -556,6 +560,16 @@ impl Config {
PathBuf::from(&self.key_path)
}
/// Resolve ~ in p2p_key_path
pub fn resolved_p2p_key_path(&self) -> PathBuf {
if self.p2p_key_path.starts_with("~/") {
if let Some(home) = dirs_next::home_dir() {
return home.join(&self.p2p_key_path[2..]);
}
}
PathBuf::from(&self.p2p_key_path)
}
/// DB connections reserved for everything other than held write-locks: auth
/// lookups, visibility-rule reads, the post-receive tail's own DB writes, and
/// admin tooling. A write pins one pooled connection for its whole duration, so
@@ -583,6 +597,48 @@ impl Config {
floor
));
}
// A p2p key path naming no directory puts the node's private key in
// whatever directory the process was started from. The node cannot
// protect that: `ensure_key_dir` would have to chmod a directory the
// operator never nominated as a key directory, and a directory it
// cannot secure is one where any local user with write access can
// replace the key and choose the node's libp2p identity. Refuse it here,
// where the denial actually stops the process, rather than in the p2p
// start path, where main.rs logs the error and keeps serving with a
// green /health.
//
// Decided lexically on the resolved path: `canonicalize` would fail on a
// parent that does not exist yet (the shipped `~/.gitlawb` default, and
// every container's first boot), and comparing against the process
// working directory would reject `/data/p2p.key` under the image's
// WORKDIR, an absolute directory the operator did name.
// `resolved_p2p_key_path` expands a leading `~/` only when a home
// directory is resolvable, and otherwise hands back the literal string.
// That would leave the shipped default naming a directory called `~`
// relative to wherever the process started, which is a real directory
// the node would create and chmod, and whose location moves with the
// working directory. It passes the check below because `~` is an
// ordinary path component, so it has to be caught separately.
let p2p_key_path = self.resolved_p2p_key_path();
if self.p2p_key_path.starts_with("~/") && p2p_key_path == Path::new(&self.p2p_key_path) {
return Err(format!(
"GITLAWB_P2P_KEY ({}) starts with `~/` but no home directory could be resolved, \
so it would name a literal `~` directory relative to the working directory. \
Set an absolute path such as /data/keys/p2p.key.",
self.p2p_key_path
));
}
if crate::p2p::names_no_usable_directory(&p2p_key_path) {
return Err(format!(
"GITLAWB_P2P_KEY ({}) must include a directory that does not walk back through \
`..`, such as ./keys/p2p.key or /data/keys/p2p.key: the node will not store its \
p2p identity key in the working directory, where the directory holding it \
cannot be secured.",
self.p2p_key_path
));
}
Ok(())
}
}
@@ -973,4 +1029,81 @@ mod tests {
"db_max_connections at the floor (pushes + headroom) must validate"
);
}
fn config_with_p2p_key(path: &str) -> Config {
Config::parse_from(["gitlawb-node", "--p2p-key-path", path])
}
/// A p2p key path that names no directory component would put the node's
/// private key in whatever directory the process happens to be started from,
/// which `ensure_key_dir` cannot protect without tightening a directory the
/// operator never nominated. Reject it at boot instead.
#[test]
fn p2p_key_path_without_a_directory_component_is_rejected() {
for path in [
// No directory component at all.
"p2p.key",
"./p2p.key",
"././p2p.key",
"p2p.key/",
"",
// Looks like it names a directory and does not: each of these
// resolves back to the working directory or above it, so accepting
// them would defeat the check and chmod an unnominated directory.
"a/../p2p.key",
"./keys/../p2p.key",
"../p2p.key",
// Absolute too: the lexical parent is what gets chmodded, so these
// would tighten /data and / rather than the named directory.
"/data/keys/../p2p.key",
"/data/../p2p.key",
] {
let err = config_with_p2p_key(path)
.validate()
.expect_err(&format!("{path:?} names no directory and must be rejected"));
assert!(
err.contains("directory"),
"{path:?} must be rejected for naming no directory, got: {err}"
);
}
}
/// The mirror of the above, and the case that stops the predicate widening
/// into "reject every relative path". The shipped default is included on
/// purpose: a predicate that rejects it is a boot failure for every node.
#[test]
fn p2p_key_path_naming_a_directory_is_accepted() {
for path in [
"keys/p2p.key",
"./keys/p2p.key",
"/data/keys/p2p.key",
"/data/p2p.key",
"~/.gitlawb/p2p.key",
] {
assert!(
config_with_p2p_key(path).validate().is_ok(),
"{path:?} names a directory and must be accepted"
);
}
Config::parse_from(["gitlawb-node"])
.validate()
.expect("the shipped default p2p key path must validate");
}
/// The one input that separates validating the raw config string from
/// validating `resolved_p2p_key_path()`. Raw, `~/` has an empty parent and
/// would be rejected; resolved, it is the home directory, whose parent is a
/// real directory, so it is accepted. Every other tilde path is accepted
/// under both readings and therefore proves nothing.
#[test]
fn p2p_key_path_is_checked_after_tilde_expansion() {
if dirs_next::home_dir().is_none() {
panic!("this test needs a home directory to distinguish raw from resolved");
}
assert!(
config_with_p2p_key("~/").validate().is_ok(),
"`~/` resolves to the home directory, whose parent is a real directory"
);
}
}
+27 -14
View File
@@ -229,22 +229,35 @@ async fn main() -> Result<()> {
.filter_map(|s| s.parse().ok())
.collect();
let shutdown_rx = shutdown_tx.subscribe();
match p2p::start(
&node_did.to_string(),
config.p2p_port,
bootstrap_addrs,
Arc::clone(&db),
config.auto_sync,
shutdown_rx,
)
.await
{
Ok(handle) => {
info!(port = config.p2p_port, peer_id = %handle.local_peer_id, "libp2p swarm started");
Some(Arc::new(handle))
match p2p::load_or_create_p2p_keypair(&config.resolved_p2p_key_path()) {
Ok(local_key) => {
match p2p::start(
local_key,
config.p2p_port,
bootstrap_addrs,
Arc::clone(&db),
config.auto_sync,
shutdown_rx,
)
.await
{
Ok(handle) => {
info!(port = config.p2p_port, peer_id = %handle.local_peer_id, "libp2p swarm started");
Some(Arc::new(handle))
}
Err(e) => {
tracing::warn!(err = %e, "failed to start libp2p swarm — continuing without p2p");
None
}
}
}
// Deliberately non-fatal, and the cost is worth naming: an
// unreadable key file takes the node off the p2p network for the
// whole run while /health keeps reporting healthy, so the outage is
// visible only to whoever reads the logs. Making it fatal, or
// surfacing it in the health response, is its own change.
Err(e) => {
tracing::warn!(err = %e, "failed to start libp2p swarm — continuing without p2p");
tracing::warn!(err = %e, "failed to load p2p identity key, continuing without p2p");
None
}
}
File diff suppressed because it is too large. Load diff
+1
View File
@@ -12,6 +12,7 @@ primary_region = "iad"
GITLAWB_P2P_PORT = "7546"
GITLAWB_REPOS_DIR = "/data/repos"
GITLAWB_KEY = "/data/keys/identity.pem"
GITLAWB_P2P_KEY = "/data/keys/p2p.key"
GITLAWB_PUBLIC_URL = "https://gitlawb-node-test.fly.dev"
GITLAWB_BOOTSTRAP_PEERS = "https://node.gitlawb.com,https://node2.gitlawb.com,https://node3.gitlawb.com"
GITLAWB_AUTO_SYNC = "true"
+1
View File
@@ -15,6 +15,7 @@ primary_region = 'sjc'
GITLAWB_HOST = '0.0.0.0'
GITLAWB_KEY = '/data/keys/identity.pem'
GITLAWB_MAX_PACK_BYTES = '524288000'
GITLAWB_P2P_KEY = '/data/keys/p2p.key'
GITLAWB_P2P_PORT = '7546'
GITLAWB_PORT = '7545'
GITLAWB_PUBLIC_URL = 'https://node2.gitlawb.com'
+1
View File
@@ -15,6 +15,7 @@ primary_region = 'nrt'
GITLAWB_HOST = '0.0.0.0'
GITLAWB_KEY = '/data/keys/identity.pem'
GITLAWB_MAX_PACK_BYTES = '524288000'
GITLAWB_P2P_KEY = '/data/keys/p2p.key'
GITLAWB_P2P_PORT = '7546'
GITLAWB_PORT = '7545'
GITLAWB_PUBLIC_URL = 'https://node3.gitlawb.com'