Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
78 changes: 78 additions & 0 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Build Linux Packages

on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_call:
inputs:
version:
required: true
type: string

jobs:
build-unix:
uses: ./.github/workflows/build-unix.yml
with:
version: ${{ inputs.version || 'dev' }}

build-rpm:
needs: build-unix
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-latest
- arch: arm64
runner: ubuntu-24.04-arm

runs-on: ${{ matrix.runner }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Download agent artifact
uses: actions/download-artifact@v4
with:
name: safechain-ultimate-linux-${{ matrix.arch }}
path: bin

- name: Download agent ui artifact
uses: actions/download-artifact@v4
with:
name: safechain-ultimate-ui-linux-${{ matrix.arch }}
path: bin

- name: Download proxy artifact
uses: actions/download-artifact@v4
with:
name: safechain-proxy-linux-${{ matrix.arch }}
path: bin

- name: Verify binaries exist
run: |
ls -lh bin/
ls -lh bin/safechain-ultimate-linux-${{ matrix.arch }}
ls -lh bin/safechain-ultimate-ui-linux-${{ matrix.arch }}
ls -lh bin/safechain-proxy-linux-${{ matrix.arch }}

- name: Install RPM tools
run: sudo apt-get update && sudo apt-get install -y rpm

- name: Build RPM
run: |
cd packaging/rpm
./build-rpm.sh -v "${{ inputs.version || 'dev' }}" -a "${{ matrix.arch }}" -b "../../bin" -o "../../dist"

- name: Rename package
run: |
mv dist/SafeChainUltimate-${{ inputs.version || 'dev' }}-${{ matrix.arch }}.rpm dist/SafeChainUltimate-${{ matrix.arch }}.rpm

- name: Upload RPM artifact
uses: actions/upload-artifact@v4
with:
name: SafeChainUltimate-${{ matrix.arch }}.rpm
path: dist/SafeChainUltimate-${{ matrix.arch }}.rpm
28 changes: 18 additions & 10 deletions .github/workflows/build-unix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,18 @@ jobs:
strategy:
matrix:
include:
- arch: amd64
- os: darwin
arch: amd64
runner: macos-14
- arch: arm64
- os: darwin
arch: arm64
runner: macos-14
- os: linux
arch: amd64
runner: ubuntu-latest
- os: linux
arch: arm64
runner: ubuntu-24.04-arm

runs-on: ${{ matrix.runner }}
steps:
Expand All @@ -36,26 +44,26 @@ jobs:
- name: Run tests
run: make test

- name: Build binaries for darwin/${{ matrix.arch }}
run: make build-darwin-${{ matrix.arch }} VERSION="${{ inputs.version || 'dev' }}"
- name: Build binaries for ${{ matrix.os }}/${{ matrix.arch }}
run: make build-${{ matrix.os }}-${{ matrix.arch }} VERSION="${{ inputs.version || 'dev' }}"

- name: Prepare artifacts
run: |
mv bin/safechain-ultimate-darwin-${{ matrix.arch }} safechain-ultimate-darwin-${{ matrix.arch }}
mv bin/safechain-ultimate-ui-darwin-${{ matrix.arch }} safechain-ultimate-ui-darwin-${{ matrix.arch }}
mv bin/safechain-ultimate-${{ matrix.os }}-${{ matrix.arch }} safechain-ultimate-${{ matrix.os }}-${{ matrix.arch }}
mv bin/safechain-ultimate-ui-${{ matrix.os }}-${{ matrix.arch }} safechain-ultimate-ui-${{ matrix.os }}-${{ matrix.arch }}

- name: Upload safechain-ultimate artifact
uses: actions/upload-artifact@v4
with:
name: safechain-ultimate-darwin-${{ matrix.arch }}
name: safechain-ultimate-${{ matrix.os }}-${{ matrix.arch }}
path: |
safechain-ultimate-darwin-${{ matrix.arch }}
safechain-ultimate-${{ matrix.os }}-${{ matrix.arch }}
- name: Upload safechain-ultimate-ui artifact
uses: actions/upload-artifact@v4
with:
name: safechain-ultimate-ui-darwin-${{ matrix.arch }}
name: safechain-ultimate-ui-${{ matrix.os }}-${{ matrix.arch }}
path: |
safechain-ultimate-ui-darwin-${{ matrix.arch }}
safechain-ultimate-ui-${{ matrix.os }}-${{ matrix.arch }}

build-unix-proxy:
strategy:
Expand Down
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build build-release build-darwin-amd64 build-darwin-arm64 build-windows-amd64 build-windows-arm64 build-proxy build-pkg build-pkg-sign-local install-pkg uninstall-pkg clean test run help
.PHONY: build build-release build-darwin-amd64 build-darwin-arm64 build-linux-amd64 build-linux-arm64 build-windows-amd64 build-windows-arm64 build-proxy build-pkg build-pkg-sign-local install-pkg uninstall-pkg build-rpm clean test run help

BINARY_NAME=safechain-ultimate
BINARY_NAME_UI=safechain-ultimate-ui
Expand Down Expand Up @@ -82,6 +82,12 @@ build-darwin-amd64:
build-darwin-arm64:
@$(MAKE) GOOS=darwin GOARCH=arm64 build-release

build-linux-amd64:
@$(MAKE) GOOS=linux GOARCH=amd64 build-release

build-linux-arm64:
@$(MAKE) GOOS=linux GOARCH=arm64 build-release

build-windows-amd64:
@$(MAKE) GOOS=windows GOARCH=amd64 build-release

Expand All @@ -105,6 +111,16 @@ else
@exit 1
endif

build-rpm:
ifeq ($(DETECTED_OS),linux)
@echo "Building Linux RPM installer..."
@cd packaging/rpm && ./build-rpm.sh -v $(VERSION) -a $(DETECTED_ARCH) -b ../../$(BIN_DIR) -o ../../$(DIST_DIR)
@echo "RPM built in $(DIST_DIR)/"
else
@echo "Error: RPM building is only supported on Linux"
@exit 1
endif

build-pkg-sign-local:
ifeq ($(DETECTED_OS),darwin)
@echo "Building complete macOS package..."
Expand Down
139 changes: 139 additions & 0 deletions packaging/rpm/build-rpm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/bin/bash

set -e

VERSION=""
ARCH=""
BIN_DIR="./bin"
OUTPUT_DIR="./dist"

while getopts "v:a:b:o:h" opt; do
case $opt in
v) VERSION="$OPTARG" ;;
a) ARCH="$OPTARG" ;;
b) BIN_DIR="$OPTARG" ;;
o) OUTPUT_DIR="$OPTARG" ;;
h)
echo "Usage: $0 -v VERSION -a ARCH [-b BIN_DIR] [-o OUTPUT_DIR]"
echo " -v VERSION Version number (e.g., 1.0.0)"
echo " -a ARCH Architecture (arm64 or amd64)"
echo " -b BIN_DIR Binary directory (default: ./bin)"
echo " -o OUTPUT_DIR Output directory (default: ./dist)"
exit 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done

