Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/rea-jadx-bridge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Temporary PR run to retrieve the small bridge artifact for sandbox verification.
name: Package REA JADX bridge

on:
push:
branches: [main]
paths:
- ".github/workflows/rea-jadx-bridge.yml"
pull_request:
branches: [main]
paths:
- ".github/workflows/rea-jadx-bridge.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
bridge:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Fetch and verify REA-pinned JADX bridge
shell: bash
run: |
set -euo pipefail
mkdir -p dist/rea-jadx-headless-mcp
JAR=dist/rea-jadx-headless-mcp/jadx-headless-mcp-0.7.1-all.jar
curl -fsSL --retry 3 "https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar" -o "$JAR"
echo "6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75 $JAR" | sha256sum -c -
curl -fsSL --retry 3 "https://raw.githubusercontent.com/1013503897/jadx-headless-mcp/5844800a486d2248fa949b74c9896285f5b54de2/LICENSE" -o dist/rea-jadx-headless-mcp/LICENSE-APACHE-2.0.txt
echo "SHA-256 verified: $(sha256sum "$JAR" | cut -d ' ' -f1)"
- name: Upload bridge artifact
uses: actions/upload-artifact@v4
with:
name: rea-jadx-headless-mcp-0.7.1
path: dist/rea-jadx-headless-mcp/
if-no-files-found: error
retention-days: 7
compression-level: 0
157 changes: 147 additions & 10 deletions .github/workflows/rea-offline-bundle.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Build REA offline bundle
# Temporary artifact retrieval verification PR.

on:
push:
Expand All @@ -14,10 +15,6 @@ on:
permissions:
contents: read

concurrency:
group: rea-offline-bundle
cancel-in-progress: true

jobs:
build-linux-x64:
name: Linux x86-64 offline kit
Expand Down Expand Up @@ -48,7 +45,9 @@ jobs:
NODE_VERSION="24.11.1"
curl -fsSL --retry 3 "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" -o "$RUNNER_TEMP/node-shasums.txt"
curl -fsSL --retry 3 "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o "$RUNNER_TEMP/node.tar.xz"
(cd "$RUNNER_TEMP" && grep " node-v${NODE_VERSION}-linux-x64.tar.xz$" node-shasums.txt | sha256sum -c -)
NODE_SHA256="$(awk -v file="node-v${NODE_VERSION}-linux-x64.tar.xz" '$2 == file {print $1}' "$RUNNER_TEMP/node-shasums.txt")"
test -n "$NODE_SHA256" || { echo "No Node.js checksum found"; exit 1; }
echo "$NODE_SHA256 $RUNNER_TEMP/node.tar.xz" | sha256sum -c -
mkdir -p "$ROOT/runtime/node"
tar -xJf "$RUNNER_TEMP/node.tar.xz" --strip-components=1 -C "$ROOT/runtime/node"
export PATH="$ROOT/runtime/node/bin:$PATH"
Expand Down Expand Up @@ -82,6 +81,13 @@ jobs:
mkdir -p "$ROOT/tools/jadx"
unzip -q "$RUNNER_TEMP/jadx.zip" -d "$ROOT/tools/jadx"

# Bundle REA's required headless JADX MCP bridge, pinned and hash-verified by REA itself.
mkdir -p "$ROOT/tools/jadx-headless-mcp"
JADX_MCP_JAR="$ROOT/tools/jadx-headless-mcp/jadx-headless-mcp-0.7.1-all.jar"
curl -fsSL --retry 3 "https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar" -o "$JADX_MCP_JAR"
echo "6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75 $JADX_MCP_JAR" | sha256sum -c -
curl -fsSL --retry 3 "https://raw.githubusercontent.com/1013503897/jadx-headless-mcp/5844800a486d2248fa949b74c9896285f5b54de2/LICENSE" -o "$ROOT/licenses/JADX-HEADLESS-MCP-APACHE-2.0.txt"

