Skip to content
Merged
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
21 changes: 21 additions & 0 deletions .github/workflows/06-railway-preview-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,27 @@ jobs:
;;
esac

- name: Verify images run as non-root
env:
TAG: ${{ steps.tag.outputs.image_tag }}
run: |
FAILED=0
for IMAGE in agenta-api agenta-web agenta-services; do
FULL="ghcr.io/agenta-ai/${IMAGE}:${TAG}"
docker pull $FULL
USER=$(docker inspect --format='{{.Config.User}}' "$FULL")
if [ -z "$USER" ] || [ "$USER" = "root" ] || [ "$USER" = "0" ]; then
echo "FAIL: ${IMAGE} runs as root (User='${USER}')"
FAILED=1
else
echo "PASS: ${IMAGE} runs as User='${USER}'"
fi
done
if [ "$FAILED" -eq 1 ]; then
echo "::error::One or more images run as root."
exit 1
fi

- name: Summary
run: |
echo "- Built \`${{ matrix.image_name }}:${{ needs.prepare.outputs.image_tag }}\`" >> "$GITHUB_STEP_SUMMARY"
Expand Down
43 changes: 26 additions & 17 deletions api/ee/docker/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM python:3.11-slim-bookworm
WORKDIR /app

RUN apt-get update && \
apt-get install -y curl cron gnupg2 lsb-release && \
apt-get install -y curl gnupg2 lsb-release && \
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
Expand All @@ -12,6 +12,19 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Install supercronic (non-root-compatible cron daemon)
ARG SUPERCRONIC_VERSION=v0.2.33
RUN ARCH=$(dpkg --print-architecture) && \
case "${ARCH}" in \
amd64) SHA1=71b0d58cc53f6bd72cf2f293e09e294b79c666d8 ;; \
arm64) SHA1=e0f0c06ebc5627e43b25475711e694450489ab00 ;; \
*) echo "Unsupported arch: ${ARCH}" && exit 1 ;; \
esac && \
curl -fsSL "https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${ARCH}" \
-o /usr/local/bin/supercronic && \
echo "${SHA1} /usr/local/bin/supercronic" | sha1sum -c - && \
chmod +x /usr/local/bin/supercronic

RUN pip install --upgrade pip \
&& pip install poetry

Expand All @@ -28,26 +41,22 @@ ENV PYTHONPATH=/sdk:$PYTHONPATH

COPY ./oss/src/crons/queries.sh /queries.sh
COPY ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
RUN sed -i -e '$a\' /etc/cron.d/queries-cron
RUN cat -A /etc/cron.d/queries-cron

RUN chmod +x /queries.sh \
&& chmod 0644 /etc/cron.d/queries-cron

COPY ./ee/src/crons/meters.sh /meters.sh
COPY ./ee/src/crons/meters.txt /etc/cron.d/meters-cron
RUN sed -i -e '$a\' /etc/cron.d/meters-cron
RUN cat -A /etc/cron.d/meters-cron

RUN chmod +x /meters.sh \
&& chmod 0644 /etc/cron.d/meters-cron

COPY ./ee/src/crons/spans.sh /spans.sh
COPY ./ee/src/crons/spans.txt /etc/cron.d/spans-cron
RUN sed -i -e '$a\' /etc/cron.d/spans-cron
RUN cat -A /etc/cron.d/spans-cron

RUN chmod +x /spans.sh \
&& chmod 0644 /etc/cron.d/spans-cron
RUN chmod +x /queries.sh /meters.sh /spans.sh \
&& chmod 0644 /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron \
&& for f in /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron; do sed -i -e '$a\' "$f"; done \
&& cat /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron \
| sed -E 's/^(([^[:space:]]+[[:space:]]+){5})root[[:space:]]+/\1/' \
| sed 's| >> /proc/1/fd/1 2>&1||' > /app/crontab

RUN groupadd --gid 10001 agenta && \
useradd --uid 10001 --gid 10001 --shell /bin/false --create-home agenta && \
chown -R agenta:agenta /app

USER 10001

EXPOSE 8000
27 changes: 25 additions & 2 deletions api/ee/docker/Dockerfile.gh
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \

# Hardcode bookworm codename to avoid pulling in lsb-release (+ perl ~56MB)
RUN apt-get update && \
apt-get install -y --no-install-recommends curl cron gnupg2 && \
apt-get install -y --no-install-recommends curl gnupg2 && \
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
Expand All @@ -85,6 +85,19 @@ RUN apt-get update && \
apt-get purge -y --auto-remove gnupg2 && \
rm -rf /var/lib/apt/lists/*

# Install supercronic (non-root-compatible cron daemon)
ARG SUPERCRONIC_VERSION=v0.2.33
RUN ARCH=$(dpkg --print-architecture) && \
case "${ARCH}" in \
amd64) SHA1=71b0d58cc53f6bd72cf2f293e09e294b79c666d8 ;; \
arm64) SHA1=e0f0c06ebc5627e43b25475711e694450489ab00 ;; \
*) echo "Unsupported arch: ${ARCH}" && exit 1 ;; \
esac && \
curl -fsSL "https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${ARCH}" \
-o /usr/local/bin/supercronic && \
echo "${SHA1} /usr/local/bin/supercronic" | sha1sum -c - && \
chmod +x /usr/local/bin/supercronic

# Copy stable cron files first (change less frequently)
COPY --chmod=755 ./oss/src/crons/queries.sh /queries.sh
COPY --chmod=644 ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
Expand All @@ -102,10 +115,20 @@ COPY --from=builder /app/oss /app/oss
COPY --from=builder /app/entrypoints /app/entrypoints
COPY --from=builder /app/sdk /app/sdk

# Generate supercronic-compatible crontab (strip user field and /proc redirects)
RUN set -eux; \
for cron_file in /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron; do \
sed -i -e '$a\' "${cron_file}"; \
done
done; \
cat /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron \
| sed -E 's/^(([^[:space:]]+[[:space:]]+){5})root[[:space:]]+/\1/' \
| sed 's| >> /proc/1/fd/1 2>&1||' > /app/crontab

RUN groupadd --gid 10001 agenta && \
useradd --uid 10001 --gid 10001 --shell /bin/false --create-home agenta && \
chown -R agenta:agenta /app

USER 10001

LABEL org.opencontainers.image.title="agenta-api-ee" \
org.opencontainers.image.description="Agenta API EE GH runtime image" \
Expand Down
25 changes: 12 additions & 13 deletions api/ee/src/crons/meters.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#!/bin/sh
set -eu

AGENTA_AUTH_KEY=$(tr '\0' '\n' < /proc/1/environ | grep ^AGENTA_AUTH_KEY= | cut -d= -f2- || true)
AGENTA_AUTH_KEY="${AGENTA_AUTH_KEY:-replace-me}"

echo "--------------------------------------------------------"
echo "[$(date)] meters.sh running from cron" >> /proc/1/fd/1
echo "[$(date)] meters.sh running from cron"

# Make POST request with 15 minute timeout
RESPONSE=$(curl \
Expand All @@ -18,23 +17,23 @@ RESPONSE=$(curl \
"http://api:8000/admin/billing/usage/report" 2>&1) || CURL_EXIT=$?

if [ -n "${CURL_EXIT:-}" ]; then
echo "❌ CURL failed with exit code: ${CURL_EXIT}" >> /proc/1/fd/1
echo "❌ CURL failed with exit code: ${CURL_EXIT}"
case ${CURL_EXIT} in
6) echo " Could not resolve host" >> /proc/1/fd/1 ;;
7) echo " Failed to connect to host" >> /proc/1/fd/1 ;;
28) echo " Operation timeout (exceeded 900s / 15 minutes)" >> /proc/1/fd/1 ;;
52) echo " Empty reply from server (server closed connection)" >> /proc/1/fd/1 ;;
56) echo " Failure in receiving network data" >> /proc/1/fd/1 ;;
*) echo " Unknown curl error" >> /proc/1/fd/1 ;;
6) echo " Could not resolve host" ;;
7) echo " Failed to connect to host" ;;
28) echo " Operation timeout (exceeded 900s / 15 minutes)" ;;
52) echo " Empty reply from server (server closed connection)" ;;
56) echo " Failure in receiving network data" ;;
*) echo " Unknown curl error" ;;
esac
else
echo "${RESPONSE}" >> /proc/1/fd/1
echo "${RESPONSE}"
HTTP_CODE=$(echo "${RESPONSE}" | grep "HTTP_STATUS:" | cut -d: -f2)
if [ "${HTTP_CODE}" = "200" ]; then
echo "✅ Report completed successfully" >> /proc/1/fd/1
echo "✅ Report completed successfully"
else
echo "❌ Report failed with HTTP ${HTTP_CODE}" >> /proc/1/fd/1
echo "❌ Report failed with HTTP ${HTTP_CODE}"
fi
fi

echo "[$(date)] meters.sh done" >> /proc/1/fd/1
echo "[$(date)] meters.sh done"
26 changes: 13 additions & 13 deletions api/ee/src/crons/spans.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/sh
set -eu

AGENTA_AUTH_KEY=$(tr '\0' '\n' < /proc/1/environ | grep ^AGENTA_AUTH_KEY= | cut -d= -f2-)
AGENTA_AUTH_KEY="${AGENTA_AUTH_KEY:-replace-me}"

echo "--------------------------------------------------------"
echo "[$(date)] spans.sh running from cron" >> /proc/1/fd/1
echo "[$(date)] spans.sh running from cron"

# Make POST request with 30 minute timeout (retention can be slow)
RESPONSE=$(curl \
Expand All @@ -17,23 +17,23 @@ RESPONSE=$(curl \
"http://api:8000/admin/billing/usage/flush" 2>&1) || CURL_EXIT=$?

if [ -n "${CURL_EXIT:-}" ]; then
echo "❌ CURL failed with exit code: ${CURL_EXIT}" >> /proc/1/fd/1
echo "❌ CURL failed with exit code: ${CURL_EXIT}"
case ${CURL_EXIT} in
6) echo " Could not resolve host" >> /proc/1/fd/1 ;;
7) echo " Failed to connect to host" >> /proc/1/fd/1 ;;
28) echo " Operation timeout (exceeded 1800s / 30 minutes)" >> /proc/1/fd/1 ;;
52) echo " Empty reply from server" >> /proc/1/fd/1 ;;
56) echo " Failure in receiving network data" >> /proc/1/fd/1 ;;
*) echo " Unknown curl error" >> /proc/1/fd/1 ;;
6) echo " Could not resolve host" ;;
7) echo " Failed to connect to host" ;;
28) echo " Operation timeout (exceeded 1800s / 30 minutes)" ;;
52) echo " Empty reply from server" ;;
56) echo " Failure in receiving network data" ;;
*) echo " Unknown curl error" ;;
esac
else
echo "${RESPONSE}" >> /proc/1/fd/1
echo "${RESPONSE}"
HTTP_CODE=$(echo "${RESPONSE}" | grep "HTTP_STATUS:" | cut -d: -f2)
if [ "${HTTP_CODE}" = "200" ]; then
echo "✅ Spans retention completed successfully" >> /proc/1/fd/1
echo "✅ Spans retention completed successfully"
else
echo "❌ Spans retention failed with HTTP ${HTTP_CODE}" >> /proc/1/fd/1
echo "❌ Spans retention failed with HTTP ${HTTP_CODE}"
fi
fi

echo "[$(date)] spans.sh done" >> /proc/1/fd/1
echo "[$(date)] spans.sh done"
28 changes: 24 additions & 4 deletions api/oss/docker/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM python:3.11-slim-bookworm
WORKDIR /app

RUN apt-get update && \
apt-get install -y curl cron gnupg2 lsb-release && \
apt-get install -y curl gnupg2 lsb-release && \
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
Expand All @@ -12,6 +12,19 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Install supercronic (non-root-compatible cron daemon)
ARG SUPERCRONIC_VERSION=v0.2.33
RUN ARCH=$(dpkg --print-architecture) && \
case "${ARCH}" in \
amd64) SHA1=71b0d58cc53f6bd72cf2f293e09e294b79c666d8 ;; \
arm64) SHA1=e0f0c06ebc5627e43b25475711e694450489ab00 ;; \
*) echo "Unsupported arch: ${ARCH}" && exit 1 ;; \
esac && \
curl -fsSL "https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${ARCH}" \
-o /usr/local/bin/supercronic && \
echo "${SHA1} /usr/local/bin/supercronic" | sha1sum -c - && \
chmod +x /usr/local/bin/supercronic

RUN pip install --upgrade pip \
&& pip install poetry

Expand All @@ -28,11 +41,12 @@ ENV PYTHONPATH=/sdk:$PYTHONPATH

COPY ./oss/src/crons/queries.sh /queries.sh
COPY ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
RUN sed -i -e '$a\' /etc/cron.d/queries-cron
RUN cat -A /etc/cron.d/queries-cron

RUN chmod +x /queries.sh \
&& chmod 0644 /etc/cron.d/queries-cron
&& chmod 0644 /etc/cron.d/queries-cron \
&& sed -i -e '$a\' /etc/cron.d/queries-cron \
&& sed -E 's/^(([^[:space:]]+[[:space:]]+){5})root[[:space:]]+/\1/' /etc/cron.d/queries-cron \
| sed 's| >> /proc/1/fd/1 2>&1||' > /app/crontab

#
#
Expand All @@ -50,4 +64,10 @@ RUN chmod +x /queries.sh \
#
#

RUN groupadd --gid 10001 agenta && \
useradd --uid 10001 --gid 10001 --shell /bin/false --create-home agenta && \
chown -R agenta:agenta /app

USER 10001

EXPOSE 8000
26 changes: 24 additions & 2 deletions api/oss/docker/Dockerfile.gh
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
# Hardcode bookworm codename to avoid pulling in lsb-release (+ perl ~56MB).
# IMPORTANT: This codename must match the Debian release used in the base image (python:3.11-slim-bookworm).
RUN apt-get update && \
apt-get install -y --no-install-recommends curl cron gnupg2 && \
apt-get install -y --no-install-recommends curl gnupg2 && \
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
Expand All @@ -85,6 +85,19 @@ RUN apt-get update && \
apt-get purge -y --auto-remove gnupg2 && \
rm -rf /var/lib/apt/lists/*

# Install supercronic (non-root-compatible cron daemon)
ARG SUPERCRONIC_VERSION=v0.2.33
RUN ARCH=$(dpkg --print-architecture) && \
case "${ARCH}" in \
amd64) SHA1=71b0d58cc53f6bd72cf2f293e09e294b79c666d8 ;; \
arm64) SHA1=e0f0c06ebc5627e43b25475711e694450489ab00 ;; \
*) echo "Unsupported arch: ${ARCH}" && exit 1 ;; \
esac && \
curl -fsSL "https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${ARCH}" \
-o /usr/local/bin/supercronic && \
echo "${SHA1} /usr/local/bin/supercronic" | sha1sum -c - && \
chmod +x /usr/local/bin/supercronic

# Copy stable cron files first (change less frequently)
COPY --chmod=755 ./oss/src/crons/queries.sh /queries.sh
COPY --chmod=644 ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
Expand All @@ -97,10 +110,19 @@ COPY --from=builder /app/oss /app/oss
COPY --from=builder /app/entrypoints /app/entrypoints
COPY --from=builder /app/sdk /app/sdk

# Generate supercronic-compatible crontab (strip user field and /proc redirects)
RUN set -eux; \
for cron_file in /etc/cron.d/queries-cron; do \
sed -i -e '$a\' "${cron_file}"; \
done
done; \
sed -E 's/^(([^[:space:]]+[[:space:]]+){5})root[[:space:]]+/\1/' /etc/cron.d/queries-cron \
| sed 's| >> /proc/1/fd/1 2>&1||' > /app/crontab

RUN groupadd --gid 10001 agenta && \
useradd --uid 10001 --gid 10001 --shell /bin/false --create-home agenta && \
chown -R agenta:agenta /app

USER 10001

LABEL org.opencontainers.image.title="agenta-api" \
org.opencontainers.image.description="Agenta API GH runtime image" \
Expand Down
7 changes: 3 additions & 4 deletions api/oss/src/crons/queries.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#!/bin/sh
set -eu

AGENTA_AUTH_KEY=$(tr '\0' '\n' < /proc/1/environ | grep ^AGENTA_AUTH_KEY= | cut -d= -f2- || true)
AGENTA_AUTH_KEY="${AGENTA_AUTH_KEY:-replace-me}"
TRIGGER_INTERVAL=$(awk 'NR==2 {split($1, a, "/"); print (a[2] ? a[2] : 1)}' /etc/cron.d/queries-cron)
TRIGGER_INTERVAL=$(awk '/queries\.sh/ {split($1, a, "/"); print (a[2] ? a[2] : 1); exit}' /app/crontab)
NOW_UTC=$(date -u "+%Y-%m-%dT%H:%M:00Z")
MINUTE=$(date -u "+%M" | sed 's/^0*//')
ROUNDED_MINUTE=$(( (MINUTE / TRIGGER_INTERVAL) * TRIGGER_INTERVAL ))
Expand All @@ -12,7 +11,7 @@ TRIGGER_DATETIME="${TRIGGER_DATETIME}:$(printf "%02d" $ROUNDED_MINUTE):00Z"


echo "--------------------------------------------------------"
echo "[$(date)] queries.sh running from cron" >> /proc/1/fd/1
echo "[$(date)] queries.sh running from cron"

# Make POST request, show status and response
curl \
Expand All @@ -22,4 +21,4 @@ curl \
-H "Authorization: Access ${AGENTA_AUTH_KEY}" \
"http://api:8000/admin/evaluations/runs/refresh?trigger_interval=${TRIGGER_INTERVAL}&trigger_datetime=${TRIGGER_DATETIME}" || echo "❌ CURL failed"

echo "[$(date)] queries.sh done" >> /proc/1/fd/1
echo "[$(date)] queries.sh done"
2 changes: 1 addition & 1 deletion api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "api"
version = "0.92.0"
version = "0.92.1"
description = "Agenta API"
authors = [
{ name = "Mahmoud Mabrouk", email = "mahmoud@agenta.ai" },
Expand Down
Loading
Loading