Files
ngit-grasp/docs/how-to/verify-stored-events.md
DanConwayDev 053ee62610 chore(release): prepare v3.0.9 security patch
Align Cargo and NixOS package versions and collect the accumulated changes in a dated release entry. Put Security first, followed by Fixed and Added, and place the optional historical event audit guidance under Security.

The vulnerabilities were reported from code review with no exploitation reported to us. Admission protection takes effect on upgrade; an offline historical scan is an optional precaution, and purging follows inspection of its report. Preserve the stopped-service requirement and historical recovery limits in both release notes and the repair guide.

This commit changes release metadata and guidance only; it does not alter runtime behavior or publish the release. Validation: locked offline Cargo metadata, Nix module parsing, cargo fmt and git diff checks passed. Implementation CI is checked separately against dfbed25e.

Assisted-by: GPT-6
2026-10-27 10:27:42 +00:00

4.8 KiB

Verify and purge stored events

Optionally use ngit-grasp event-integrity-check after upgrading to v3.0.9 to check data retained by an older relay. The reported vulnerabilities were found by code review; no exploitation has been reported to us. Upgrading enables the admission checks without requiring this historical scan. The command recomputes each event ID and verifies its signature independently of the SDK cache. It supports the persistent LMDB backend; an in-memory database does not survive shutdown.

Stop the relay for both report-only and execute runs, and keep it stopped until the repair is complete. This is an offline maintenance command, not a request to the running relay. Running it against live stores can race admission and checkpoints. Use the effective data paths of the instance being repaired, including any configured private-mode path suffix.

Back up and inspect

Stop your instance using its service manager (for example, systemctl stop ngit-grasp-<instance> for a NixOS instance). Make a backup while it is stopped. The following commands use explicit example paths; replace them with your instance's paths and a new backup directory:

mkdir /srv/grasp-backup-before-event-repair
cp -a /var/lib/ngit-grasp/relay /srv/grasp-backup-before-event-repair/relay
cp -a /var/lib/ngit-grasp/git /srv/grasp-backup-before-event-repair/git

ngit-grasp event-integrity-check \
  --relay-data-path /var/lib/ngit-grasp/relay \
  --git-data-path /var/lib/ngit-grasp/git \
  > event-integrity-report.jsonl

Without --execute, no events or checkpoints are changed. An invalid-payload finding makes the command exit nonzero after writing its summary. Read errors, invalid checkpoint formats, and missing required paths also exit nonzero; they must not be mistaken for a completed clean scan. A mistyped LMDB path is rejected instead of creating an empty database.

Each invalid_event JSON line records its store, claimed ID, claimed author, kind, claimed repository identifier (if present), and verification error. These identity fields are untrusted. The final summary gives checked, invalid and purged payload counts and reset negative-cache counts per store. Preserve the report alongside the backup.

Purge invalid payloads

With the relay still stopped, run:

ngit-grasp event-integrity-check \
  --relay-data-path /var/lib/ngit-grasp/relay \
  --git-data-path /var/lib/ngit-grasp/git \
  --execute > event-integrity-purge.jsonl

# A successful repair should now produce a clean summary.
ngit-grasp event-integrity-check \
  --relay-data-path /var/lib/ngit-grasp/relay \
  --git-data-path /var/lib/ngit-grasp/git

The command scans the main database, existing tombstone, holding and replacement history stores, the purgatory and rejected-event checkpoints, and the durable .grasp/pending-saves/ journal under the Git directory. It removes invalid payloads and their linked internal history/deletion metadata. It also resets payload-free expiry and rejection caches: their authenticity cannot be checked without the original events, and retaining them could block genuine recovery after an interrupted repair. This may increase sync traffic temporarily. Valid payloads in another store are preserved even if an invalid copy claimed the same ID. PR placeholders without an event and valid pending events are preserved.

Removal uses exact stored IDs and the deletion lifecycle's request-removal primitive. It does not issue a signed NIP-09 request, create a permanent ID tombstone, cascade through a forged event's tags, or delete Git archives. A subsequently recovered genuine event can therefore reuse its correct ID. If an execute run fails partway through, leave the relay stopped, resolve the reported error, and rerun it; removal is idempotent. Database scanning uses pages plus a complete timestamp-boundary bucket, so memory usage depends on the largest number of events sharing one timestamp rather than all stored payloads.

Restart the upgraded relay after the clean scan. In-memory authority indexes will be rebuilt from the remaining events. For a known affected repository, the existing online integrity command can check and repair its Git storage and refs against retained authoritative event state:

ngit-grasp integrity-check --identifier my-repository \
  --git-data-path /var/lib/ngit-grasp/git --repair

This queues work in the running relay; inspect the service logs for its outcome. Payload purging cannot reconstruct previously overwritten events, deleted Git objects, or data no longer retained locally or by a trusted peer. It also cannot prove that a correctly signed event was authorized by the repository's policy. Keep the backup for investigation and recovery of those cases. Do not substitute holding-eject for this command: that command permanently removes retained repository recovery data.