if [ -z "$VERSION" ]; then
echo "Error: VERSION is required (-v)" >&2
exit 1
fi

if [ -z "$ARCH" ]; then
echo "Error: ARCH is required (-a)" >&2
exit 1
fi

if [ "$VERSION" = "dev" ]; then
PKG_VERSION="0.0.0"
else
PKG_VERSION="$VERSION"
fi

case "$ARCH" in
amd64) RPM_ARCH="x86_64" ;;
arm64) RPM_ARCH="aarch64" ;;
*)
echo "Error: Unsupported architecture: $ARCH (expected amd64 or arm64)" >&2
exit 1
;;
esac

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
BIN_DIR="$(cd "$BIN_DIR" 2>/dev/null && pwd || echo "$PROJECT_DIR/$BIN_DIR")"
OUTPUT_DIR="$(mkdir -p "$OUTPUT_DIR" && cd "$OUTPUT_DIR" && pwd)"

echo "Building Linux RPM installer for SafeChain Ultimate v$VERSION"
echo " Architecture: $ARCH ($RPM_ARCH)"
echo " Binary directory: $BIN_DIR"
echo " Output directory: $OUTPUT_DIR"
echo " Project directory: $PROJECT_DIR"

AGENT_BIN="$BIN_DIR/safechain-ultimate-linux-$ARCH"
AGENT_UI_BIN="$BIN_DIR/safechain-ultimate-ui-linux-$ARCH"
PROXY_BIN="$BIN_DIR/safechain-proxy-linux-$ARCH"