# Bundle Apktool, preserving its license when published at the upstream path.
curl -fsSL -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
https://api.github.com/repos/iBotPeaches/Apktool/releases/latest -o "$RUNNER_TEMP/apktool-release.json"
Expand All @@ -96,8 +102,10 @@ jobs:
#!/usr/bin/env bash
set -e
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
export PATH="$ROOT/runtime/node/bin:$ROOT/tools/jadx/bin:$ROOT/tools/ghidra/support:$PATH"
export PATH="$ROOT/runtime/node/bin:$ROOT/tools/jadx/bin:$ROOT/tools/ghidra:$ROOT/tools/ghidra/support:$PATH"
export JAVA_HOME="$ROOT/runtime/jdk"
export GHIDRA_INSTALL_DIR="${GHIDRA_INSTALL_DIR:-$ROOT/tools/ghidra}"
export REA_JADX_MCP_JAR="${REA_JADX_MCP_JAR:-$ROOT/tools/jadx-headless-mcp/jadx-headless-mcp-0.7.1-all.jar}"
exec "$ROOT/runtime/node/bin/node" "$ROOT/app/node_modules/rea-agents/scripts/rea.mjs" "$@"
EOF

Expand Down Expand Up @@ -164,7 +172,7 @@ jobs:
## Scope and limits

- Platform: Linux x86-64 only. This is not an Android/Termux or Windows build.
- Bundled tools: REA, Node.js, JDK, Ghidra, JADX, and Apktool.
- Bundled tools: REA, Node.js, JDK, Ghidra, JADX, JADX headless MCP bridge, and Apktool.
- Commercial tools (IDA Pro, Hopper, JEB) are not included; use valid licenses.
- Some optional REA integrations may require additional platform packages or caller-supplied tools.
- Analyze only software you own or are authorized to examine.
Expand All @@ -186,6 +194,7 @@ jobs:
echo "Node.js: $NODE_VERSION"
echo "Ghidra release: $(jq -r '.tag_name' "$RUNNER_TEMP/ghidra-release.json")"
echo "JADX release: $(jq -r '.tag_name' "$RUNNER_TEMP/jadx-release.json")"
echo "JADX headless MCP: 0.7.1 (SHA-256 verified)"
echo "Apktool release: $(jq -r '.tag_name' "$RUNNER_TEMP/apktool-release.json")"
echo "Target: Linux x86-64"
} > "$ROOT/MANIFEST.txt"
Expand All @@ -196,20 +205,148 @@ jobs:
"$ROOT/bin/apktool" --version
"$ROOT/runtime/jdk/bin/java" -version
"$ROOT/tools/ghidra/support/analyzeHeadless" -h > "$RUNNER_TEMP/ghidra-help.txt" 2>&1 || true
"$ROOT/bin/rea" doctor --json > "$RUNNER_TEMP/rea-doctor.json" || true
jq -e '.providerInspections[] | select(.id == "ghidra") | .available == true' "$RUNNER_TEMP/rea-doctor.json" >/dev/null
jq -e '.providerInspections[] | select(.id == "jadx") | .available == true' "$RUNNER_TEMP/rea-doctor.json" >/dev/null

# Avoid packaging transient caches from the online build.
rm -rf "$ROOT/app/.npm" "$ROOT/app/node_modules/.cache"
mkdir -p "$GITHUB_WORKSPACE/dist"
(cd "$RUNNER_TEMP" && zip -q -r -1 "$GITHUB_WORKSPACE/dist/rea-offline-linux-x64.zip" "rea-offline-linux-x64")
sha256sum "$GITHUB_WORKSPACE/dist/rea-offline-linux-x64.zip" > "$GITHUB_WORKSPACE/dist/SHA256SUMS.txt"
echo "Bundle size: $(du -h "$GITHUB_WORKSPACE/dist/rea-offline-linux-x64.zip" | cut -f1)"
# GitHub connector downloads have a 512 MiB per-artifact limit; upload independent chunks.
split -b 80M -d -a 2 "$GITHUB_WORKSPACE/dist/rea-offline-linux-x64.zip" "$GITHUB_WORKSPACE/dist/rea-offline-linux-x64.part-"
PART_COUNT="$(find "$GITHUB_WORKSPACE/dist" -maxdepth 1 -type f -name 'rea-offline-linux-x64.part-*' | wc -l)"
test "$PART_COUNT" -eq 14 || { echo "Expected 14 bundle chunks, found $PART_COUNT"; exit 1; }
ZIP_SHA="$(awk '{print $1}' "$GITHUB_WORKSPACE/dist/SHA256SUMS.txt")"
PARTS_SHA="$(cat "$GITHUB_WORKSPACE"/dist/rea-offline-linux-x64.part-* | sha256sum | awk '{print $1}')"
test "$ZIP_SHA" = "$PARTS_SHA" || { echo "Split chunks do not reconstruct the original ZIP"; exit 1; }
ls -lh "$GITHUB_WORKSPACE"/dist/rea-offline-linux-x64.part-*

