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
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
[*.{yml,yaml,json}]
indent_size = 2
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
113 changes: 113 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: ci

on:
push:
branches: [master]
tags: ['v*']
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
lint:
name: shellcheck
runs-on: ubuntu-latest
# The init script and the installers run under BusyBox ash on the camera, where nobody watches
# them fail. SC2155 is off: `export X="$(fw_printenv ...)"` masking the exit status is the point —
# a key that is not set is simply empty.
steps:
- uses: actions/checkout@v4
- run: shellcheck -S warning -e SC2155 S99cerberus bootstrap.sh uninstall.sh ci/build.sh tests/run.sh tests/suite.sh

test:
name: tests (${{ matrix.name }})
runs-on: ubuntu-latest
# Both mbedTLS generations are in the field: 3.x on current distros and in Alpine (musl, which is
# what OpenIPC is), 2.28 LTS in Buildroot-era firmware — and Debian bookworm carries exactly that.
# The suite builds with -Werror, enrols against a fake coordinator over real TLS, and brings up a
# real WireGuard tunnel to a hub in its own netns; REQUIRE_WG turns a runner without kernel
# WireGuard into a failure instead of a silently skipped section. ubuntu-latest has it.
strategy:
fail-fast: false
matrix:
include:
- name: musl, mbedTLS 3.x
image: alpine:3.20
- name: glibc, mbedTLS 2.28
image: debian:bookworm-slim
steps:
- uses: actions/checkout@v4

- name: Test
run: tests/run.sh
env:
CERBERUS_TEST_IMAGE: ${{ matrix.image }}
REQUIRE_WG: '1'

build:
name: build (${{ matrix.arch }})
runs-on: ubuntu-latest
# The real target is arm; a compile-only x64 job would keep reporting green while the binary the
# firmware needs does not exist. musl-armv7 is the artefact that actually goes into OpenIPC
# firmware and builds in an emulated armv7 Alpine, so it is the one target here that needs binfmt.
# The ELF-architecture assertion lives in the script, next to the build that produced the binary.
strategy:
fail-fast: false
matrix:
arch: [musl-armv7, armhf, arm64, amd64]
steps:
- uses: actions/checkout@v4
with:
# git describe needs the tags: the version compiled into the binary comes from them.
fetch-depth: 0

- name: Enable arm emulation
if: matrix.arch == 'musl-armv7'
uses: docker/setup-qemu-action@v3
with:
platforms: arm

- name: Build and package
run: ci/build.sh ${{ matrix.arch }}

- uses: actions/upload-artifact@v4
with:
name: cerberus-${{ matrix.arch }}
path: dist/*.tar.gz*
if-no-files-found: error

release:
name: release
# A v* tag publishes the tarballs that were just built and tested — the same artefacts, not a
# rebuild — as a GitHub release.
if: startsWith(github.ref, 'refs/tags/v')
needs: [lint, test, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
pattern: cerberus-*
path: dist
merge-multiple: true

- name: Every tarball carries the tag's version
run: |
want="${GITHUB_REF_NAME#v}"
ls dist
for f in dist/*.tar.gz; do
case "$(basename "$f")" in
"cerberus-$want-linux-"*) ;;
*) echo "$f was not built as $want"; exit 1 ;;
esac
done

- name: Publish
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" dist/* \
--repo "$GITHUB_REPOSITORY" --title "cerberus ${GITHUB_REF_NAME#v}" --generate-notes --verify-tag
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# build output
/cerberus
/dist/
*.o
57 changes: 57 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## The Prosperity Public License 3.0.0

Contributor: OpenIPC (c) 2026

Source Code: https://github.com/OpenIPC/cerberus

### Purpose

This license allows you to use and share this software for noncommercial purposes for free and to try this software for commercial purposes for thirty days.

### Agreement

In order to receive this license, you have to agree to its rules. Those rules are both obligations under that agreement and conditions to your license. Don't do anything with this software that triggers a rule you can't or won't follow.

### Notices

Make sure everyone who gets a copy of any part of this software from you, with or without changes, also gets the text of this license and the contributor and source code lines above.

### Commercial Trial

Limit your use of this software for commercial purposes to a thirty-day trial period. If you use this software for work, your company gets one trial period for all personnel, not one trial per person.

### Contributions Back

Developing feedback, changes, or additions that you contribute back to the contributor on the terms of a standardized public software license such as [the Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0), [the Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), [the MIT license](https://spdx.org/licenses/MIT.html), or [the two-clause BSD license](https://spdx.org/licenses/BSD-2-Clause.html) doesn't count as use for a commercial purpose.

### Personal Uses

Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, doesn't count as use for a commercial purpose.

### Noncommercial Organizations

Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution doesn't count as use for a commercial purpose regardless of the source of funding or obligations resulting from the funding.

### Defense

Don't make any legal claim against anyone accusing this software, with or without changes, alone or with other technology, of infringing any patent.

### Copyright

The contributor licenses you to do everything with this software that would otherwise infringe their copyright in it.

### Patent

The contributor licenses you to do everything with this software that would otherwise infringe any patents they can license or become able to license.

### Reliability

The contributor can't revoke this license.

### Excuse

You're excused for unknowingly breaking Notices if you take all practical steps to comply within thirty days of learning you broke the rule.

### No Liability

_**As far as the law allows, this software comes as is, without any warranty or condition, and the contributor won't be liable to anyone for any damages related to this software or this license, under any kind of legal claim.**_
62 changes: 62 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# cerberus — on-camera agent. mbedTLS is the only dependency; everything else is libc.
#
# Native build: make
# Static binary: make STATIC=1
# Cross (OpenIPC): make CC=arm-openipc-linux-musleabi-gcc MBEDTLS=/path/to/staging STATIC=1
# Release version: make VERSION=1.2.0 (otherwise the version in main.c)
# Tests: make test (needs Docker; see tests/run.sh)
#
# MBEDTLS points at a prefix holding include/mbedtls and lib/libmbed*. Leave it empty when the
# toolchain already sees them (a distro's mbedtls-dev, or a Buildroot sysroot).

CC ?= cc
STRIP ?= strip
DESTDIR ?=
PREFIX ?= /usr
MBEDTLS ?=
VERSION ?=

CFLAGS ?= -Os -std=c99 -Wall -Wextra -ffunction-sections -fdata-sections
LDFLAGS ?= -Wl,--gc-sections
LIBS = -lmbedtls -lmbedx509 -lmbedcrypto

# CI adds -Werror here without having to restate the defaults above.
CFLAGS += $(EXTRA_CFLAGS)

ifneq ($(VERSION),)
CFLAGS += -DCERBERUS_VERSION=\"$(VERSION)\"
endif

ifneq ($(MBEDTLS),)
CFLAGS += -I$(MBEDTLS)/include
LDFLAGS += -L$(MBEDTLS)/lib
endif

ifeq ($(STATIC),1)
LDFLAGS += -static
endif

BIN = cerberus

all: $(BIN)

$(BIN): main.c
$(CC) $(CFLAGS) -o $@ main.c $(LDFLAGS) $(LIBS)
$(STRIP) $@
@echo "==> $@: $$(wc -c <$@) bytes"

size: $(BIN)
@size $(BIN) || true
@ls -l $(BIN)

install: $(BIN)
install -D -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/sbin/$(BIN)
install -D -m 0755 S99cerberus $(DESTDIR)/etc/init.d/S99cerberus

test:
tests/run.sh

clean:
rm -f $(BIN)

.PHONY: all size install test clean
Loading
Loading