Files
JRay-public-server/.gitea/workflows/ci.yml
T
dtourolleandClaude Opus 5 a848750a65
CI / fmt, clippy, test (push) Failing after 2m46s
CI / static musl binary (push) Has been skipped
CI / advisories and licences (push) Successful in 4m22s
Initial implementation: core vertical slice
Implements the core of SPEC.md — the manifest exchange, less audio-tier
matching (§3) and federation (§9a), both of which the spec sequences as
later work.

- §2 Jmanifest format and series bundles
- §3 cut matching: exact / runtime / loose tiers
- §4 API, less POST /manifests/search
- §5 rate limiting; §5a trust model, anonymous bearer tokens
- §6 upload validation, all four stages
- §7 relational storage, no JSON blob on the write path
- §8 Rust + Axum + SQLite, single serialized writer, in-process job queue
- §9a content addressing, computed on upload

Reconciled against the system spec:

- anneal_sec removed, withdrawn upstream by AR-012/AR-013. Presence follows
  track extent, so a track survives its own gaps and there is nothing to
  anneal. Its successor extinction_sec and the new gallery_scope are accepted
  and stored; scope enters the §7 ranking. A manifest still carrying
  anneal_sec is a hard 400, not silently ignored — it came from a pipeline
  whose window semantics differ from what this server assumes.
- Audio signature: media under 120 s now emits no signature at all, matching
  scene-actor-extraction IR-007. The earlier §3 draft allowed a shortened
  window under 150 s, which was the weaker rule — a caller-varying length is
  the property SR-004 forbids.
- UR IDs regularised to UR-nnn; docs/requirements.md registers 32
  requirements, each tracing to an SR-nnn or PR-nnn.

189 tests: unit, end-to-end through the real router, and an injection suite
covering SQL, JSON, header and Unicode payloads. Writing that suite found two
real gaps, both fixed here: compatibility homoglyphs passed the §5a character
class, and a one-frame audio signature was accepted on a feature-length item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 18:14:02 +02:00

152 lines
5.0 KiB
YAML

# Gitea Actions CI.
#
# Gitea Actions is workflow-compatible with GitHub Actions, so this runs on either
# with no changes. It needs a registered runner with the `ubuntu-latest` label.
#
# The gates, in the order they fail fastest:
# fmt — formatting, seconds
# clippy — lints, denied rather than warned
# test — 160 unit + integration tests
# deny — RustSec advisories, licence policy, source policy
# musl — the artifact §8 actually ships: one static binary
name: CI
on:
push:
branches: [main, master]
pull_request:
# Advisories appear without any code changing, so the dependency audit also
# runs on a schedule rather than only on push.
schedule:
- cron: "0 6 * * 1"
env:
CARGO_TERM_COLOR: always
# Fail the build on warnings. The tree is warning-clean, so keeping it that way
# is cheaper than letting warnings accumulate.
RUSTFLAGS: "-D warnings"
jobs:
check:
name: fmt, clippy, test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: |
# rustup is not guaranteed present on a self-hosted Gitea runner.
if ! command -v rustup >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --component rustfmt,clippy
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
else
rustup component add rustfmt clippy
fi
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
- name: Formatting
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --all-targets --all-features
- name: Tests
run: cargo test --all-features
deny:
name: advisories and licences
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: |
if ! command -v rustup >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
fi
- name: Cache cargo-deny
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-deny
key: ${{ runner.os }}-cargo-deny
- name: Install cargo-deny
run: |
command -v cargo-deny >/dev/null 2>&1 || cargo install cargo-deny --locked
# Advisories, licences, bans and sources — see deny.toml for why the licence
# allow-list is closed rather than a deny-list.
- name: cargo deny
run: cargo deny check
musl:
name: static musl binary
runs-on: ubuntu-latest
# Only gate merges on the artifact build once the cheaper checks have passed.
needs: check
steps:
- uses: actions/checkout@v4
- name: Install Rust and musl target
run: |
if ! command -v rustup >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
export PATH="$HOME/.cargo/bin:$PATH"
fi
rustup target add x86_64-unknown-linux-musl
sudo apt-get update && sudo apt-get install -y musl-tools
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-musl-${{ hashFiles('Cargo.lock') }}
restore-keys: ${{ runner.os }}-musl-
# §8: "Ship a single static binary (musl target) plus the SQLite file."
# rusqlite is built with `bundled`, so SQLite is compiled in; reqwest uses
# rustls rather than OpenSSL, so there is no system TLS dependency to link.
- name: Build
run: cargo build --release --target x86_64-unknown-linux-musl
- name: Verify the binary is actually static
run: |
BIN=target/x86_64-unknown-linux-musl/release/jray-server
file "$BIN"
# A dynamically-linked result would defeat §8's deployment story, so this
# is asserted rather than assumed.
#
# Checked with `file`, not `ldd`: the musl target produces a static-PIE,
# and `ldd` prints the musl loader for one — an `ldd`-based check reports
# a perfectly static binary as dynamic.
if ! file "$BIN" | grep -qE 'static-pie linked|statically linked'; then
echo "::error::binary is not statically linked" >&2
exit 1
fi
- name: Upload binary
uses: actions/upload-artifact@v3
with:
name: jray-server-x86_64-musl
path: target/x86_64-unknown-linux-musl/release/jray-server
if-no-files-found: error