Compare commits

..

1 commit

Author SHA1 Message Date
Tom Foster
ee2557f722 feat(ci): Add Fedora RPM package build workflow
Build and publish RPM packages for Fedora using rpkg and official
rust-packaging macros. GPG sign packages with Ed25519 repository key
and deploy to Forgejo package registry.

Publishes packages to organised groups:
- continuwuity (binary): base group (stable/dev/branch-name)
- continuwuity-debuginfo: GROUP-debug
- continuwuity (source RPM): GROUP-src

Workflow triggers on pushes to relevant paths and version tags (v*).
Tagged releases use clean version numbers (v1.2.3 becomes 1.2.3-1)
while branch builds use git SHA versioning.

Include GPG public key for package verification and documentation
for RPM repository configuration and installation methods.
2025-08-31 19:49:53 +01:00
21 changed files with 104 additions and 257 deletions

View file

@ -81,7 +81,7 @@ jobs:
# Aggressive GC since cache restores don't increment counter # Aggressive GC since cache restores don't increment counter
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
- name: Install base RPM tools - name: Install build dependencies
run: | run: |
dnf install -y --setopt=keepcache=1 \ dnf install -y --setopt=keepcache=1 \
wget \ wget \
@ -91,14 +91,25 @@ jobs:
rpkg \ rpkg \
cargo-rpm-macros \ cargo-rpm-macros \
systemd-rpm-macros \ systemd-rpm-macros \
clang \
liburing-devel \
rust \
cargo \
gcc \
gcc-c++ \
make \
openssl-devel \
pkg-config \
python3-pip python3-pip
- name: Setup build environment and build SRPM - name: Setup build environment and build SRPM
run: | run: |
# Configure git for rpkg
git config --global --add safe.directory "$GITHUB_WORKSPACE" git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global user.email "ci@continuwuity.org" git config --global user.email "ci@continuwuity.org"
git config --global user.name "Continuwuity" git config --global user.name "Continuwuity"
# Setup RPM build tree
rpmdev-setuptree rpmdev-setuptree
cd "$GITHUB_WORKSPACE" cd "$GITHUB_WORKSPACE"
@ -132,8 +143,10 @@ jobs:
fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
fi fi
# Build the SRPM
rpkg srpm --outdir "$HOME/rpmbuild/SRPMS" rpkg srpm --outdir "$HOME/rpmbuild/SRPMS"
# Show SRPM info
ls -la $HOME/rpmbuild/SRPMS/ ls -la $HOME/rpmbuild/SRPMS/
- name: Setup GPG for RPM signing - name: Setup GPG for RPM signing
@ -144,32 +157,23 @@ jobs:
exit 0 exit 0
fi fi
# Import the signing key
echo "${{ secrets.RPM_SIGNING_KEY }}" | gpg --batch --import echo "${{ secrets.RPM_SIGNING_KEY }}" | gpg --batch --import
# Get the key ID (look for the sec line, not the uid line) # Get the key ID (look for the sec line, not the uid line)
KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep "^sec" | head -1 | awk '{print $2}' | cut -d'/' -f2) KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep "^sec" | head -1 | awk '{print $2}' | cut -d'/' -f2)
echo "Using GPG key: $KEY_ID" echo "Using GPG key: $KEY_ID"
# Configure RPM macros for signing
cat > ~/.rpmmacros << EOF cat > ~/.rpmmacros << EOF
%_signature gpg %_signature gpg
%_gpg_name $KEY_ID %_gpg_name $KEY_ID
%__gpg /usr/bin/gpg %__gpg /usr/bin/gpg
EOF EOF
- name: Install build dependencies from SRPM
run: |
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
if [ -z "$SRPM" ]; then
echo "Error: No SRPM file found"
exit 1
fi
echo "Installing build dependencies from: $(basename $SRPM)"
dnf builddep -y "$SRPM"
- name: Build RPM from SRPM - name: Build RPM from SRPM
run: | run: |
# Find the SRPM file
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1) SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
if [ -z "$SRPM" ]; then if [ -z "$SRPM" ]; then
@ -179,6 +183,7 @@ jobs:
echo "Building from SRPM: $SRPM" echo "Building from SRPM: $SRPM"
# Build the binary RPM
rpmbuild --rebuild "$SRPM" \ rpmbuild --rebuild "$SRPM" \
--define "_topdir $HOME/rpmbuild" \ --define "_topdir $HOME/rpmbuild" \
--define "_sourcedir $GITHUB_WORKSPACE" \ --define "_sourcedir $GITHUB_WORKSPACE" \
@ -192,20 +197,32 @@ jobs:
exit 0 exit 0
fi fi
# Track signing failures
FAILED_COUNT=0
TOTAL_COUNT=0
# Export GPG_TTY to avoid terminal warnings # Export GPG_TTY to avoid terminal warnings
export GPG_TTY=/dev/null export GPG_TTY=/dev/null
# Sign all RPMs (binary and source)
for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do
echo "Signing: $(basename $rpm)" echo "Signing: $(basename $rpm)"
TOTAL_COUNT=$((TOTAL_COUNT + 1))
# Use expect or provide empty passphrase via stdin for batch signing # Use expect or provide empty passphrase via stdin for batch signing
if ! echo "" | rpmsign --addsign "$rpm" 2>&1; then if ! echo "" | rpmsign --addsign "$rpm" 2>&1; then
echo "ERROR: Failed to sign $rpm" echo "ERROR: Failed to sign $rpm"
exit 1 FAILED_COUNT=$((FAILED_COUNT + 1))
fi fi
done done
echo "Successfully signed all RPMs" # Fail if any RPMs failed to sign
if [ "$FAILED_COUNT" -gt 0 ]; then
echo "ERROR: Failed to sign $FAILED_COUNT out of $TOTAL_COUNT RPMs"
exit 1
fi
echo "Successfully signed all $TOTAL_COUNT RPMs"
- name: Verify RPM signatures - name: Verify RPM signatures
run: | run: |
@ -215,12 +232,15 @@ jobs:
exit 0 exit 0
fi fi
# Import our public key for verification
echo "Importing GPG public key for verification..." echo "Importing GPG public key for verification..."
rpm --import fedora/RPM-GPG-KEY-continuwuity.asc rpm --import fedora/RPM-GPG-KEY-continuwuity.asc
# Track verification failures
FAILED_COUNT=0 FAILED_COUNT=0
TOTAL_COUNT=0 TOTAL_COUNT=0
# Verify all RPMs
for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do for rpm in $(find "$HOME/rpmbuild" -name "*.rpm" -type f); do
echo -n "Verifying $(basename $rpm): " echo -n "Verifying $(basename $rpm): "
TOTAL_COUNT=$((TOTAL_COUNT + 1)) TOTAL_COUNT=$((TOTAL_COUNT + 1))
@ -261,8 +281,8 @@ jobs:
echo "" echo ""
rpm -qpl "$RPM" rpm -qpl "$RPM"
# Actually install it # Actually install it (would need --nodeps if dependencies aren't met)
dnf install -y "$RPM" dnf install -y "$RPM" || rpm -ivh --nodeps "$RPM"
# Verify installation # Verify installation
rpm -qa | grep continuwuity rpm -qa | grep continuwuity
@ -285,9 +305,11 @@ jobs:
run: | run: |
mkdir -p artifacts mkdir -p artifacts
# Copy all RPMs to artifacts directory
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \; find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \; find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
# Create metadata file
cd artifacts cd artifacts
echo "Build Information:" > BUILD_INFO.txt echo "Build Information:" > BUILD_INFO.txt
echo "==================" >> BUILD_INFO.txt echo "==================" >> BUILD_INFO.txt
@ -314,6 +336,7 @@ jobs:
! -name "*.src.rpm" \ ! -name "*.src.rpm" \
-type f) -type f)
# Create temp directory for this artifact
mkdir -p upload-bin mkdir -p upload-bin
cp $BIN_RPM upload-bin/ cp $BIN_RPM upload-bin/
@ -344,6 +367,7 @@ jobs:
exit 0 exit 0
fi fi
# Extract version from RPM filename
RPM_BASENAME=$(basename "$RPM") RPM_BASENAME=$(basename "$RPM")
echo "Publishing: $RPM_BASENAME" echo "Publishing: $RPM_BASENAME"
@ -359,6 +383,7 @@ jobs:
GROUP=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30) GROUP=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
fi fi
# Extract package info from RPM for deletion
PACKAGE_INFO=$(rpm -qpi "$RPM" 2>/dev/null) PACKAGE_INFO=$(rpm -qpi "$RPM" 2>/dev/null)
PACKAGE_NAME=$(echo "$PACKAGE_INFO" | grep "^Name" | awk '{print $3}') PACKAGE_NAME=$(echo "$PACKAGE_INFO" | grep "^Name" | awk '{print $3}')
PACKAGE_VERSION=$(echo "$PACKAGE_INFO" | grep "^Version" | awk '{print $3}') PACKAGE_VERSION=$(echo "$PACKAGE_INFO" | grep "^Version" | awk '{print $3}')
@ -368,20 +393,15 @@ jobs:
# Full version includes release # Full version includes release
FULL_VERSION="${PACKAGE_VERSION}-${PACKAGE_RELEASE}" FULL_VERSION="${PACKAGE_VERSION}-${PACKAGE_RELEASE}"
# Forgejo's RPM registry cannot overwrite existing packages, so we must delete first # Try to delete existing package first (ignore errors if it doesn't exist)
# 404 is OK if package doesn't exist yet
echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH" echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH"
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ curl -X DELETE \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/package/$PACKAGE_NAME/$FULL_VERSION/$PACKAGE_ARCH") "https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/package/$PACKAGE_NAME/$FULL_VERSION/$PACKAGE_ARCH" \
HTTP_CODE=$(echo "$RESPONSE" | tail -n1) || echo "Package didn't exist or deletion failed (this is OK)"
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
echo "ERROR: Failed to delete package (HTTP $HTTP_CODE)"
echo "$RESPONSE" | head -n -1
exit 1
fi
# Upload to Forgejo package registry
# Using the RPM registry endpoint with group support
curl --fail-with-body \ curl --fail-with-body \
-X PUT \ -X PUT \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
@ -402,6 +422,7 @@ jobs:
for DEBUG_RPM in $DEBUG_RPMS; do for DEBUG_RPM in $DEBUG_RPMS; do
echo "Publishing: $(basename "$DEBUG_RPM")" echo "Publishing: $(basename "$DEBUG_RPM")"
# Extract debug RPM info
DEBUG_INFO=$(rpm -qpi "$DEBUG_RPM" 2>/dev/null) DEBUG_INFO=$(rpm -qpi "$DEBUG_RPM" 2>/dev/null)
DEBUG_NAME=$(echo "$DEBUG_INFO" | grep "^Name" | awk '{print $3}') DEBUG_NAME=$(echo "$DEBUG_INFO" | grep "^Name" | awk '{print $3}')
DEBUG_VERSION=$(echo "$DEBUG_INFO" | grep "^Version" | awk '{print $3}') DEBUG_VERSION=$(echo "$DEBUG_INFO" | grep "^Version" | awk '{print $3}')
@ -409,18 +430,13 @@ jobs:
DEBUG_ARCH=$(echo "$DEBUG_INFO" | grep "^Architecture" | awk '{print $2}') DEBUG_ARCH=$(echo "$DEBUG_INFO" | grep "^Architecture" | awk '{print $2}')
DEBUG_FULL_VERSION="${DEBUG_VERSION}-${DEBUG_RELEASE}" DEBUG_FULL_VERSION="${DEBUG_VERSION}-${DEBUG_RELEASE}"
# Must delete existing package first (Forgejo limitation) # Try to delete existing debug package first
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ curl -X DELETE \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/package/$DEBUG_NAME/$DEBUG_FULL_VERSION/$DEBUG_ARCH") "https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/package/$DEBUG_NAME/$DEBUG_FULL_VERSION/$DEBUG_ARCH" \
HTTP_CODE=$(echo "$RESPONSE" | tail -n1) || echo "Debug package didn't exist or deletion failed (this is OK)"
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
echo "ERROR: Failed to delete debug package (HTTP $HTTP_CODE)"
echo "$RESPONSE" | head -n -1
exit 1
fi
# Upload debug RPM
curl --fail-with-body \ curl --fail-with-body \
-X PUT \ -X PUT \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
@ -439,24 +455,19 @@ jobs:
echo "Publishing source RPM: $(basename "$SRPM")" echo "Publishing source RPM: $(basename "$SRPM")"
echo "Publishing to group: ${GROUP}-src" echo "Publishing to group: ${GROUP}-src"
# Extract SRPM info
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null) SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null)
SRPM_NAME=$(echo "$SRPM_INFO" | grep "^Name" | awk '{print $3}') SRPM_NAME=$(echo "$SRPM_INFO" | grep "^Name" | awk '{print $3}')
SRPM_VERSION=$(echo "$SRPM_INFO" | grep "^Version" | awk '{print $3}') SRPM_VERSION=$(echo "$SRPM_INFO" | grep "^Version" | awk '{print $3}')
SRPM_RELEASE=$(echo "$SRPM_INFO" | grep "^Release" | awk '{print $3}') SRPM_RELEASE=$(echo "$SRPM_INFO" | grep "^Release" | awk '{print $3}')
SRPM_FULL_VERSION="${SRPM_VERSION}-${SRPM_RELEASE}" SRPM_FULL_VERSION="${SRPM_VERSION}-${SRPM_RELEASE}"
# Must delete existing SRPM first (Forgejo limitation) # Try to delete existing SRPM first
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src" echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src"
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \ curl -X DELETE \
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \ -H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src") "https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src" \
HTTP_CODE=$(echo "$RESPONSE" | tail -n1) || echo "SRPM didn't exist or deletion failed (this is OK)"
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
echo "ERROR: Failed to delete SRPM (HTTP $HTTP_CODE)"
echo "$RESPONSE" | head -n -1
exit 1
fi
curl --fail-with-body \ curl --fail-with-body \
-X PUT \ -X PUT \

