Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/.gitea/workflows/nightly.yml
Fimeg ff2f30f47a v0.2.9.3: device classification + ARM support — Pixel 3 lands
DEVICE-002: ARM machine-ID fallback — device-tree model + /etc/machine-id
combo, then /proc/cpuinfo Serial (all-zero rejected), before the weak
hostname fallback. Hardware-bound IDs on DMI-less devices.

DEVICE-001: agent detects device_type (server/desktop/phone/tablet) from
/sys signals — system battery (scope=Device peripherals excluded, UPS
excluded), DRM connector state, framebuffer min-dimension for phone/tablet
split. Reports device_type/device_model/os_distro in registration and
system-info paths.

SERVER-001: migration 061 — device_type, device_type_manual (operator
override, never agent-written), device_model, os_distro on agents.
effective_device_type computed into every serialized agent.

SERVER-002: PUT /admin/agents/:id/device-type — set/clear override,
enum-validated, journaled.

WEB-001: device-type icons + fleet filter, device model in list, detail
header badge with reclassify dropdown, os_distro surfaced.

INSTALL-003: arm64 install path unblocked — helper (required manifest
component) now cross-built aarch64-unknown-linux-musl via rust-lld in the
server image, signed at boot (helperArches += arm64), listed in the release
manifest. Install template already handled uname -m and pacman.

Plus in-flight: desktop tray wiring, enrollment page polish, CI workflow
updates, RAF session-broker/pacman-scanner docs, native installer scaffold.
2026-07-06 18:21:23 -04:00

216 lines
9.7 KiB
YAML