if [ ! -f "$AGENT_BIN" ]; then
echo "Error: safechain-ultimate binary not found at $AGENT_BIN" >&2
exit 1
fi

if [ ! -f "$AGENT_UI_BIN" ]; then
echo "Error: safechain-ultimate-ui binary not found at $AGENT_UI_BIN" >&2
exit 1
fi

if [ ! -f "$PROXY_BIN" ]; then
echo "Error: safechain-proxy binary not found at $PROXY_BIN" >&2
exit 1
fi

BUILD_DIR="$(mktemp -d)"
trap "rm -rf '$BUILD_DIR'" EXIT
Copy link
Copy Markdown
Contributor

@aikido-pr-checks aikido-pr-checks Bot Feb 9, 2026

Choose a reason for hiding this comment

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

EXIT trap uses rm -rf '$BUILD_DIR', so $BUILD_DIR won’t expand and cleanup targets a literal directory name, leaving the temp build directory behind.

Details

✨ AI Reasoning
​The script creates a temporary directory and sets an EXIT trap intended to delete it. However, the trap command wraps the variable in single quotes, which stops the shell from expanding it when the trap executes. That makes the cleanup command operate on the literal string instead of the actual temporary path, so the temporary build directory will not be removed as intended.

🔧 How do I fix it?
Trace execution paths carefully. Ensure precondition checks happen before using values, validate ranges before checking impossible conditions, and don't check for states that the code has already ruled out.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Show Fix

Remediation - low confidence
This patch mitigates the logic bug on line 87 by replacing single quotes with escaped double quotes around $BUILD_DIR in the trap command, ensuring the variable expands correctly and the temporary build directory is properly cleaned up on exit.

Suggested change
trap "rm -rf '$BUILD_DIR'" EXIT
trap "rm -rf \"$BUILD_DIR\"" EXIT


echo "Using temporary build directory: $BUILD_DIR"

RPMBUILD_DIR="$BUILD_DIR/rpmbuild"
mkdir -p "$RPMBUILD_DIR"/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

echo "Copying binaries to SOURCES..."
cp "$AGENT_BIN" "$RPMBUILD_DIR/SOURCES/safechain-ultimate"
cp "$AGENT_UI_BIN" "$RPMBUILD_DIR/SOURCES/safechain-ultimate-ui"
cp "$PROXY_BIN" "$RPMBUILD_DIR/SOURCES/safechain-proxy"

echo "Copying packaging files to SOURCES..."
cp "$SCRIPT_DIR/safechain-ultimate.service" "$RPMBUILD_DIR/SOURCES/"
cp "$SCRIPT_DIR/scripts/uninstall" "$RPMBUILD_DIR/SOURCES/"

echo "Copying spec file..."
cp "$SCRIPT_DIR/safechain-ultimate.spec" "$RPMBUILD_DIR/SPECS/"

echo "Building RPM package..."
rpmbuild -bb \
--define "_topdir $RPMBUILD_DIR" \
--define "_pkg_version $PKG_VERSION" \
--target "$RPM_ARCH" \
"$RPMBUILD_DIR/SPECS/safechain-ultimate.spec"

RPM_FILE=$(find "$RPMBUILD_DIR/RPMS/$RPM_ARCH/" -name "safechain-ultimate-*.rpm" | head -1)

if [ -z "$RPM_FILE" ]; then
echo "Error: RPM file not found after build" >&2
exit 1
fi

OUTPUT_RPM="$OUTPUT_DIR/SafeChainUltimate-$VERSION-$ARCH.rpm"
cp "$RPM_FILE" "$OUTPUT_RPM"

echo ""
echo "✓ RPM package built successfully: $OUTPUT_RPM"
echo ""

CHECKSUM=$(sha256sum "$OUTPUT_RPM" | awk '{print $1}')
echo "SHA256: $CHECKSUM"
echo "$CHECKSUM" > "$OUTPUT_RPM.sha256"
echo ""