- name: Upload bundle part 00
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-00
path: dist/rea-offline-linux-x64.part-00
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 01
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-01
path: dist/rea-offline-linux-x64.part-01
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 02
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-02
path: dist/rea-offline-linux-x64.part-02
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 03
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-03
path: dist/rea-offline-linux-x64.part-03
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 04
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-04
path: dist/rea-offline-linux-x64.part-04
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 05
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-05
path: dist/rea-offline-linux-x64.part-05
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 06
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-06
path: dist/rea-offline-linux-x64.part-06
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 07
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-07
path: dist/rea-offline-linux-x64.part-07
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 08
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-08
path: dist/rea-offline-linux-x64.part-08
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 09
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-09
path: dist/rea-offline-linux-x64.part-09
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 10
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-10
path: dist/rea-offline-linux-x64.part-10
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 11
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-11
path: dist/rea-offline-linux-x64.part-11
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload bundle part 12
uses: actions/upload-artifact@v4
with:
name: rea-offline-part-12
path: dist/rea-offline-linux-x64.part-12
if-no-files-found: error
retention-days: 7
compression-level: 0

- name: Upload offline bundle
- name: Upload bundle part 13
uses: actions/upload-artifact@v4
with:
name: rea-offline-linux-x64
name: rea-offline-part-13
path: |
dist/rea-offline-linux-x64.zip
dist/rea-offline-linux-x64.part-13
dist/SHA256SUMS.txt
if-no-files-found: error
retention-days: 7
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/rea-reassemble-bundle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Temporary verification copy for the current offline bundle run.
name: Reassemble REA offline bundle

on:
pull_request:
branches: [main]
paths:
- ".github/workflows/rea-reassemble-bundle.yml"
workflow_dispatch:
inputs:
run_id:
description: "Successful Build REA offline bundle run ID"
required: true
default: "39485305024"

permissions:
actions: read
contents: read

jobs:
reassemble:
runs-on: ubuntu-24.04
timeout-minutes: 10
env:
SOURCE_RUN_ID: ${{ inputs.run_id || '39485305024' }}
steps:
- name: Download bundle chunks from the successful build
uses: actions/download-artifact@v4
with:
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ env.SOURCE_RUN_ID }}
pattern: rea-offline-part-*
path: downloads
merge-multiple: true

- name: Reassemble and verify the single ZIP
shell: bash
run: |
set -euo pipefail
mkdir -p dist
for i in $(seq -w 0 13); do
test -s "downloads/rea-offline-linux-x64.part-$i" || {
echo "Missing bundle chunk part-$i"; exit 1;
}
done
test -s downloads/SHA256SUMS.txt
cat downloads/rea-offline-linux-x64.part-* > dist/rea-offline-linux-x64.zip
EXPECTED="$(awk '{print $1}' downloads/SHA256SUMS.txt)"
ACTUAL="$(sha256sum dist/rea-offline-linux-x64.zip | awk '{print $1}')"
printf 'Expected SHA-256: %s\nActual SHA-256: %s\n' "$EXPECTED" "$ACTUAL"
test "$EXPECTED" = "$ACTUAL" || {
echo "Reassembled ZIP checksum mismatch"; exit 1;
}
cp downloads/SHA256SUMS.txt dist/SHA256SUMS.txt
unzip -tq dist/rea-offline-linux-x64.zip >/dev/null
echo "Single offline bundle ZIP verified."

- name: Upload one-piece bundle
uses: actions/upload-artifact@v4
with:
name: rea-offline-linux-x64-full
path: |
dist/rea-offline-linux-x64.zip
dist/SHA256SUMS.txt
if-no-files-found: error
retention-days: 7
compression-level: 0