Skip to content

gef + rizin: the scriptable half of the reverse-engineering loadout - #547

Merged
bryan-minimal merged 4 commits into
mainfrom
reveng-loadout
Aug 3, 2026
Merged

gef + rizin: the scriptable half of the reverse-engineering loadout#547
bryan-minimal merged 4 commits into
mainfrom
reveng-loadout

Conversation

@bryan-minimal

@bryan-minimal bryan-minimal commented Jul 31, 2026

Copy link
Copy Markdown
Member

The other half of the reverse-engineering loadout: the scriptable disassembler, and the thing that makes gdb worth sitting next to a decompiler. Follows #544 (gdb, merged) and pairs with #545 (ghidra).

rizin 0.9.1 — the use_sys_* decisions ARE the package

Ghidra answers "what does this function do"; rizin answers "run that over 400 binaries and diff the results" — the shape this distro's own tooling works in.

All seventeen use_sys_* options default to disabled, so out of the box rizin statically links its own zlib, zstd, xz, lz4, pcre2, openssl and tree-sitter. Those copies are invisible to pkgscan: a CVE in any of them would never appear against this package. For a distro whose premise is supply-chain vuln tracking, seven silently-vendored libraries is the wrong default.

All seven now link from the system — verified in the built tree:

libz.so.1   libzstd   liblzma.so   liblz4   libpcre2-8/16/32
libcrypto.so.3   libtree-sitter.so.0.26

Deliberately left vendored, and named rather than left to be discovered: capstone (rizin defaults to use_capstone_version=next — the unreleased capstone 6, so a "system" capstone would be a different disassembler than it was tested against), plus libzip / magic / zydis / xxhash / libmspack / softfloat / blake2 / blake3, which we do not package.

--wrap-mode=nodownload is what makes it hermetic: the official rizin-src tarball vendors its subprojects, and the flag makes meson fail rather than reach for the network if one is ever missing.

Licence recorded as GPL-3.0-or-later, not the LGPL-3.0-only of the core — the linked binary aggregates a 16-licence REUSE union including GPL-3.0 and GPL-2.0 files, so the permissive core alone would understate it.

gef 2026.01 — a launcher, not a dotfile edit

MIT, and genuinely a single file: gef.py is 433 KB of Python whose every import is stdlib.

Upstream's install instructions append a source line to ~/.gdbinit, which would make this package mutate the user's home directory and silently change the behaviour of every unrelated gdb invocation on the machine. Instead gef is a separate entry point — gdb with gef loaded — and gdb stays exactly what it was.

gef.py asserts GDB_MIN_VERSION (10,0) and PYTHON_MIN_VERSION (3,10) at import time; ours are 17.2 and 3.14. The gdb package from #544 is built --with-python precisely so this works, and that flag is pinned by a test over there rather than trusted.

Tests, targeting the failure each package actually has

Both mutation-tested — breaking any assertion makes minimal check fail.

rizin system_libs — meson probes for each system library and falls back to the vendored subproject when one is missing, printing a note and carrying on to a successful build. You would get a working rizin with seven invisible bundled libraries: exactly what the flags exist to prevent, and nothing else would notice. The test asserts all seven appear in the librz_* DT_NEEDED.

Two bugs in my own first version of that test, both caught by running it: it used readelf without declaring binutils (failed loudly — correct), and it asserted against /usr/bin/rizin, which is a thin frontend carrying none of these. The linkage lives in librz_*.so.

gef loads_into_gdb — there is no compile step, so the only way this package breaks is gdb failing to import it, and that is quiet: gdb prints the traceback to stderr, carries on to a normal prompt, and exits 0. So nothing asserts on the exit code. One test checks gef help registers as a command (only true if the file imported to its last line); the other checks no Traceback appears, since a partial import leaves gef present with most commands missing.

Verified

minimal package --rebuild --no-fetch {gef,rizin}   exit 0
minimal check --packages {gef,rizin}               14/14 each
rizin                                              ELF aarch64, 8 rz-* tools
reproducibility                                    byte-identical across rebuilds
pkgmgr check                                       both resolve up_to_date

Why the reveng loadout is not in this PR yet

It was, and I removed it — because it does not build. stacks/reveng/stack.ncl references ghidra, which lands in #545, and the whole repo then fails to evaluate:

Error: package 'ghidra' does not exist

That is not theoretical: it broke every build on my working branch, including gef and rizin, which were fine. Worth knowing that minimal check --stacks does not catch it — I tested packages valid against a deliberately nonexistent package name and it still reported Pass. Only a build catches a bad stack reference.

So the loadout commit is ready and will be pushed to this same branch the moment #545 merges, keeping it one PR for the final bunch. Its content is unchanged from what I verified locally alongside ghidra: 6/6 stack checks, and a build_cmd that exercises all four anchors rather than merely listing them — because each fails silently in its own way.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added the GEF package with a GDB launcher and Python debugging support.
    • Added Rizin 0.9.1 for binary analysis and reverse engineering.
    • Added an opt-in reverse-engineering stack with Ghidra, Rizin, GDB, GEF, and supporting tools.
  • Quality
    • Added installation, version, integration, executable-analysis, and runtime-library validation.
    • Builds use verified upstream sources and reproducible settings.

MIT, and genuinely a single file: gef.py is 433 KB of Python whose every
import is stdlib. No build step, no dependencies to vendor.

Installed as a LAUNCHER, not a dotfile edit. Upstream's instructions
append a source line to ~/.gdbinit, which would have this package mutate
the user's home directory and silently change the behaviour of every
unrelated gdb invocation on the machine. Instead `gef` is gdb with gef
loaded, and `gdb` stays exactly what it was.

gef.py asserts GDB_MIN_VERSION (10,0) and PYTHON_MIN_VERSION (3,10) at
import time and refuses to load otherwise; ours are 17.2 and 3.14. The
gdb package is built --with-python precisely so this works — without it
gdb reports 'Python scripting is not supported in this copy of GDB' and
gef cannot load at all.

TESTED FOR THE FAILURE THAT MATTERS. There is no compile step, so the
only way this package breaks is gdb failing to IMPORT gef — and that is
quiet: gdb prints the traceback to stderr, carries on to a normal
prompt, and exits 0. So nothing asserts on gdb's exit code. One test
asserts `gef help` registers as a command (only true if gef.py imported
to the last line), a second asserts no Traceback appears (a partial
import would leave gef present but most commands missing).

Mutation-tested: breaking the assertion makes minimal check FAIL, so it
is not vacuous.

Built and verified locally, not proposed for merge yet:
  minimal package --rebuild --no-fetch gef   exit 0
  minimal check --packages gef               14/14 pass
  usr/bin/gef                                52-byte launcher, 0755
  usr/share/gef/gef.py                       433,482 bytes, byte-identical

Stacked on the gdb branch, which it needs at runtime.
The scriptable counterpart to Ghidra. Ghidra answers 'what does this
function do'; rizin answers 'run that over 400 binaries and diff the
results' — which is the shape this distro's own tooling works in.

THE use_sys_* DECISIONS ARE THE PACKAGE, not the build.

All seventeen use_sys_* options default to DISABLED, so out of the box
rizin statically links its own zlib, zstd, xz, lz4, pcre2, openssl and
tree-sitter. Those copies are invisible to pkgscan: a CVE in any of them
would never appear against this package. For a distro whose premise is
supply-chain vuln tracking, seven silently-vendored libraries is the
wrong default, so all seven we package are flipped to system.

Deliberately left vendored, and named rather than left to be discovered:
capstone (rizin defaults to use_capstone_version=next — the UNRELEASED
capstone 6, so a 'system' capstone would be a different disassembler
than it was tested against), plus libzip/magic/zydis/xxhash/libmspack/
softfloat/blake2/blake3, which we do not package.

--wrap-mode=nodownload makes the build hermetic: the official rizin-src
tarball vendors its subprojects, and the flag makes meson FAIL rather
than reach for the network if one is ever missing.

Licence recorded as GPL-3.0-or-later, not the LGPL-3.0-only of the core:
the linked binary aggregates a 16-licence REUSE union including GPL-3.0
and GPL-2.0 files, so the permissive core alone would understate it.