echo "Package information:"
rpm -qip "$OUTPUT_RPM"
echo ""

SIZE=$(du -h "$OUTPUT_RPM" | awk '{print $1}')
echo "Package size: $SIZE"

exit 0
16 changes: 16 additions & 0 deletions packaging/rpm/safechain-ultimate.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Unit]
Description=SafeChain Ultimate - Security Agent by Aikido Security
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/aikidosecurity/safechainultimate/bin/safechain-ultimate
WorkingDirectory=/opt/aikidosecurity/safechainultimate
Restart=always
RestartSec=60
StandardOutput=append:/var/log/aikidosecurity/safechainultimate/safechain-ultimate.log
StandardError=append:/var/log/aikidosecurity/safechainultimate/safechain-ultimate.error.log

[Install]
WantedBy=multi-user.target
71 changes: 71 additions & 0 deletions packaging/rpm/safechain-ultimate.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
Name: safechain-ultimate
Version: %{_pkg_version}
Release: 1%{?dist}
Summary: SafeChain Ultimate - Security Agent by Aikido Security

License: AGPL-3.0-or-later
URL: https://aikido.dev

AutoReqProv: no

%description
SafeChain Ultimate is a security agent by Aikido Security that protects
your applications and infrastructure.

%install
mkdir -p %{buildroot}/opt/aikidosecurity/safechainultimate/bin
mkdir -p %{buildroot}/opt/aikidosecurity/safechainultimate/scripts
mkdir -p %{buildroot}/usr/lib/systemd/system
mkdir -p %{buildroot}/var/log/aikidosecurity/safechainultimate

install -m 755 %{_sourcedir}/safechain-ultimate %{buildroot}/opt/aikidosecurity/safechainultimate/bin/
install -m 755 %{_sourcedir}/safechain-ultimate-ui %{buildroot}/opt/aikidosecurity/safechainultimate/bin/
install -m 755 %{_sourcedir}/safechain-proxy %{buildroot}/opt/aikidosecurity/safechainultimate/bin/
install -m 755 %{_sourcedir}/uninstall %{buildroot}/opt/aikidosecurity/safechainultimate/scripts/
install -m 644 %{_sourcedir}/safechain-ultimate.service %{buildroot}/usr/lib/systemd/system/

%files
%dir /opt/aikidosecurity
%dir /opt/aikidosecurity/safechainultimate
%dir /opt/aikidosecurity/safechainultimate/bin
%dir /opt/aikidosecurity/safechainultimate/scripts
%dir /var/log/aikidosecurity
%dir /var/log/aikidosecurity/safechainultimate
%attr(755, root, root) /opt/aikidosecurity/safechainultimate/bin/safechain-ultimate
%attr(755, root, root) /opt/aikidosecurity/safechainultimate/bin/safechain-ultimate-ui
%attr(755, root, root) /opt/aikidosecurity/safechainultimate/bin/safechain-proxy
%attr(755, root, root) /opt/aikidosecurity/safechainultimate/scripts/uninstall
%attr(644, root, root) /usr/lib/systemd/system/safechain-ultimate.service

%pre
if systemctl is-active --quiet safechain-ultimate 2>/dev/null; then
systemctl stop safechain-ultimate || true
fi

%post
systemctl daemon-reload
systemctl enable safechain-ultimate
systemctl start safechain-ultimate

echo ""
echo "SafeChain Ultimate has been installed successfully!"
echo " Binaries: /opt/aikidosecurity/safechainultimate/bin"
echo " Logs: /var/log/aikidosecurity/safechainultimate"
echo ""
echo "The agent is now running as a systemd service."

%preun
if [ $1 -eq 0 ]; then
if systemctl is-active --quiet safechain-ultimate 2>/dev/null; then
systemctl stop safechain-ultimate || true
fi
systemctl disable safechain-ultimate 2>/dev/null || true
fi

%postun
systemctl daemon-reload
if [ $1 -eq 0 ]; then
rm -rf /var/log/aikidosecurity/safechainultimate
rmdir /var/log/aikidosecurity 2>/dev/null || true
rmdir /opt/aikidosecurity 2>/dev/null || true
fi
Loading
Loading