Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
b218195
ci: re-enable AddressSanitizer on aarch64 via native arm64 runners
aflores-qb Jun 14, 2026
791893a
feat: track listened status for library files
pladux Jul 31, 2026
3d4dfaa
Merge pull request #461 from aflores-qb/fix/311-enable-asan-aarch64-n…
SciLor Aug 25, 2026
5d8c839
Add optional web UI login with cookie sessions and rate limiting.
Sep 13, 2026
2bff557
fix: improve git pull command in commit step to avoid submodule issues
SciLor Sep 14, 2026
b541699
Update frontend (make web)
SciLor Sep 14, 2026
e05598e
fix(http_server): keep serving stream files past the first EOF
alexander-wenzel-dev Sep 18, 2026
69e843d
perf(stream): skip encoding for range requests that force a box restart
alexander-wenzel-dev Sep 18, 2026
8069897
fix: export selected TAF tracks as Ogg or Zip
Sep 27, 2026
450b53c
fix: address web login review feedback
Sep 28, 2026
813e802
fix: install zip in runtime images for multi-track TAF export
Sep 28, 2026
f46bc8f
fix: replace mkdtemp with portable temp dir helper for TAF track export
Sep 28, 2026
8d81e10
docs: describe web radio streaming and its tuning settings
alexander-wenzel-dev Sep 18, 2026
ff1b20f
Merge pull request #478 from alexander-wenzel-dev/fix/stream-sticky-eof
SciLor Sep 29, 2026
398a404
Merge pull request #479 from alexander-wenzel-dev/perf/stream-skip-en…
SciLor Sep 29, 2026
5257f23
feat(os_ext): add osSpawnvp for shell-less external process invocation
SciLor Sep 30, 2026
c722f85
test: add tests/c unit test runner and consolidate server-lifecycle h…
SciLor Sep 30, 2026
54e8a27
feat(docs): add architecture and settings documentation
SciLor Sep 30, 2026
977be11
Merge pull request #467 from pladux/feature/listened
SciLor Sep 30, 2026
453763a
feat(settings): update permissions to allow GitHub CLI comments and r…
SciLor Sep 30, 2026
0b6673f
Fix CC3235 (Toniebox 1) misclassified as box generation TB2
SciLor Sep 30, 2026
a745789
docs: clarify instructions for modifying vendored submodule files
SciLor Sep 30, 2026
2aacb49
feat(docs): add issue triage documentation for open issues and PR status
SciLor Sep 30, 2026
8bdc5d8
docs: update PR status section to include frontend repo and detailed …
SciLor Sep 30, 2026
55fa444
docs: update issue triage documentation to reflect merged PR #317 and…
SciLor Sep 30, 2026
fdf9112
Merge pull request #482 from ditschi/feature/web-ui-auth
SciLor Sep 30, 2026
d461ca6
fix(cert): free the CA DER after signing an RSA certificate
emka Sep 30, 2026
6e30947
fix(server): clear authenticated on every pooled connection reuse
emka Sep 17, 2026
bdd5812
Merge pull request #477 from emka/fix/auth-pool-reuse-bypass
SciLor Oct 1, 2026
9d35539
Update frontend (make web)
SciLor Oct 1, 2026
a13dba7
fix(server): stop logging web UI bearer tokens as parse failures
Oct 1, 2026
e3e2716
fix: allow base URL redirect to web UI when web login is enabled
Oct 1, 2026
a6b8d97
Merge pull request #486 from ditschi/fix/485-bearer-auth-warn
SciLor Oct 2, 2026
78de422
Merge pull request #487 from ditschi/fix/web-auth-root-redirect
SciLor Oct 2, 2026
3e66ae7
Update frontend (make web)
SciLor Oct 2, 2026
a992b56
Update frontend (make web)
SciLor Oct 2, 2026
af5c114
feat: remove legacy admin GUI
ian0318git Oct 2, 2026
ebe1125
Add handleCorsOptions function for CORS support
henryk86 Oct 2, 2026
776bafe
Refactor handleCorsOptions call for clarity
henryk86 Oct 2, 2026
645c335
Refactor HTTP response handling in server.c
henryk86 Oct 2, 2026
382c2f6
Update server.c
henryk86 Oct 2, 2026
8579c93
Merge remote-tracking branch 'upstream/develop' into feature/taf-trac…
Oct 3, 2026
e0f9315
refactor: reuse existing helpers for TAF track export
Oct 3, 2026
2f17147
Merge pull request #484 from ditschi/feature/taf-track-download
SciLor Oct 4, 2026
fb92b72
Merge pull request #490 from henryk86/develop
SciLor Oct 4, 2026
71a1991
Merge pull request #491 from ian0318git/feature/489-sunset-legacy-adm…
SciLor Oct 4, 2026
e393e81
test: restore config.ini and web_users.json after with_server runs
SciLor Oct 4, 2026
bc81149
fix(cors): parse full HTTP method and harden preflight handler
SciLor Oct 4, 2026
c031a0e
Update frontend (make web)
SciLor Oct 4, 2026
0d95429
fix(cache): avoid NULL deref on /cache/ lookup of the list head
mrueg Oct 5, 2026
0f6685f
fix(multipart): reject empty boundary and clamp data-end length
mrueg Oct 5, 2026
1180f36
fix(esp32 upload): fix use-after-free and NULL deref in firmware upload
mrueg Oct 5, 2026
07e4686
fix(toniefile): avoid double pclose of the ffmpeg pipe
mrueg Oct 5, 2026
8b95222
fix(api): bound source list and path length in /api/fileEncode
mrueg Oct 5, 2026
7d9fb40
test: add hardening regression tests for PR #499/#501/#502/#503
SciLor Oct 5, 2026
d1d23f5
fix(toniefile): prevent shell command injection via ffmpeg source
mrueg Oct 5, 2026
4158c48
test: drop Encode494, it cannot tell the #494 bug from the fix
SciLor Oct 5, 2026
4c1ad0c
fix(api): never expose secret settings through getIndex
mrueg Oct 5, 2026
96fabb9
refactor(os_ext): move shell quoting to osShellQuote, fix Windows, ad…
SciLor Oct 5, 2026
ea872e5
test: catch private keys leaking through settings getIndex (#505)
SciLor Oct 5, 2026
25aff55
fix(web,tonies): close download file once in body callbacks
mrueg Oct 5, 2026
f5d65ca
fix(handler): stream passthrough headers instead of fixed stack buffers
mrueg Oct 5, 2026
5d89c9e
fix(cloud): bound URL parsing in split_url against redirect Location
mrueg Oct 5, 2026
4365c91
fix(esp32): prevent stack overflow parsing crafted NVS partitions
mrueg Oct 5, 2026
7c6801d
fix(rtnl): bound hex/escape output in RTNL log handlers
mrueg Oct 5, 2026
67eb70a
fix(tap): bound file count and path copies in TAP playlists
mrueg Oct 5, 2026
76168b8
test: cover #493/#495/#497, move string helpers to str_ext.c
SciLor Oct 5, 2026
0d1b92e
fix(esp32): abort NVS parsing when an item span is zero
mrueg Oct 5, 2026
a51a7c3
fix(cert): write private-key files with 0600 permissions
mrueg Oct 5, 2026
2c8f8ba
fix(net): bound the 16-bit word index when parsing "::" in IPv6
mrueg Oct 5, 2026
f9c3888
fix(security): run blacklist and crawler mitigations independently
mrueg Oct 5, 2026
8ba21f4
fix(tap): free resolved file path in tap_free
mrueg Oct 5, 2026
0e3d0aa
test: cover #508 crawler detection and #512 key file permissions
SciLor Oct 5, 2026
2f1b7bc
fix: RTNL length parsing, status after redirects, owner-only box keys
SciLor Oct 5, 2026
26a3613
fix(web): require HTTP 200 for a successful web_download
mrueg Oct 5, 2026
36b67f4
fix(cert): shared owner-only helper in cert.c, fix cert upload settings
SciLor Oct 5, 2026
bd1dc42
test: guard the multipart helper against the 64 KB upload hang
SciLor Oct 5, 2026
2ae8b50
fix(api): strip leading ".." in sanitizePath to stop path traversal (…
mrueg Oct 6, 2026
8c4acd0
fix(rtnl): validate field6 length before reading box-supplied data (#…
mrueg Oct 6, 2026
4d496e7
fix(http): validate Range and free Content-Range buffer (#515)
mrueg Oct 6, 2026
e225ebb
fix(toniefile): guard TAF append against open failure and bad header …
mrueg Oct 6, 2026
ba95a3a
fix(http): drop off-by-one in User-Agent copy (#517)
mrueg Oct 6, 2026
a69591a
fix(tls): free cert buffers on name-constraint rejection (#518)
mrueg Oct 6, 2026
2f96700
fix(tonies): bound tracks loop to the allocated count (#519)
mrueg Oct 6, 2026
24e5102
fix(mqtt): bound topic/instance formatting with osSnprintf (#520)
mrueg Oct 6, 2026
b2d1527
fix(cloud): reject non-hex hash in V3 OTA requests (#521)
mrueg Oct 6, 2026
d80f7d4
fix(esp32): validate filename and MAC in extractCerts (#522)
mrueg Oct 6, 2026
a5c23bd
fix(http): guard TAF-header skip against short files (#523)
mrueg Oct 6, 2026
b41dc44
fix: stop file read loops from spinning on short/failed reads (#524)
mrueg Oct 6, 2026
c1a826b
fix(fs): guard fsRemoveFilename against an empty string (#525)
mrueg Oct 6, 2026
201cb53
fix(content): free parsed fields before reloading on version mismatch…
mrueg Oct 6, 2026
e57fa45
fix(cache): don't leak a duplicate entry in cache_add (#527)
mrueg Oct 6, 2026
8e8744b
perf(settings): look up options by name with a sorted index + bsearch…
mrueg Oct 6, 2026
906c9b3
perf(api): move 405 KB encode source array off the request stack (#529)
mrueg Oct 6, 2026
ccc70a6
test: cover the sanitizePath, Range and extractCerts fixes (#513, #51…
SciLor Oct 6, 2026
084a461
test: cover fsRemoveFilename on empty input and settings lookup by na…
SciLor Oct 6, 2026
7b2a7d6
ci: run all tests in parallel to the builds, cancel the run on failure
SciLor Oct 6, 2026
62ff355
Validate filename and MAC in esp32 patchFirmware
SciLor Oct 6, 2026
69babb8
test: run integration tests in an isolated sandbox
SciLor Oct 6, 2026
bcc31ea
test: run the Python tests with pytest from the Makefile
SciLor Oct 6, 2026
a5dc050
test: add a Toniebox simulator and box connection tests
SciLor Oct 6, 2026
27751ff
test: add per-hardware box profiles with TLS parameters
SciLor Oct 6, 2026
6dda0a8
test: add a fake cloud and cloud proxy tests
SciLor Oct 6, 2026
7078c15
settings: park replaced settings memory instead of freeing it in place
SciLor Oct 6, 2026
1847198
Refuse downloads from non-public addresses (SSRF)
SciLor Oct 6, 2026
b2ede3f
ci: add concurrency settings to workflows for better job management
SciLor Oct 6, 2026
ede4009
Update frontend (make web)
SciLor Oct 7, 2026
cd9d212
fix(tls): no session resumption where boxes authenticate by certificate
Oaradla Oct 6, 2026
bebda08
fix(certs): uploads for a new box go to its own directory
Oaradla Oct 6, 2026
6452896
feat(esp32): patch the port the box connects to
Oaradla Oct 6, 2026
b2a6025
feat: add total audio length to TAF info (#537)
ditschi Oct 8, 2026
f09b4d4
test: run KeyPermissions512 from the sandbox, it needs the CA
SciLor Oct 8, 2026
427895e
ci: install ffmpeg for the tests job
SciLor Oct 8, 2026
8b39ac9
test: check lengthSeconds of an encoded TAF
SciLor Oct 8, 2026
06e08be
Bump actions/cache from 4 to 6
dependabot[bot] Oct 13, 2026
3513abe
fix(http): end the request line at its CRLF when the first read fills…
zimmermq Oct 11, 2026
8e3c22d
fix(test): run the key-permission hardening test against the sandbox
Oct 8, 2026
670986c
docker: drop privileges by numeric uid:gid so PUID collisions do not …
Sep 7, 2026
18d6189
fix(sse): take the event lock before the context lock in the keep-ali…
zimmermq Oct 11, 2026
f1aa684
test(sim): box profiles from captures of a CC3200 and an ESP32
Oaradla Oct 9, 2026
1d5063a
cloud: answers the boxes accept: claim 204, /v1/log answered, cloud t…
Oaradla Oct 9, 2026
944392f
Update frontend (make web)
SciLor Oct 15, 2026
ae15eb8
fix(sse): send the response header before a subscriber gets events (#…
zimmermq Oct 11, 2026
3209233
Update frontend (make web)
SciLor Oct 15, 2026
942c6c1
feat(server): check box certificates
Oaradla Oct 7, 2026
8291cda
test: set core.boxCertAuth per box in the log-only test
SciLor Oct 16, 2026
676612a
Makefile: auto-discover python tests
SciLor Oct 16, 2026
e5fac5c
Update frontend (make web)
SciLor Oct 16, 2026
d8a8965
Honor tracks= on /content/download for tag track export
Oct 17, 2026
d853b7a
Return 400 for an invalid track selection
Oct 18, 2026
bfc2374
Merge pull request #553 from ditschi/fix/track-export-content-download
SciLor Oct 23, 2026
0e47512
Merge pull request #554 from ditschi/fix/track-export-invalid-track-400
SciLor Oct 23, 2026
00b6c06
Write the track export zip in-process
Oct 18, 2026
70d86d3
Test zip entry names with UTF-8 track titles
Oct 18, 2026
f3d9fb6
Merge pull request #555 from ditschi/feature/in-process-track-zip
SciLor Oct 23, 2026
9784f78
Update apt-get commands to include update step before installing depe…
SciLor Oct 23, 2026
2ff53fc
Fix NULL localtime in zip writer, drop zip from Debian runtime image
SciLor Oct 23, 2026
6c8ae98
Update frontend (make web)
SciLor Oct 23, 2026
f610a2d
Serve JSON content files as application/json
SciLor Oct 24, 2026
2826493
ci: release candidates with their own tag prefix (rc_vX.Y.Z[-N|-rcN])…
SciLor Oct 24, 2026
132120e
Merge pull request #560 from toniebox-reverse-engineering/release-can…
SciLor Oct 24, 2026
f4ab2a4
docs: document release candidates and the Docker image tags in the RE…
SciLor Oct 24, 2026
bd1123f
docs: how to promote a good release candidate to a release
SciLor Oct 24, 2026
d212387
ci: stop metadata-action from adding an automatic latest tag
SciLor Oct 24, 2026
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
72 changes: 72 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"permissions": {
"allow": [
"Bash(rg:--max-depth:*)",
"Bash(grep:*)",
"Bash(find:. -type f:*)",
"Bash(ls:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(wc:*)",
"Bash(file:*)",
"Bash(stat:*)",
"Bash(readlink:*)",
"Bash(tree:-L 2:*)",
"Bash(diff:*)",
"Bash(which:*)",
"Bash(du:*)",
"Bash(df:*)",
"Bash(env)",
"Bash(pwd)",
"Bash(git status:*)",
"Bash(git log:*)",
"Bash(git diff:*)",
"Bash(git show:*)",
"Bash(git branch --list:*)",
"Bash(git ls-files:*)",
"Bash(git remote -v)",
"Bash(git submodule status:*)",
"Bash(git merge-base:*)",
"Bash(git fetch:*)",
"Bash(gh pr view:*)",
"Bash(gh pr list:*)",
"Bash(gh pr diff:*)",
"Bash(gh issue view:*)",
"Bash(gh issue list:*)",
"Bash(gh repo view:*)",
"Bash(gh auth status:*)",
"Bash(make)",
"Bash(make build:*)",
"Bash(make test:*)",
"Bash(make test_c:*)",
"Bash(make test_py:*)",
"Bash(make check_dependencies:*)",
"Bash(make submodules:*)",
"Bash(make cppcheck:*)",
"Bash(npm ls:*)",
"Bash(npm view:*)",
"Bash(node --version)",
"Bash(curl -s http://127.0.0.1:80*)",
"Bash(curl -s -i http://127.0.0.1:80*)",
"Bash(curl -s http://127.0.0.1:8443*)",
"Bash(curl -s http://127.0.0.1:18080*)",
"Bash(curl -s -i http://127.0.0.1:18080*)",
"Bash(docker ps:*)",
"Bash(docker logs:*)"
],
"deny": [
"Bash(git push:*)",
"Bash(rm:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(sftp:*)",
"Bash(ssh-keygen:*)",
"Bash(ssh-copy-id:*)",
"Bash(rsync:*-e ssh*)",
"Bash(rsync:*--rsh=ssh*)",
"Bash(gh pr comment:*)",
"Bash(gh issue comment:*)",
"Bash(gh pr review:*)"
]
}
}
10 changes: 5 additions & 5 deletions .github/workflows/build_commit_web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ jobs:
- name: Commit and push if changed
run: |
if [[ -n $(git status --porcelain) ]]; then
git add .
git commit -m "Update frontend (make web)"
git pull --rebase
git push
git add .
git commit -m "Update frontend (make web)"
git pull --no-recurse-submodules --no-tags --rebase
git push --no-recurse-submodules
else
echo "No changes to commit and push."
echo "No changes to commit and push."
fi

- name: Get Last Commit Hash
Expand Down
44 changes: 43 additions & 1 deletion .github/workflows/build_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,49 @@ on:
pull_request:
branches: [ "master", "develop" ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref_type == 'branch' || github.event_name == 'pull_request' }}

jobs:
# runs next to the builds; if a test fails, the whole run is cancelled
tests:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write # only for cancelling this run
steps:
- uses: actions/checkout@v7
with:
submodules: recursive

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gcc protobuf-c-compiler build-essential openssl faketime python3 python3-pytest curl ffmpeg

# the tests start a server and check the web UI it serves
- name: Build web UI
run: |
make web
mkdir -p data/www/web
cp -r contrib/data/www/web/. data/www/web/

# generating the test certificates takes minutes, see tests/py/with_server.sh
- name: Cache test template
uses: actions/cache@v6
with:
path: bin/test-template
key: test-template-${{ hashFiles('src/cert.c', 'include/cert.h') }}

- name: Run all tests
run: make test

- name: Cancel the run on failed tests
if: failure()
continue-on-error: true # PRs from forks only get a read-only token
env:
GH_TOKEN: ${{ github.token }}
run: gh run cancel ${{ github.run_id }} --repo "$GITHUB_REPOSITORY"

build-windows-amd64:
runs-on: windows-latest
outputs:
Expand Down Expand Up @@ -49,7 +91,7 @@ jobs:
appendix: ${{ steps.set_data2.outputs.appendix }}
steps:
- name: Install build dependencies
run: sudo apt-get install -y --no-install-recommends gcc protobuf-c-compiler build-essential
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gcc protobuf-c-compiler build-essential
- name: Get current datetime
id: get-datetime
run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
Expand Down
34 changes: 28 additions & 6 deletions .github/workflows/publish_docker_matrix_all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@ on:
tags:
- tc_nightly*
- tc_v*.*.*
# release candidates: images only (rc, rc0.7.1, ...), no release, never latest; cut from develop
- rc_v*.*.*
pull_request:
branches:
- master
- develop

concurrency:
# release candidates share one group: rc / rc0.x.y are moving tags, runs must not overlap
group: ${{ github.workflow }}-${{ startsWith(github.ref_name, 'rc_v') && 'release-candidates' || github.ref }}
cancel-in-progress: ${{ github.ref_type == 'branch' || github.event_name == 'pull_request' }}

jobs:
test_commit_hash:
runs-on: ubuntu-latest
Expand All @@ -28,6 +35,17 @@ jobs:
submodules: recursive
ref: ${{ inputs.tcw_commit_hash }}

# a release candidate is cut from develop: refuse an rc_ tag whose commit is not reachable from it
- name: Check that the release candidate tag is on develop
if: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'rc_v') }}
run: |
git fetch --no-tags --unshallow origin develop || git fetch --no-tags origin develop
commit="$(git rev-parse HEAD)"
if ! git merge-base --is-ancestor "$commit" FETCH_HEAD; then
echo "::error::$GITHUB_REF_NAME points at $commit, which is not on develop. Release candidates are cut from develop."
exit 1
fi

- name: Verify commit hash
if: ${{ inputs.tcw_commit_hash != '' }}
run: |
Expand All @@ -48,7 +66,8 @@ jobs:
platforms: '["linux/amd64", "linux/arm/v7", "linux/arm64/v8", "linux/ppc64le", "linux/s390x"]'
primary_image: true
error_platforms: '["linux/s390x"]'
noasan_fallback_platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
# arm64 builds with AddressSanitizer (native runner, see base workflow).
noasan_fallback_platforms: '["linux/arm/v7", "linux/ppc64le"]'
tcw_commit_hash: ${{ inputs.tcw_commit_hash }}
debian:
needs: test_commit_hash
Expand All @@ -59,7 +78,8 @@ jobs:
platforms: '["linux/amd64", "linux/arm/v7", "linux/arm64/v8", "linux/i386", "linux/ppc64le", "linux/s390x"]'
primary_image: false
error_platforms: '["linux/s390x"]'
noasan_fallback_platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
# arm64 builds with AddressSanitizer (native runner, see base workflow).
noasan_fallback_platforms: '["linux/arm/v7", "linux/ppc64le"]'
tcw_commit_hash: ${{ inputs.tcw_commit_hash }}
alpine:
needs: test_commit_hash
Expand All @@ -79,9 +99,10 @@ jobs:
with:
system: "ubuntuAsanTest"
dockerfile: "DockerfileUbuntu"
platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
# arm64 is promoted to the main build; these remain ASAN-broken under QEMU.
platforms: '["linux/arm/v7", "linux/ppc64le"]'
primary_image: false
error_platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
error_platforms: '["linux/arm/v7", "linux/ppc64le"]'
noasan_fallback_platforms: "[]"
skip_empty_merge: true
tcw_commit_hash: ${{ inputs.tcw_commit_hash }}
Expand All @@ -91,9 +112,10 @@ jobs:
with:
system: "debianAsanTest"
dockerfile: "DockerfileDebian"
platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
# arm64 is promoted to the main build; these remain ASAN-broken under QEMU.
platforms: '["linux/arm/v7", "linux/ppc64le"]'
primary_image: false
error_platforms: '["linux/arm/v7", "linux/arm64/v8", "linux/ppc64le"]'
error_platforms: '["linux/arm/v7", "linux/ppc64le"]'
noasan_fallback_platforms: "[]"
skip_empty_merge: true
tcw_commit_hash: ${{ inputs.tcw_commit_hash }}
95 changes: 93 additions & 2 deletions .github/workflows/publish_docker_matrix_base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ jobs:
fail-fast: false
matrix:
platform: ${{ fromJson(inputs.platforms) }}
runs-on: ubuntu-latest
# aarch64 is built/tested natively so AddressSanitizer works (QEMU-user
# emulation cannot satisfy libasan's fixed 64-bit allocator mapping).
# All other platforms stay on the amd64 runner and cross-build via QEMU.
runs-on: ${{ matrix.platform == 'linux/arm64/v8' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v7
with:
Expand All @@ -70,6 +73,20 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Release candidate version
id: rc_version
if: ${{ startsWith(github.ref, 'refs/tags/rc_v') }}
run: |
# rc_v0.7.1, rc_v0.7.1-1 or rc_v0.7.1-rc0: base = 0.7.1, full = 0.7.1-1 / 0.7.1-rc0 (empty for the base tag)
ver="${GITHUB_REF_NAME#rc_v}"
if ! [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
echo "::error::$GITHUB_REF_NAME is not rc_vX.Y.Z or rc_vX.Y.Z-<suffix>"
exit 1
fi
base="${ver%%-*}"
echo "base=$base" >> "$GITHUB_OUTPUT"
if [ "$ver" != "$base" ]; then echo "full=$ver" >> "$GITHUB_OUTPUT"; fi

- name: Docker meta matrix
id: matrix_meta
uses: docker/metadata-action@v6
Expand All @@ -86,15 +103,37 @@ jobs:
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/tc_v') }}
type=raw,value=nightly,enable=${{ startsWith(github.ref, 'refs/tags/tc_nightly') }}
type=raw,value=nightly-develop,enable=${{ github.ref == 'refs/heads/develop' }}
type=raw,value=rc,enable=${{ startsWith(github.ref, 'refs/tags/rc_v') }}
type=raw,value=rc${{ steps.rc_version.outputs.base }},enable=${{ startsWith(github.ref, 'refs/tags/rc_v') }}
type=raw,value=rc${{ steps.rc_version.outputs.full }},enable=${{ startsWith(github.ref, 'refs/tags/rc_v') && steps.rc_version.outputs.full != '' }}
type=ref,event=tag
type=match,pattern=tc_v(\d+),group=1
type=match,pattern=tc_v(\d+.\d+),group=1
type=match,pattern=tc_v(\d+.\d+.\d+),group=1
type=match,pattern=tc_v(\d+.\d+.\d+-\S+),group=1
flavor: |
latest=false
prefix=arch_,onlatest=true
suffix=_${{ matrix.platform }}_${{ inputs.system }},onlatest=${{ inputs.primary_image }}

- name: Release candidates must not move latest or the plain version tags
if: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'rc_v') }}
env:
TAGS: ${{ steps.matrix_meta.outputs.tags }}
run: |
# do not rely on metadata-action internals (e.g. automatic latest): look at what it generated
echo "$TAGS"
bad=0
while read -r tag; do
[ -n "$tag" ] || continue
name="${tag##*:}"; name="${name#arch_}"; name="${name%%_*}"
if [ "$name" = latest ] || [[ "$name" =~ ^[0-9]+(\.[0-9]+){0,2}$ ]]; then
echo "::error::release candidate $GITHUB_REF_NAME would get the image tag '$tag'"
bad=1
fi
done <<< "$TAGS"
exit $bad

- name: Modify tags
id: modify_tags
if: ${{ inputs.primary_image }}
Expand Down Expand Up @@ -141,10 +180,27 @@ jobs:
platform=$(echo "${{ matrix.platform }}" | tr '/' '_')
echo "platform=$platform"
echo "platform=$platform" >> $GITHUB_OUTPUT
- name: Lower ASLR entropy for AddressSanitizer (aarch64)
if: ${{ matrix.platform == 'linux/arm64/v8' }}
run: |
# Native arm64 runners use a recent kernel with vm.mmap_rnd_bits=32, which can
# collide with libasan's fixed 64-bit allocator base and abort at startup with
# "CHECK failed: sanitizer_allocator_primary64.h". 28 still gives strong ASLR.
# Load-bearing when the base image's libasan predates LLVM 17 (GCC <=13); a
# no-op for GCC 14+, which moved the allocator base to tolerate 32-bit ASLR.
# vm.* sysctls are not namespaced, so this host-level change reaches the
# container started below. CI-only; does not touch shipped images. Non-fatal.
sudo sysctl -w vm.mmap_rnd_bits=28 || echo "warning: could not set vm.mmap_rnd_bits"
- name: Run docker image test
id: docker-test
run: |
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# QEMU binfmt is only needed to run foreign-arch containers on the amd64
# runner. The native arm64 runner runs arm64 containers directly, and the
# multiarch/qemu-user-static helper is not arm64-compatible there
# (it fails with "Exec format error"), so skip it for arm64.
if [ "${{ matrix.platform }}" != "linux/arm64/v8" ]; then
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
fi
if [ "${{ github.event_name }}" = "pull_request" ]; then
docker run -e DOCKER_TEST=1 --platform ${{ matrix.platform }} --name teddyCloud-test teddycloud-test:local
else
Expand Down Expand Up @@ -231,6 +287,20 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Release candidate version
id: rc_version
if: ${{ startsWith(github.ref, 'refs/tags/rc_v') }}
run: |
# rc_v0.7.1, rc_v0.7.1-1 or rc_v0.7.1-rc0: base = 0.7.1, full = 0.7.1-1 / 0.7.1-rc0 (empty for the base tag)
ver="${GITHUB_REF_NAME#rc_v}"
if ! [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
echo "::error::$GITHUB_REF_NAME is not rc_vX.Y.Z or rc_vX.Y.Z-<suffix>"
exit 1
fi
base="${ver%%-*}"
echo "base=$base" >> "$GITHUB_OUTPUT"
if [ "$ver" != "$base" ]; then echo "full=$ver" >> "$GITHUB_OUTPUT"; fi

- name: Docker meta
if: ${{ steps.check_digests.outputs.has_digests == 'true' }}
id: teddycloud_meta # you'll use this in the next step
Expand All @@ -250,14 +320,35 @@ jobs:
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/tc_v') }}
type=raw,value=nightly,enable=${{ startsWith(github.ref, 'refs/tags/tc_nightly') }}
type=raw,value=nightly-develop,enable=${{ github.ref == 'refs/heads/develop' }}
type=raw,value=rc,enable=${{ startsWith(github.ref, 'refs/tags/rc_v') }}
type=raw,value=rc${{ steps.rc_version.outputs.base }},enable=${{ startsWith(github.ref, 'refs/tags/rc_v') }}
type=raw,value=rc${{ steps.rc_version.outputs.full }},enable=${{ startsWith(github.ref, 'refs/tags/rc_v') && steps.rc_version.outputs.full != '' }}
type=ref,event=tag
type=match,pattern=tc_v(\d+),group=1
type=match,pattern=tc_v(\d+.\d+),group=1
type=match,pattern=tc_v(\d+.\d+.\d+),group=1
type=match,pattern=tc_v(\d+.\d+.\d+-\S+),group=1
flavor: |
latest=false
suffix=_${{ inputs.system }},onlatest=${{ !inputs.primary_image }}

- name: Release candidates must not move latest or the plain version tags
if: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'rc_v') }}
env:
TAGS: ${{ steps.teddycloud_meta.outputs.tags }}
run: |
# do not rely on metadata-action internals (e.g. automatic latest): look at what it generated
echo "$TAGS"
bad=0
while read -r tag; do
[ -n "$tag" ] || continue
name="${tag##*:}"; name="${name#arch_}"; name="${name%%_*}"
if [ "$name" = latest ] || [[ "$name" =~ ^[0-9]+(\.[0-9]+){0,2}$ ]]; then
echo "::error::release candidate $GITHUB_REF_NAME would get the image tag '$tag'"
bad=1
fi
done <<< "$TAGS"
exit $bad
- name: Create manifest list and push (primary)
if: ${{ inputs.primary_image && steps.check_digests.outputs.has_digests == 'true' }}
working-directory: /tmp/digests/${{ github.sha }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ fake-server-tb2/*
/dev-sandbox/run/
/dev-sandbox/.teddycloud-native.pid
*.pcap

# scratch notes, not committed
tmp/
Loading
Loading