TESTED FOR THE SILENT FAILURE. meson PROBES for each system library and
falls back to the vendored subproject when one is missing — printing a
note and carrying on to a successful build. You would get a working
rizin with seven invisible bundled libraries, i.e. exactly what these
flags exist to prevent, and nothing else here would notice. The test
asserts all seven appear in the librz_* DT_NEEDED.

Two bugs in my own first version of that test, both caught by running
it: it used readelf without declaring binutils (failed loudly, correct),
and it asserted against /usr/bin/rizin, which is a thin frontend that
carries none of these — the linkage lives in librz_*.so.

Mutation-tested: breaking the assertion fails minimal check.

Built and verified locally, not proposed for merge:
  minimal package --rebuild --no-fetch rizin   exit 0
  minimal check --packages rizin               14/14 pass
  binary                                       ELF aarch64, 8 rz-* tools
  system libs                                  7/7 linked (libz.so.1,
    libzstd, liblzma.so, liblz4, libpcre2-8/16/32, libcrypto.so.3,
    libtree-sitter.so.0.26)
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds complete package builds for GEF 2026.01 and Rizin 0.9.1. Adds an opt-in reveng stack with reverse-engineering tools, environment variables, and startup validation.

Changes

GEF package

Layer / File(s) Summary
GEF extraction and launcher
packages/gef/build.sh, packages/gef/build.ncl
The build extracts the archive, installs gef.py, creates a GDB launcher, and declares dependencies, outputs, tests, and MIT/GitHub metadata.

Rizin package

Layer / File(s) Summary
Rizin hermetic build
packages/rizin/build.sh
The script configures reproducible release flags, disables network downloads, selects system libraries, builds with Meson and Ninja, and installs into OUTPUT_DIR.
Rizin package outputs and validation
packages/rizin/build.ncl
The specification declares source data, dependencies, binaries, libraries, data files, smoke tests, system-library checks, binary analysis validation, and GPL-3.0-or-later metadata.

Reverse-engineering stack

Layer / File(s) Summary
Reverse-engineering toolchain integration
stacks/reveng/stack.ncl
The opt-in stack provisions reverse-engineering tools, sets Ghidra environment variables, validates Ghidra, Rizin, GDB, and GEF at startup, and documents excluded tools.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: twitchyliquid64

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main additions, GEF and Rizin, and their role in the reverse-engineering loadout.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch reveng-loadout

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/rizin/build.ncl (1)

60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider subsetOf for the openssl runtime dependency.

openssl is declared as a full package dependency in runtime_deps on Line 60. The openssl/build.ncl precedent shows this package exposes many outputs beyond libcrypto/libssl (the openssl CLI binary, c_rehash, engines-3, pkgconfigs, cmake_data, includes, mans, etc), none of which rizin needs at runtime. Only libcrypto and libssl (OutputLib types) are required for linking. Use subsetOf to select just those outputs and avoid pulling the full openssl closure (CLI tool, man pages, cmake data) into rizin's runtime dependency graph.

As per coding guidelines, "Use subsetOf when depending on selected outputs of a large package, and import subsetOf from minimal.ncl." Based on learnings, subsetOf is safe here because the needed outputs (libcrypto, libssl) are OutputLib, not OutputData, so this does not trigger the spec-hasher panic noted for OutputData outputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rizin/build.ncl` at line 60, Replace the full openssl runtime
dependency in the runtime_deps declaration with a subsetOf selection containing
only the libcrypto and libssl OutputLib outputs required by rizin. Import
subsetOf from minimal.ncl, following the existing openssl/build.ncl precedent,
and leave unrelated dependencies unchanged.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/gef/build.ncl`:
- Around line 59-62: Update the GDB validation commands in the build test to
explicitly reject output indicating `Undefined command: "gef"` (or the
equivalent unknown-command message). Ensure the check around the existing `gef
help` invocation fails when the command is unavailable, while preserving the
traceback rejection and successful registered-command behavior.

In `@packages/rizin/build.ncl`:
- Around line 34-40: Remove the direct gcc and glibc entries from the build_deps
list in the package definition, since toolchain supplies them transitively;
retain glibc in runtime_deps and leave the other build dependencies unchanged.

---