name: nightly
# Rolling alpha channel. Every night, if CI is green on public HEAD and there
# are new commits since the last nightly, build lean artifacts and replace the
# `nightly` prerelease on Gitea and Codeberg. Versioned releases stay on
# release.yml — this channel never tags v*, never ships a manifest, and is
# therefore invisible to fleet self-upgrade. Manual installs only.
on:
schedule:
- cron: "0 9 * * *"
workflow_dispatch: {}
permissions:
contents: write
jobs:
nightly:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: public
fetch-depth: 0
- name: Preflight — CI green, new commits since last nightly
id: pre
run: |
set -euo pipefail
SHA=$(git rev-parse HEAD)
SHORT=$(git rev-parse --short HEAD)
API="${GITHUB_SERVER_URL}/api/v1"
STATE=$(curl -sf -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"$API/repos/${GITHUB_REPOSITORY}/commits/$SHA/status" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('state',''))" || echo "")
echo "HEAD=$SHA ci_state=$STATE"
if [ "$STATE" != "success" ]; then
echo "[INFO] [nightly] CI not green on public HEAD (state=$STATE) — no build tonight"
echo "go=false" >> "$GITHUB_OUTPUT"
exit 0
fi
PREV=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"$API/repos/${GITHUB_REPOSITORY}/releases/tags/nightly" \
| python3 -c "
import json,sys
try:
r = json.load(sys.stdin)
sha = r.get('target_commitish','')
print(sha if len(sha) == 40 else '')
except Exception:
print('')")
if [ "$PREV" = "$SHA" ]; then
echo "[INFO] [nightly] public HEAD unchanged since last nightly — nothing to build"
echo "go=false" >> "$GITHUB_OUTPUT"
exit 0
fi
BASE=$(grep -P '^\s*AgentVersion\s*=' server/internal/version/versions.go | grep -oP '"\K[^"]+')
VERSION="${BASE}-nightly.$(date -u +%Y%m%d).${SHORT}"
{
echo "go=true"
echo "sha=$SHA"
echo "short=$SHORT"
echo "prev=$PREV"
echo "version=$VERSION"
} >> "$GITHUB_OUTPUT"
echo "Building nightly $VERSION (prev nightly: ${PREV:-none})"
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
if: steps.pre.outputs.go == 'true'
with:
go-version-file: agent/go.mod
cache: true
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
if: steps.pre.outputs.go == 'true'
with:
node-version: 20
cache: npm
cache-dependency-path: web/package-lock.json
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
if: steps.pre.outputs.go == 'true'
- name: Build web UI and stage embed
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
cd web && npm ci && npm run build && cd ..
rm -rf server/internal/webui/dist
cp -r web/dist server/internal/webui/dist
test -s server/internal/webui/dist/index.html
# Agent + helper only. The server is NOT shipped on the nightly channel:
# its supported install paths are docker-compose-from-source today and the
# per-OS installers landing in v0.3.0 — both verify the signed release
# manifest, which nightly deliberately does not generate. Shipping a bare
# nightly server tarball would be an install artifact with a stub manifest,
# so it's left to the versioned (v*) channel where the manifest is real.
- name: Build agent + helper binaries (linux-amd64 + windows-amd64)
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
VERSION="${{ steps.pre.outputs.version }}"
mkdir -p dist
build_agent () { # $1=goos $2=suffix $3=ext
GOOS=$1 GOARCH=amd64 CGO_ENABLED=0 sh -c "
cd agent && go build -ldflags \"-s -w \
-X github.com/Fimeg/RedFlag/agent/internal/version.Version=$VERSION \
-X github.com/Fimeg/RedFlag/agent/internal/version.ConfigVersion=$VERSION \
-X github.com/Fimeg/RedFlag/agent/internal/version.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \
-o ../dist/redflag-agent-$2$3 ./cmd/agent/"
}
build_agent linux linux-amd64 ""
build_agent windows windows-amd64 ".exe"
cd helper && cargo build --release && cd ..
cp helper/target/release/redflag-helper dist/redflag-helper-linux-amd64
- name: Package
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
VERSION="${{ steps.pre.outputs.version }}"
cd dist
tar czf redflag-$VERSION-linux-amd64.tar.gz redflag-agent-linux-amd64 redflag-helper-linux-amd64
zip -q redflag-$VERSION-windows-amd64.zip redflag-agent-windows-amd64.exe
sha256sum redflag-$VERSION-linux-amd64.tar.gz redflag-$VERSION-windows-amd64.zip > checksums-$VERSION.txt
ls -la
- name: Write release notes
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
SHA="${{ steps.pre.outputs.sha }}"
PREV="${{ steps.pre.outputs.prev }}"
VERSION="${{ steps.pre.outputs.version }}"
{
echo "Nightly alpha build — untagged channel, replaced every night. Agent + helper test binaries only; not fleet-upgradable (no manifest). Install the server from a versioned (v*) release or build from source."
echo ""
echo "version: $VERSION"
echo "commit: $SHA"
echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo ""
if [ -n "$PREV" ] && git cat-file -e "$PREV" 2>/dev/null; then
echo "### Since last nightly"
echo '```'
git log --oneline --no-decorate "$PREV..$SHA" | head -50
echo '```'
fi
} > notes.md
cat notes.md
- name: Publish nightly release (Gitea)
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
TOKEN="${{ secrets.GITHUB_TOKEN }}"
SHA="${{ steps.pre.outputs.sha }}"
VERSION="${{ steps.pre.outputs.version }}"
RID=$(curl -s -H "Authorization: token $TOKEN" "$API/releases/tags/nightly" \
| python3 -c "
import json,sys
try: print(json.load(sys.stdin).get('id',''))
except Exception: print('')")
[ -n "$RID" ] && curl -s -X DELETE -H "Authorization: token $TOKEN" "$API/releases/$RID"
curl -s -o /dev/null -X DELETE -H "Authorization: token $TOKEN" "$API/tags/nightly" || true
BODY=$(python3 -c "import json; print(json.dumps(open('notes.md').read()))")
RID=$(curl -sf -X POST "$API/releases" \
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
-d "{\"tag_name\":\"nightly\",\"target_commitish\":\"$SHA\",\"name\":\"nightly $VERSION\",\"prerelease\":true,\"draft\":false,\"body\":$BODY}" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
for f in dist/redflag-$VERSION-linux-amd64.tar.gz dist/redflag-$VERSION-windows-amd64.zip dist/checksums-$VERSION.txt; do
curl -sf -o /dev/null -X POST "$API/releases/$RID/assets?name=$(basename "$f")" \
-H "Authorization: token $TOKEN" -F "attachment=@$f"
done
echo "Gitea nightly published (release id=$RID)"
- name: Publish nightly release (Codeberg)
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
TOKEN="${{ secrets.CODEBERG_TOKEN }}"
if [ -z "$TOKEN" ]; then
echo "[INFO] [nightly] CODEBERG_TOKEN not set — skipping codeberg publish"
exit 0
fi
API="https://codeberg.org/api/v1/repos/Fimeg/RedFlag"
SHA="${{ steps.pre.outputs.sha }}"
VERSION="${{ steps.pre.outputs.version }}"
# Make sure codeberg has the commit before targeting a release at it.
git push "https://Fimeg:${TOKEN}@codeberg.org/Fimeg/RedFlag.git" HEAD:public
RID=$(curl -s -H "Authorization: token $TOKEN" "$API/releases/tags/nightly" \
| python3 -c "
import json,sys
try: print(json.load(sys.stdin).get('id',''))
except Exception: print('')")
[ -n "$RID" ] && curl -s -X DELETE -H "Authorization: token $TOKEN" "$API/releases/$RID"
curl -s -o /dev/null -X DELETE -H "Authorization: token $TOKEN" "$API/tags/nightly" || true
BODY=$(python3 -c "import json; print(json.dumps(open('notes.md').read()))")
RID=$(curl -sf -X POST "$API/releases" \
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
-d "{\"tag_name\":\"nightly\",\"target_commitish\":\"$SHA\",\"name\":\"nightly $VERSION\",\"prerelease\":true,\"draft\":false,\"body\":$BODY}" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
for f in dist/redflag-$VERSION-linux-amd64.tar.gz dist/redflag-$VERSION-windows-amd64.zip dist/checksums-$VERSION.txt; do
curl -sf -o /dev/null -X POST "$API/releases/$RID/assets?name=$(basename "$f")" \
-H "Authorization: token $TOKEN" -F "attachment=@$f"
done
echo "Codeberg nightly published (release id=$RID)"