Watch
1
0
Fork
You've already forked RedFlag
0

ci: nightly alpha channel + hand profile readme to profile-engine

This commit is contained in:
Fimeg 2026-06-12 19:48:54 -04:00
commit b8cdb91a21
2 changed files with 217 additions and 79 deletions

View file

@ -187,9 +187,9 @@ jobs:
fi
echo "All action refs are SHA-pinned."
# Push public to Codeberg when all checks pass — nightly mirror.
# Also updates the .profile README with latest release badges and
# recent activity. Requires CODEBERG_TOKEN secret in the repo settings.
# Push public to Codeberg when all checks pass. The .profile README is
# rendered by the profile-engine repo — single writer, do not stamp it here.
# Requires CODEBERG_TOKEN secret in the repo settings.
sync-codeberg:
runs-on: ubuntu-latest
needs: [go-vet, go-test, rust-test, cross-compile, web-build, installer-integrity, no-ai-attribution, action-pins]
@ -207,79 +207,3 @@ jobs:
git remote add codeberg-ci "https://${{ secrets.CODEBERG_TOKEN }}@codeberg.org/Fimeg/RedFlag.git"
git push codeberg-ci public:public
echo "Pushed public to codeberg.org/Fimeg/RedFlag"
- name: Update profile README
run: |
set -euo pipefail
TOKEN="${{ secrets.CODEBERG_TOKEN }}"
if [ -z "$TOKEN" ]; then
echo "[INFO] [sync] CODEBERG_TOKEN not set — skipping profile update"
exit 0
fi
# Clone the .profile repo
git clone "https://${TOKEN}@codeberg.org/Fimeg/.profile.git" /tmp/profile
cd /tmp/profile
# Fetch latest RedFlag release tag from codeberg API
RF_VER=$(curl -sf "https://codeberg.org/api/v1/repos/Fimeg/RedFlag/releases/latest" \
-H "Authorization: token ${TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tag_name','v0.2.x'))" 2>/dev/null || echo "v0.2.x")
echo "RedFlag: $RF_VER"
# Fetch latest Souveraine release tag from codeberg API
SV_VER=$(curl -sf "https://codeberg.org/api/v1/repos/Fimeg/Souveraine/releases/latest" \
-H "Authorization: token ${TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tag_name','dev'))" 2>/dev/null || echo "dev")
echo "Souveraine: $SV_VER"
# Fetch recent activity (last 6 push/create/release events)
curl -sf "https://codeberg.org/api/v1/users/Fimeg/events?limit=20" \
-H "Authorization: token ${TOKEN}" | python3 -c "
import sys, json
events = json.load(sys.stdin)
count = 0
for e in events:
if count >= 6: break
t = e.get('type','')
repo = e.get('repo',{}).get('name','')
url = 'https://codeberg.org/' + repo
if t == 'ReleaseEvent':
tag = e.get('payload',{}).get('release',{}).get('tag_name','')
print(f' - [**{repo}**]({url}) — released **{tag}**')
count += 1
elif t == 'PushEvent':
n = len(e.get('payload',{}).get('commits',[]))
print(f' - [**{repo}**]({url}) — {n} commit{"s" if n!=1 else ""}')
count += 1
elif t == 'CreateEvent':
ref = e.get('payload',{}).get('ref','')
print(f' - [**{repo}**]({url}) — created **{ref}**')
count += 1
" > /tmp/activity.md || true
# If no activity fetched, write placeholder
if [ ! -s /tmp/activity.md ]; then
echo " - _no recent activity_" > /tmp/activity.md
fi
echo "Activity:"
cat /tmp/activity.md
# Stamp badges. shields.io needs literal dashes escaped as --
TODAY=$(date -u +%Y--%m--%d)
sed -i "s|RedFlag-v[^ ]*-green|RedFlag-${RF_VER}-green|" README.md
sed -i "s|Souveraine-[^ ]*-blue|Souveraine-${SV_VER}-blue|" README.md
sed -i "s|Updated-[^ ]*-gray|Updated-${TODAY}-gray|" README.md
# Stamp activity section (replace between <!--ACTIVITY--> markers)
awk '
/<!--ACTIVITY-->/ { print; system("cat /tmp/activity.md"); inblock=1; next }
/<!--\/ACTIVITY-->/ { inblock=0 }
!inblock' README.md > README.tmp && mv README.tmp README.md
# Commit and push if changed
git config user.name "sync-bot"
git config user.email "ci@codeberg.org"
git diff --quiet README.md || {
git commit -m "sync: badges + activity for ${TODAY}"
git push origin main
echo "Profile README updated"
}

View file

@ -0,0 +1,214 @@
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,re
try:
m = re.search(r'commit: ([0-9a-f]{40})', json.load(sys.stdin).get('body',''))
print(m.group(1) if m 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@29eef336d9b2848a0b548edc03f92a220660cdb8 # 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
- name: Build binaries (linux-amd64 + windows-amd64)
if: steps.pre.outputs.go == 'true'
run: |
set -euo pipefail
VERSION="${{ steps.pre.outputs.version }}"
mkdir -p dist
build_go () { # $1=goos $2=suffix $3=ext
GOOS=$1 GOARCH=amd64 CGO_ENABLED=0 sh -c "
cd server && go build -ldflags \"-s -w \
-X github.com/Fimeg/RedFlag/server/internal/version/versions.AgentVersion=$VERSION \
-X github.com/Fimeg/RedFlag/server/internal/version/versions.ConfigVersion=$VERSION\" \
-o ../dist/redflag-server-$2$3 cmd/server/main.go"
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_go linux linux-amd64 ""
build_go 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-server-linux-amd64 redflag-agent-linux-amd64 redflag-helper-linux-amd64
zip -q redflag-$VERSION-windows-amd64.zip redflag-server-windows-amd64.exe 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. Not fleet-upgradable (no manifest)."
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)"