Skip to content

Archive website (LFS + history cleanup) #416

Archive website (LFS + history cleanup)

Archive website (LFS + history cleanup) #416

Workflow file for this run

---
name: Archive website (LFS + history cleanup)
'on':
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
workflow_dispatch: {}
permissions:
contents: write
jobs:
archive:
runs-on: ubuntu-latest
environment:
name: archive-signing
steps:
# ----------------------------
# Checkout repository (full history + LFS)
# ----------------------------
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
lfs: true
fetch-depth: 0
persist-credentials: false
# ----------------------------
# Install dependencies
# ----------------------------
- name: Install dependencies
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y clang libbsd-dev
python3 -m pip install --upgrade git-filter-repo
- name: Install signify (build from source or fall back to package)
id: signify
run: |
set -euo pipefail
SIGNIFY_REPO="https://codeberg.org/aperezdc/signify.git"
SIGNIFY_DIR="$(mktemp -d)"
trap 'rm -rf "$SIGNIFY_DIR"' EXIT
build_signify() {
make -s -C "$SIGNIFY_DIR" CC=clang BUNDLED_LIBBSD=1
sudo install -m 0755 "$SIGNIFY_DIR/signify" /usr/local/bin/signify
}
clone_signify() {
local proxy_cfg="$1"
LATEST_TAG="$(
git ${proxy_cfg} ls-remote \
--tags --sort='version:refname' \
"$SIGNIFY_REPO" 'refs/tags/v*' |
awk '{print $2}' |
sed 's#refs/tags/##; s#\^{}##' |
uniq |
tail -n1
)"
test -n "$LATEST_TAG"
git ${proxy_cfg} clone --quiet --depth 1 \
"$SIGNIFY_REPO" "$SIGNIFY_DIR"
git -C "$SIGNIFY_DIR" ${proxy_cfg} fetch --quiet --depth 1 origin \
"refs/tags/$LATEST_TAG:refs/tags/$LATEST_TAG"
git -C "$SIGNIFY_DIR" checkout --quiet "tags/$LATEST_TAG"
}
# Attempt 1: clearnet clone from Codeberg
if clone_signify ""; then
build_signify
echo "binary=/usr/local/bin/signify" >> "$GITHUB_OUTPUT"
exit 0
fi
# Attempt 2: via Tor SOCKS proxy
echo "Clearnet clone failed. Attempting via Tor..."
sudo apt-get install -y tor
sudo nohup tor --RunAsDaemon 1 &
sleep 3
PROXY="-c http.proxy=socks5h://127.0.0.1:9050"
PROXY="$PROXY -c https.proxy=socks5h://127.0.0.1:9050"
if clone_signify "$PROXY"; then
build_signify
echo "binary=/usr/local/bin/signify" >> "$GITHUB_OUTPUT"
exit 0
fi
# Attempt 3: Debian / Ubuntu package fallback
echo "Source build failed. Installing signify-openbsd package..."
sudo apt-get install -y signify-openbsd
echo "binary=/usr/bin/signify-openbsd" >> "$GITHUB_OUTPUT"
# ----------------------------
# Check if repository changed since last archive
# ----------------------------
- name: Check for repository changes
id: changes
run: |
set -euo pipefail
LAST_AUTHOR="$(git log -1 --pretty=%an)"
LAST_MESSAGE="$(git log -1 --pretty=%s)"
if [[ "$LAST_AUTHOR" == "github-actions[bot]" && \
"$LAST_MESSAGE" == Archive\ website* ]]; then
echo "No real changes since last archive. Skipping."
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "Changes detected. Proceeding with archive."
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
# ----------------------------
# Create archive, checksum, and signature
# ----------------------------
- name: Create archive, checksum, and signature
if: steps.changes.outputs.changed == 'true'
env:
SIGNIFY_KEY: ${{ secrets.SIGNIFY_KEY }}
SIGNIFY_BIN: ${{ steps.signify.outputs.binary }}
run: |
set -euo pipefail
REPO_NAME="$(basename "$GITHUB_REPOSITORY")"
WORKDIR="$GITHUB_WORKSPACE"
TMP_DIR="$WORKDIR/tmp_archive"
ARCHIVE_DIR="$WORKDIR/archive"
mkdir -p "$TMP_DIR" "$ARCHIVE_DIR"
ARCHIVE="$TMP_DIR/$REPO_NAME.tar.gz"
CHECKSUM="$TMP_DIR/$REPO_NAME.tar.gz.sha256"
SIGNATURE="$TMP_DIR/$REPO_NAME.tar.gz.sig"
KEYFILE="$TMP_DIR/$REPO_NAME.sec"
rm -f "$ARCHIVE" "$CHECKSUM" "$SIGNATURE" "$KEYFILE"
# Create tar.gz archive
# Excluded:
# - .git/ (VCS metadata)
# - .github/ (CI configuration)
# - .gitattributes (LFS rules / derived config)
# - archive/ (derived artifacts)
# - tmp_archive/ (temporary files)
tar \
--format=pax \
--exclude="./.git" \
--exclude="./.github" \
--exclude="./.gitattributes" \
--exclude="./archive" \
--exclude="./tmp_archive" \
--use-compress-program="gzip -9" \
-cf "$ARCHIVE" .
# Generate SHA256 checksum (filename only)
(
cd "$TMP_DIR"
sha256sum "$(basename "$ARCHIVE")" > "$(basename "$CHECKSUM")"
)
# Write signify private key to a temporary file
printf '%s\n' "$SIGNIFY_KEY" > "$KEYFILE"
chmod 600 "$KEYFILE"
# Sign the checksum (NOT the archive)
"$SIGNIFY_BIN" -S \
-s "$KEYFILE" \
-m "$CHECKSUM" \
-x "$SIGNATURE"
# Securely delete secret key material
shred -u "$KEYFILE"
# ----------------------------
# Track archive via Git LFS
# ----------------------------
- name: Track archive with Git LFS
if: steps.changes.outputs.changed == 'true'
run: |
set -euo pipefail
git lfs install --local
git lfs track "archive/*.tar.gz"
git add .gitattributes
# ----------------------------
# Remove old archive from history
# ----------------------------
- name: Clean old archive from history
if: steps.changes.outputs.changed == 'true'
run: |
set -euo pipefail
REPO_NAME="$(basename "$GITHUB_REPOSITORY")"
# Remove previous archive versions from history
git filter-repo \
--path "archive/$REPO_NAME.tar.gz" \
--invert-paths \
--force
# Copy new artifacts into the repository
cp "$GITHUB_WORKSPACE/tmp_archive/$REPO_NAME.tar.gz" archive/
cp "$GITHUB_WORKSPACE/tmp_archive/$REPO_NAME.tar.gz.sha256" archive/
cp "$GITHUB_WORKSPACE/tmp_archive/$REPO_NAME.tar.gz.sig" archive/
git add \
"archive/$REPO_NAME.tar.gz" \
"archive/$REPO_NAME.tar.gz.sha256" \
"archive/$REPO_NAME.tar.gz.sig"
# ----------------------------
# Commit and push changes
# ----------------------------
- name: Commit and push changes
if: steps.changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# Re-add origin remote (removed by git-filter-repo)
PROTO="https://x-access-token:"
REPO_PART="@github.com/${GITHUB_REPOSITORY}.git"
REPO_URL="${PROTO}${GH_TOKEN}${REPO_PART}"
git remote add origin "$REPO_URL"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if [ -n "$(git status --porcelain)" ]; then
git commit -m "Archive website (updated $(date -u +'%Y-%m-%d'))"
git push --force origin main
else
echo "No changes to commit."
fi