View file

@ -13,4 +13,3 @@ Rudi Floren <rudi.floren@gmail.com> <rudi.floren@googlemail.com>
Tamara Schmitz <tamara.zoe.schmitz@posteo.de> <15906939+tamara-schmitz@users.noreply.github.com> Tamara Schmitz <tamara.zoe.schmitz@posteo.de> <15906939+tamara-schmitz@users.noreply.github.com>
Timo Kösters <timo@koesters.xyz> Timo Kösters <timo@koesters.xyz>
x4u <xi.zhu@protonmail.ch> <14617923-x4u@users.noreply.gitlab.com> x4u <xi.zhu@protonmail.ch> <14617923-x4u@users.noreply.gitlab.com>
Ginger <ginger@gingershaped.computer> <75683114+gingershaped@users.noreply.github.com>

22
Cargo.lock generated
View file

@ -4058,7 +4058,7 @@ checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.10.1" version = "0.10.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"assign", "assign",
"js_int", "js_int",
@ -4078,7 +4078,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-appservice-api" name = "ruma-appservice-api"
version = "0.10.0" version = "0.10.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -4090,7 +4090,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.18.0" version = "0.18.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"assign", "assign",
@ -4113,7 +4113,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.13.0" version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"base64 0.22.1", "base64 0.22.1",
@ -4145,7 +4145,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events" name = "ruma-events"
version = "0.28.1" version = "0.28.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"as_variant", "as_variant",
"indexmap 2.10.0", "indexmap 2.10.0",
@ -4170,7 +4170,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"bytes", "bytes",
"headers", "headers",
@ -4192,7 +4192,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-validation" name = "ruma-identifiers-validation"
version = "0.9.5" version = "0.9.5"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"js_int", "js_int",
"thiserror 2.0.12", "thiserror 2.0.12",
@ -4201,7 +4201,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identity-service-api" name = "ruma-identity-service-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -4211,7 +4211,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-macros" name = "ruma-macros"
version = "0.13.0" version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"proc-macro-crate", "proc-macro-crate",
@ -4226,7 +4226,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-push-gateway-api" name = "ruma-push-gateway-api"
version = "0.9.0" version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -4238,7 +4238,7 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.15.0" version = "0.15.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd#8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=b753738047d1f443aca870896ef27ecaacf027da#b753738047d1f443aca870896ef27ecaacf027da"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"ed25519-dalek", "ed25519-dalek",

View file

@ -352,7 +352,7 @@ version = "0.1.2"
[workspace.dependencies.ruma] [workspace.dependencies.ruma]
git = "https://forgejo.ellis.link/continuwuation/ruwuma" git = "https://forgejo.ellis.link/continuwuation/ruwuma"
#branch = "conduwuit-changes" #branch = "conduwuit-changes"
rev = "8fb268fa2771dfc3a1c8075ef1246e7c9a0a53fd" rev = "b753738047d1f443aca870896ef27ecaacf027da"
features = [ features = [
"compat", "compat",
"rand", "rand",

View file

@ -20,7 +20,6 @@ StandardError=journal+console
Environment="CONTINUWUITY_LOG_TO_JOURNALD=true" Environment="CONTINUWUITY_LOG_TO_JOURNALD=true"
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
Environment="CONTINUWUITY_DATABASE_PATH=/var/lib/conduwuit"
TTYReset=yes TTYReset=yes
# uncomment to allow buffer to be cleared every restart # uncomment to allow buffer to be cleared every restart

View file

@ -79,11 +79,9 @@
# This is the only directory where continuwuity will save its data, # This is the only directory where continuwuity will save its data,
# including media. Note: this was previously "/var/lib/matrix-conduit". # including media. Note: this was previously "/var/lib/matrix-conduit".
# #
# YOU NEED TO EDIT THIS, UNLESS you are running continuwuity as a `systemd` service. # YOU NEED TO EDIT THIS.
# The service file sets it to `/var/lib/conduwuit` using an environment variable
# and also grants write access.
# #
# example: "/var/lib/conduwuit" # example: "/var/lib/continuwuity"
# #
#database_path = #database_path =

View file

@ -16,7 +16,6 @@ Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml"
Environment="CONTINUWUITY_LOG_TO_JOURNALD=true" Environment="CONTINUWUITY_LOG_TO_JOURNALD=true"
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
Environment="CONTINUWUITY_DATABASE_PATH=/var/lib/conduwuit"
ExecStart=/usr/sbin/conduwuit ExecStart=/usr/sbin/conduwuit

View file

@ -21,7 +21,6 @@ This document contains the help content for the `admin` command-line program.
* [`admin users list-joined-rooms`↴](#admin-users-list-joined-rooms) * [`admin users list-joined-rooms`↴](#admin-users-list-joined-rooms)
* [`admin users force-join-room`↴](#admin-users-force-join-room) * [`admin users force-join-room`↴](#admin-users-force-join-room)
* [`admin users force-leave-room`↴](#admin-users-force-leave-room) * [`admin users force-leave-room`↴](#admin-users-force-leave-room)
* [`admin users force-leave-remote-room`↴](#admin-users-force-leave-remote-room)
* [`admin users force-demote`↴](#admin-users-force-demote) * [`admin users force-demote`↴](#admin-users-force-demote)
* [`admin users make-user-admin`↴](#admin-users-make-user-admin) * [`admin users make-user-admin`↴](#admin-users-make-user-admin)
* [`admin users put-room-tag`↴](#admin-users-put-room-tag) * [`admin users put-room-tag`↴](#admin-users-put-room-tag)
@ -296,7 +295,6 @@ You can find the ID using the `list-appservices` command.
* `list-joined-rooms` — - Lists all the rooms (local and remote) that the specified user is joined in * `list-joined-rooms` — - Lists all the rooms (local and remote) that the specified user is joined in
* `force-join-room` — - Manually join a local user to a room * `force-join-room` — - Manually join a local user to a room
* `force-leave-room` — - Manually leave a local user from a room * `force-leave-room` — - Manually leave a local user from a room
* `force-leave-remote-room` — - Manually leave a remote room for a local user
* `force-demote` — - Forces the specified user to drop their power levels to the room default, if their permissions allow and the auth check permits * `force-demote` — - Forces the specified user to drop their power levels to the room default, if their permissions allow and the auth check permits
* `make-user-admin` — - Grant server-admin privileges to a user * `make-user-admin` — - Grant server-admin privileges to a user
* `put-room-tag` — - Puts a room tag for the specified user and room ID * `put-room-tag` — - Puts a room tag for the specified user and room ID
@ -451,19 +449,6 @@ Reverses the effects of the `suspend` command, allowing the user to send message
## `admin users force-leave-remote-room`
- Manually leave a remote room for a local user
**Usage:** `admin users force-leave-remote-room <USER_ID> <ROOM_ID>`
###### **Arguments:**
* `<USER_ID>`
* `<ROOM_ID>`
## `admin users force-demote` ## `admin users force-demote`
- Forces the specified user to drop their power levels to the room default, if their permissions allow and the auth check permits - Forces the specified user to drop their power levels to the room default, if their permissions allow and the auth check permits

View file

@ -15,7 +15,6 @@ Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml"
Environment="CONTINUWUITY_LOG_TO_JOURNALD=true" Environment="CONTINUWUITY_LOG_TO_JOURNALD=true"
Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N"
Environment="CONTINUWUITY_DATABASE_PATH=/var/lib/conduwuit"
ExecStart=/usr/bin/conduwuit ExecStart=/usr/bin/conduwuit

View file

@ -1,8 +1,8 @@
use std::{collections::BTreeMap, fmt::Write as _}; use std::{collections::BTreeMap, fmt::Write as _};
use api::client::{ use api::client::{
full_user_deactivate, join_room_by_id_helper, leave_all_rooms, leave_room, remote_leave_room, full_user_deactivate, join_room_by_id_helper, leave_all_rooms, leave_room, update_avatar_url,
update_avatar_url, update_displayname, update_displayname,
}; };
use conduwuit::{ use conduwuit::{
Err, Result, debug, debug_warn, error, info, is_equal_to, Err, Result, debug, debug_warn, error, info, is_equal_to,
@ -926,29 +926,3 @@ pub(super) async fn redact_event(&self, event_id: OwnedEventId) -> Result {
)) ))
.await .await
} }
#[admin_command]
pub(super) async fn force_leave_remote_room(
&self,
user_id: String,
room_id: OwnedRoomOrAliasId,
) -> Result {
let user_id = parse_local_user_id(self.services, &user_id)?;
let (room_id, _) = self
.services
.rooms
.alias
.resolve_with_servers(&room_id, None)
.await?;
assert!(
self.services.globals.user_is_local(&user_id),
"Parsed user_id must be a local user"
);
remote_leave_room(self.services, &user_id, &room_id, None)
.boxed()
.await?;
self.write_str(&format!("{user_id} has been joined to {room_id}.",))
.await
}

View file

@ -103,12 +103,6 @@ pub enum UserCommand {
room_id: OwnedRoomOrAliasId, room_id: OwnedRoomOrAliasId,
}, },
/// - Manually leave a remote room for a local user.
ForceLeaveRemoteRoom {
user_id: String,
room_id: OwnedRoomOrAliasId,
},
/// - Forces the specified user to drop their power levels to the room /// - Forces the specified user to drop their power levels to the room
/// default, if their permissions allow and the auth check permits /// default, if their permissions allow and the auth check permits
ForceDemote { ForceDemote {

View file

@ -1,3 +0,0 @@
mod suspend;
pub(crate) use self::suspend::*;

View file

@ -1,89 +0,0 @@
use axum::extract::State;
use conduwuit::{Err, Result};
use futures::future::{join, join3};
use ruma::api::client::admin::{get_suspended, set_suspended};
use crate::Ruma;
/// # `GET /_matrix/client/v1/admin/suspend/{userId}`
///
/// Check the suspension status of a target user
pub(crate) async fn get_suspended_status(
State(services): State<crate::State>,
body: Ruma<get_suspended::v1::Request>,
) -> Result<get_suspended::v1::Response> {
let sender_user = body.sender_user();
let (admin, active) =
join(services.users.is_admin(sender_user), services.users.is_active(&body.user_id)).await;
if !admin {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
if !services.globals.user_is_local(&body.user_id) {
return Err!(Request(InvalidParam("Can only check the suspended status of local users")));
}
if !active {
return Err!(Request(NotFound("Unknown user")));
}
Ok(get_suspended::v1::Response::new(
services.users.is_suspended(&body.user_id).await?,
))
}
/// # `PUT /_matrix/client/v1/admin/suspend/{userId}`
///
/// Set the suspension status of a target user
pub(crate) async fn put_suspended_status(
State(services): State<crate::State>,
body: Ruma<set_suspended::v1::Request>,
) -> Result<set_suspended::v1::Response> {
let sender_user = body.sender_user();
let (sender_admin, active, target_admin) = join3(
services.users.is_admin(sender_user),
services.users.is_active(&body.user_id),
services.users.is_admin(&body.user_id),
)
.await;
if !sender_admin {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
if !services.globals.user_is_local(&body.user_id) {
return Err!(Request(InvalidParam("Can only set the suspended status of local users")));
}
if !active {
return Err!(Request(NotFound("Unknown user")));
}
if body.user_id == *sender_user {
return Err!(Request(Forbidden("You cannot suspend yourself")));
}
if target_admin {
return Err!(Request(Forbidden("You cannot suspend another server administrator")));
}
if services.users.is_suspended(&body.user_id).await? == body.suspended {
// No change
return Ok(set_suspended::v1::Response::new(body.suspended));
}
let action = if body.suspended {
services
.users
.suspend_account(&body.user_id, sender_user)
.await;
"suspended"
} else {
services.users.unsuspend_account(&body.user_id).await;
"unsuspended"
};
if services.config.admin_room_notices {
// Notify the admin room that an account has been un/suspended
services
.admin
.send_text(&format!("{} has been {} by {}.", body.user_id, action, sender_user))
.await;
}
Ok(set_suspended::v1::Response::new(body.suspended))
}

View file

@ -19,7 +19,7 @@ use crate::Ruma;
/// of this server. /// of this server.
pub(crate) async fn get_capabilities_route( pub(crate) async fn get_capabilities_route(
State(services): State<crate::State>, State(services): State<crate::State>,
body: Ruma<get_capabilities::v3::Request>, _body: Ruma<get_capabilities::v3::Request>,
) -> Result<get_capabilities::v3::Response> { ) -> Result<get_capabilities::v3::Response> {
let available: BTreeMap<RoomVersionId, RoomVersionStability> = let available: BTreeMap<RoomVersionId, RoomVersionStability> =
Server::available_room_versions().collect(); Server::available_room_versions().collect();
@ -45,14 +45,5 @@ pub(crate) async fn get_capabilities_route(
json!({"enabled": services.config.forget_forced_upon_leave}), json!({"enabled": services.config.forget_forced_upon_leave}),
)?; )?;
if services
.users
.is_admin(body.sender_user.as_ref().unwrap())
.await
{
// Advertise suspension API
capabilities.set("uk.timedout.msc4323", json!({"suspend":true, "lock": false}))?;
}
Ok(get_capabilities::v3::Response { capabilities }) Ok(get_capabilities::v3::Response { capabilities })
} }

View file

@ -156,8 +156,6 @@ pub(crate) async fn join_room_by_id_or_alias_route(
.await?; .await?;
let mut servers = body.via.clone(); let mut servers = body.via.clone();
if servers.is_empty() {
debug!("No via servers provided for join, injecting some.");
servers.extend( servers.extend(
services services
.rooms .rooms
@ -184,7 +182,6 @@ pub(crate) async fn join_room_by_id_or_alias_route(
if let Some(server) = room_id.server_name() { if let Some(server) = room_id.server_name() {
servers.push(server.to_owned()); servers.push(server.to_owned());
} }
}
servers.sort_unstable(); servers.sort_unstable();
servers.dedup(); servers.dedup();

View file

@ -215,7 +215,7 @@ pub async fn leave_room(
Ok(()) Ok(())
} }
pub async fn remote_leave_room( async fn remote_leave_room(
services: &Services, services: &Services,
user_id: &UserId, user_id: &UserId,
room_id: &RoomId, room_id: &RoomId,

View file

@ -29,7 +29,7 @@ pub(crate) use self::{
}; };
pub use self::{ pub use self::{
join::join_room_by_id_helper, join::join_room_by_id_helper,
leave::{leave_all_rooms, leave_room, remote_leave_room}, leave::{leave_all_rooms, leave_room},
}; };
use crate::{Ruma, client::full_user_deactivate}; use crate::{Ruma, client::full_user_deactivate};

View file

@ -1,6 +1,5 @@
pub(super) mod account; pub(super) mod account;
pub(super) mod account_data; pub(super) mod account_data;
pub(super) mod admin;
pub(super) mod alias; pub(super) mod alias;
pub(super) mod appservice; pub(super) mod appservice;
pub(super) mod backup; pub(super) mod backup;
@ -44,7 +43,6 @@ pub(super) mod well_known;
pub use account::full_user_deactivate; pub use account::full_user_deactivate;
pub(super) use account::*; pub(super) use account::*;
pub(super) use account_data::*; pub(super) use account_data::*;
pub(super) use admin::*;
pub(super) use alias::*; pub(super) use alias::*;
pub(super) use appservice::*; pub(super) use appservice::*;
pub(super) use backup::*; pub(super) use backup::*;
@ -57,7 +55,7 @@ pub(super) use keys::*;
pub(super) use media::*; pub(super) use media::*;
pub(super) use media_legacy::*; pub(super) use media_legacy::*;
pub(super) use membership::*; pub(super) use membership::*;
pub use membership::{join_room_by_id_helper, leave_all_rooms, leave_room, remote_leave_room}; pub use membership::{join_room_by_id_helper, leave_all_rooms, leave_room};
pub(super) use message::*; pub(super) use message::*;
pub(super) use openid::*; pub(super) use openid::*;
pub(super) use presence::*; pub(super) use presence::*;

View file

@ -58,7 +58,6 @@ pub(crate) async fn get_supported_versions_route(
("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */ ("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */
("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */ ("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */
("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */ ("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */
("uk.timedout.msc4323".to_owned(), true), /* agnostic suspend (https://github.com/matrix-org/matrix-spec-proposals/pull/4323) */
]), ]),
}; };

View file

@ -184,8 +184,6 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
"/_matrix/client/unstable/im.nheko.summary/rooms/:room_id_or_alias/summary", "/_matrix/client/unstable/im.nheko.summary/rooms/:room_id_or_alias/summary",
get(client::get_room_summary_legacy) get(client::get_room_summary_legacy)
) )
.ruma_route(&client::get_suspended_status)
.ruma_route(&client::put_suspended_status)
.ruma_route(&client::well_known_support) .ruma_route(&client::well_known_support)
.ruma_route(&client::well_known_client) .ruma_route(&client::well_known_client)
.route("/_conduwuit/server_version", get(client::conduwuit_server_version)) .route("/_conduwuit/server_version", get(client::conduwuit_server_version))

View file

@ -126,11 +126,9 @@ pub struct Config {
/// This is the only directory where continuwuity will save its data, /// This is the only directory where continuwuity will save its data,
/// including media. Note: this was previously "/var/lib/matrix-conduit". /// including media. Note: this was previously "/var/lib/matrix-conduit".
/// ///
/// YOU NEED TO EDIT THIS, UNLESS you are running continuwuity as a `systemd` service. /// YOU NEED TO EDIT THIS.
/// The service file sets it to `/var/lib/conduwuit` using an environment variable
/// and also grants write access.
/// ///
/// example: "/var/lib/conduwuit" /// example: "/var/lib/continuwuity"
pub database_path: PathBuf, pub database_path: PathBuf,
/// continuwuity supports online database backups using RocksDB's Backup /// continuwuity supports online database backups using RocksDB's Backup