Nitpick comments:
In `@packages/rizin/build.ncl`:
- Line 60: Replace the full openssl runtime dependency in the runtime_deps
declaration with a subsetOf selection containing only the libcrypto and libssl
OutputLib outputs required by rizin. Import subsetOf from minimal.ncl, following
the existing openssl/build.ncl precedent, and leave unrelated dependencies
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae5cc7b0-de1e-4d25-8d7f-73afd0ad2309

📥 Commits

Reviewing files that changed from the base of the PR and between 97e04d2 and 0e7bd14.

📒 Files selected for processing (4)
  • packages/gef/build.ncl
  • packages/gef/build.sh
  • packages/rizin/build.ncl
  • packages/rizin/build.sh

Comment thread packages/gef/build.ncl
Comment on lines +59 to +62
["/bin/bash", "-c", "gef -batch -ex 'gef help' 2>&1 | grep -qi 'gef'"],
# A traceback on stderr means a partial import — gef would look
# present while most commands were missing.
["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -q 'Traceback'"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject the GDB unknown-command result.

Line 59 passes when GDB prints Undefined command: "gef" because that error contains gef. Line 62 does not reject this error. The test can pass when gef.py did not register the command.

Add an explicit assertion that rejects the unknown-command output.

Proposed fix
           ["/bin/bash", "-c", "gef -batch -ex 'gef help' 2>&1 | grep -qi 'gef'"],
+          ["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -qi 'Undefined command'"],
           # A traceback on stderr means a partial import — gef would look
           # present while most commands were missing.
           ["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -q 'Traceback'"],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
["/bin/bash", "-c", "gef -batch -ex 'gef help' 2>&1 | grep -qi 'gef'"],
# A traceback on stderr means a partial import — gef would look
# present while most commands were missing.
["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -q 'Traceback'"],
["/bin/bash", "-c", "gef -batch -ex 'gef help' 2>&1 | grep -qi 'gef'"],
["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -qi 'Undefined command'"],
# A traceback on stderr means a partial import — gef would look
# present while most commands were missing.
["/bin/bash", "-c", "! gef -batch -ex 'gef help' 2>&1 | grep -q 'Traceback'"],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/gef/build.ncl` around lines 59 - 62, Update the GDB validation
commands in the build test to explicitly reject output indicating `Undefined
command: "gef"` (or the equivalent unknown-command message). Ensure the check
around the existing `gef help` invocation fails when the command is unavailable,
while preserving the traceback rejection and successful registered-command
behavior.

Comment thread packages/rizin/build.ncl
Comment on lines +34 to +40
toolchain,
gcc,
meson,
ninja,
pkgconf,
python, # meson is Python
glibc,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect what toolchain/build.ncl already provides
fd -a build.ncl packages/toolchain
cat -n packages/toolchain/build.ncl

Repository: gominimal/pkgs

Length of output: 719


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- minimal.ncl references ---'
rg -n -C 3 'build_deps|runtime_deps|BuildSpec|transitive|closure' packages/minimal.ncl packages -g '*.ncl' -g '*.md' | head -240
printf '%s\n' '--- relevant package declarations ---'
for f in packages/openssl/build.ncl packages/rizin/build.ncl packages/gcc/build.ncl packages/glibc/build.ncl; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    cat -n "$f"
  fi
done

Repository: gominimal/pkgs

Length of output: 34578


🏁 Script executed:

#!/bin/bash
set -eu
echo '--- minimal.ncl location ---'
git ls-files | rg '(^|/)minimal\.ncl$|README|docs' | head -100
echo '--- dependency semantics ---'
rg -n -C 4 'build_deps|runtime_deps|transitive|dependency closure|dependency graph|subsetOf' . -g '*.md' -g '*.ncl' -g '*.nickel' -g '*.toml' | head -300
echo '--- packages using toolchain with direct compiler dependencies ---'
rg -n -C 2 'toolchain|gcc|glibc' packages -g 'build.ncl' | rg -B2 -A2 'toolchain|gcc|glibc' | head -300

Repository: gominimal/pkgs

Length of output: 29875


Remove redundant build_deps entries.

toolchain already exposes gcc and glibc through its transitive runtime dependencies. Remove direct gcc and glibc entries from build_deps, but keep glibc in runtime_deps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rizin/build.ncl` around lines 34 - 40, Remove the direct gcc and
glibc entries from the build_deps list in the package definition, since
toolchain supplies them transitively; retain glibc in runtime_deps and leave the
other build dependencies unchanged.

Source: Coding guidelines

@bryan-minimal
bryan-minimal marked this pull request as ready for review July 31, 2026 22:56
One session that takes an unknown binary from "what is this file" to "here is
the C it decompiles to" to "here is what it does when it runs": ghidra +
analyzeHeadless for the decompiler, rizin for the scriptable pass, gdb + gef
for the dynamic half, and the identify/inspect/trace/diff tools the repo
already ships.

Opt-in by design — deliberately no `matches_project_if_any`. Nothing about a
source tree implies you want an RE bench; you ask for this one, the way you ask
for `aeneas`.

Held back until now because it could not exist: the stack references ghidra,
and until #545 landed the whole repo failed to evaluate with
`Error: package 'ghidra' does not exist` — which takes every other package down
with it. Worth knowing that `min check --stacks` does NOT catch that: I tested
`packages valid` against a deliberately nonexistent package name and it still
reported Pass. Only a build catches a bad stack reference, so the 17 names here
were also checked against packages/ by hand.

build_cmd exercises all four anchors rather than listing them, because each
fails silently in its own way: analyzeHeadless exits 0 with no decompiler, gdb
builds fine without Python (and then gef cannot load), and rizin builds fine
having silently vendored seven libraries.

Tools excluded on licence grounds are named at the bottom of the file with the
reason — volatility3, peda, nmap — so nobody re-proposes them; frida is
excluded on build cost, not licence, and is worth revisiting.
@bryan-minimal

Copy link
Copy Markdown
Member Author

Updated now that #545 (ghidra) has landed on main.

  • Merged latest main in (no force-push), so this branch now contains ghidra + the gh 2.97.0 bump.
  • Added stacks/reveng/stack.ncl — the loadout that was held back because it references ghidra. On a branch without ghidra it takes the whole repo down with Error: package 'ghidra' does not exist, which is why it wasn't here before.

Re-verified against latest main through the min-native path:

min package build ghidra gdb gef rizin                             exit 0
min check --packages gef --packages rizin --stacks reveng          36/36 Pass, 0 Fail
                                                                   (gef 15 + rizin 15 + reveng 6)

Two notes for the reviewer:

min check --stacks does not verify that a stack's packages exist — I tested packages valid against a deliberately nonexistent name and it still reported Pass. So the 17 names in the stack were also checked against packages/ by hand; only a build catches a bad reference.

The stack does not yet include capstone / upx / fq from #549 — those aren't on main, and naming an absent package is precisely the failure above. They're a one-line addition once #549 lands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
stacks/reveng/stack.ncl (1)

93-102: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Align the startup contract with the existing package tests.

packages/ghidra/build.ncl already checks headless import and non-empty decompilation. packages/rizin/build.ncl already checks system DT_NEEDED entries. Replace the weaker probes with equivalent checks, or remove the comments that claim they validate these properties.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stacks/reveng/stack.ncl` around lines 93 - 102, The startup command in the
analysis bench must match the stronger package validation contracts: update the
Ghidra probe near build_cmd to verify headless import and non-empty
decompilation, and update the Rizin probe to validate system DT_NEEDED entries
using the existing package-test approach; otherwise remove comments claiming
those properties are checked.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@stacks/reveng/stack.ncl`:
- Around line 93-102: The startup command in the analysis bench must match the
stronger package validation contracts: update the Ghidra probe near build_cmd to
verify headless import and non-empty decompilation, and update the Rizin probe
to validate system DT_NEEDED entries using the existing package-test approach;
otherwise remove comments claiming those properties are checked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b33bdf2e-ea8c-49bc-be23-8ff5ddb8d9c5

📥 Commits

Reviewing files that changed from the base of the PR and between 0e7bd14 and 0ba4b2a.

📒 Files selected for processing (1)
  • stacks/reveng/stack.ncl

@bryan-minimal
bryan-minimal added this pull request to the merge queue Aug 3, 2026
Merged via the queue into main with commit 3ccfc4f Aug 3, 2026
10 checks passed
@bryan-minimal
bryan-minimal deleted the reveng-loadout branch August 3, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants