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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ jobs:
! command -v node
! command -v npm
! command -v git
! command -v curl
! command -v pipenv
test "$(id -u)" -eq 10001
test -x /app/scripts/run.sh
Expand All @@ -63,3 +64,14 @@ jobs:
python -c "import asyncio, os; from algosdk import account, mnemonic; private_key, _ = account.generate_account(); os.environ[\"ALGO_MNEMONIC\"] = mnemonic.from_private_key(private_key); import app; assert asyncio.run(app.status())[\"version\"] == app.VERSION"
python -m pip check
'
- name: Scan production image
run: |
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f \
image \
--no-progress \
--scanners vuln,secret \
--severity HIGH,CRITICAL \
--exit-code 1 \
"cometa-backend:${COMETA_IMAGE_TAG:-local}"
2 changes: 1 addition & 1 deletion BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
| Precision-safe pricing | done | Decimal observations, provenance, freshness policy, guarded legacy boundary |
| Provider resilience | done | Typed fallback errors, bounded stale data, retry classification, circuit breaker |
| Replay identity | done | Deterministic nested event IDs and collection-level uniqueness constraints |
| Container baseline | done | Digest-pinned base, unprivileged user, healthcheck, bounded logs, Docker exclusions |
| Container baseline | done | Digest-pinned Alpine base, multi-stage non-root runtime, healthcheck, image exclusions, Trivy CI gate |
| API hardening | done | Fail-closed header authentication, trusted hosts, explicit CORS policy, bounded LP/asset/wallet requests |
| Native Reach decoding | done | Versioned global/local codecs, exact-width integers, deterministic layout tests, no private npm runtime |
| Legacy runtime removal | done | CB-077: Node/Reach sidecar and production source bind mount removed |
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Backend for Cometa — an Algorand DeFi platform handling liquidity pools, token
- **Blockchain**: Algorand (py-algorand-sdk, algosdk)
- **Contract state**: versioned native Reach decoder over Algorand state
- **Deployment**: Docker Compose on VPS
- **Image**: digest-pinned Python 3.12 slim
- **Image**: digest-pinned Python 3.12 Alpine

## Project Structure

Expand Down
12 changes: 5 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.12-slim@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de AS builder
FROM python:3.12-alpine@sha256:6d43704baacd1bfbe7c295d7f13079d5d8104ed33568873133f8fc69980419df AS builder

WORKDIR /app

Expand All @@ -10,17 +10,15 @@ ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \

ARG PIPENV_RELEASE=2024.4.0

RUN apt-get update \
&& apt-get install --yes --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
RUN apk add --no-cache build-base git libffi-dev

COPY Pipfile Pipfile.lock ./
RUN python -m venv /opt/pipenv \
&& /opt/pipenv/bin/pip install "pipenv==${PIPENV_RELEASE}" \
&& /opt/pipenv/bin/pipenv verify \
&& /opt/pipenv/bin/pipenv sync

FROM python:3.12-slim@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de AS runtime
FROM python:3.12-alpine@sha256:6d43704baacd1bfbe7c295d7f13079d5d8104ed33568873133f8fc69980419df AS runtime

WORKDIR /app

Expand All @@ -30,8 +28,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \

COPY --from=builder /app/.venv /app/.venv

RUN groupadd --system --gid 10001 cometa \
&& useradd --system --uid 10001 --gid cometa --home-dir /home/cometa --create-home cometa
RUN addgroup -S -g 10001 cometa \
&& adduser -S -D -u 10001 -G cometa -h /home/cometa cometa

COPY --chown=cometa:cometa app.py env.py telegram_bot.py ./
COPY --chown=cometa:cometa api ./api
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<p align="center">
<a href="https://github.com/MetaLabsOG/cometa-backend/actions/workflows/ci.yml"><img src="https://github.com/MetaLabsOG/cometa-backend/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.12-3776AB?logo=python&logoColor=white" alt="Python 3.12" /></a>
<a href="https://fastapi.tiangolo.com/"><img src="https://img.shields.io/badge/FastAPI-0.135-009688?logo=fastapi&logoColor=white" alt="FastAPI" /></a>
<a href="https://fastapi.tiangolo.com/"><img src="https://img.shields.io/badge/FastAPI-0.139-009688?logo=fastapi&logoColor=white" alt="FastAPI" /></a>
<a href="https://developer.algorand.org/"><img src="https://img.shields.io/badge/Algorand-mainnet-black?logo=algorand&logoColor=white" alt="Algorand mainnet" /></a>
<a href="https://api.cometa.farm/status"><img src="https://img.shields.io/website?label=API&up_message=online&down_message=offline&url=https%3A%2F%2Fapi.cometa.farm%2Fstatus" alt="API status" /></a>
</p>
Expand Down Expand Up @@ -42,6 +42,7 @@ MongoDB—into stable, query-oriented API models for the product frontend.
| **Resilient price routing** | Vestige and Tinyman payloads are validated with provenance and bounded staleness; retry classification and a guarded Vestige refresh prevent failure storms. |
| **Operational boundaries** | Selected latency-sensitive SDK calls leave the event loop through executors; wallet fan-out is cached and bounded; background workers reconcile chain state without coupling reads to refresh latency. |
| **Versioned chain decoding** | Reach 0.1.11 state is decoded natively from Algorand with explicit per-version layouts, exact-width integers, and fail-closed schema validation. |
| **Supply-chain hardening** | The digest-pinned Alpine image is multi-stage, non-root, and Python-only; CI smoke-tests it and rejects high/critical vulnerabilities or embedded secrets. |

The codebase combines a production system's real constraints with incremental
modernization: pure domain modules and strict typing sit beside legacy adapters,
Expand Down Expand Up @@ -134,9 +135,10 @@ This single command runs:
state-codec and security-boundary tests.

CI repeats those checks on every pull request and every push to `main`, verifies
the lockfile, and validates the Compose configuration. The focused coverage
ratchet is currently 75%; it measures maintained domain and infrastructure
modules rather than presenting a misleading whole-repository number.
the lockfile and Compose configuration, builds and smoke-tests the production
image, and scans it with Trivy. The focused coverage ratchet is currently 75%;
it measures maintained domain and infrastructure modules rather than presenting
a misleading whole-repository number.

Useful individual targets are `make lint`, `make format-check`,
`make typecheck`, and `make test`.
Expand Down
14 changes: 7 additions & 7 deletions scripts/run.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/usr/bin/env bash
set -Eeuo pipefail
#!/bin/sh
set -eu

readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)"
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)"
project_root="$(dirname -- "${script_dir}")"

cd -- "${PROJECT_ROOT}"
cd -- "${project_root}"

if [[ ! -f "app.py" ]]; then
printf 'ERROR: application entrypoint not found: %s/app.py\n' "${PROJECT_ROOT}" >&2
if [ ! -f "app.py" ]; then
printf 'ERROR: application entrypoint not found: %s/app.py\n' "${project_root}" >&2
exit 1
fi

Expand Down