RPM Plugin

The RPM plugin provides support for DNF/YUM-based repositories (RHEL, CentOS, Fedora, Rocky Linux, AlmaLinux).

Overview

Status: ✅ Available

The RPM plugin consists of:

  • RpmSyncPlugin - Syncs packages from upstream RPM repositories

  • RpmPublisher - Publishes RPM repositories with metadata

Features

Repository Modes:

  • Mirror Mode - Full metadata mirroring (all repomd.xml types)

  • Filtered Mode - Smart metadata regeneration for filtered repos

  • Hosted Mode - Upload-only repositories for self-hosted packages (chantal package upload)

Package Management:

  • ✅ Repomd.xml/primary.xml.gz parsing

  • ✅ RPM package downloading

  • ✅ SHA256 checksum verification

  • ✅ Architecture filtering

  • ✅ Pattern-based package filtering

  • ✅ Source RPM exclusion

  • ✅ Version filtering (only latest)

Metadata Support:

  • ✅ Full metadata mirroring (updateinfo, filelists, other, comps, modules, etc.)

  • ✅ Updateinfo/errata parsing and filtering

  • ✅ Metadata regeneration for filtered repositories

  • Compression: Gzip, Zstandard (.zst), XZ, BZ2 (read & write)

  • ✅ Configurable compression for generated metadata

  • ✅ Magic byte detection for auto-format detection

  • ✅ GPG signing of regenerated metadata (repomd.xml.asc) in filtered mode

  • ✅ RHEL CDN support (client certificates)

Quality Assurance:

  • ✅ 39 comprehensive tests for compression support

  • ✅ Roundtrip tests (compress + decompress)

  • ✅ Compatibility tests with stdlib and zstandard library

  • ✅ Compression level tests

  • ✅ Large data handling tests

Not supported:

  • ❌ Delta RPMs (drpm / prestodelta) — see Limitations

Note: RPM packages are served unmodified and keep their upstream signatures (verified client-side with gpgcheck=1). Chantal signs only the repository metadata (repomd.xml.asc) in filtered mode and does not re-sign packages.

Configuration

Basic RPM Repository

repositories:
  - id: epel9-latest
    name: EPEL 9 - Latest
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true

With Filters

repositories:
  - id: epel9-webservers
    name: EPEL 9 - Web Servers
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true
    filters:
      patterns:
        include: ["^nginx-.*", "^httpd-.*"]
        exclude: [".*-debug.*"]
      metadata:
        architectures:
          include: ["x86_64", "noarch"]
      rpm:
        exclude_source_rpms: true
      post_processing:
        only_latest_version: true

With Custom Compression

Configure metadata compression format (useful for openSUSE Tumbleweed which uses .zst):

repositories:
  - id: opensuse-tumbleweed
    name: openSUSE Tumbleweed
    type: rpm
    feed: https://download.opensuse.org/tumbleweed/repo/oss/
    enabled: true
    metadata:
      compression: auto  # auto | gzip | zstandard | bzip2 | none

Compression Options:

  • auto (default): Use same compression as upstream repository

  • gzip: Always use gzip for regenerated metadata (.gz files)

  • zstandard: Always use Zstandard (.zst files) - Required for openSUSE Tumbleweed

  • bzip2: Always use bzip2 (.bz2 files)

  • none: No compression (not recommended)

Note: This setting only affects metadata generated by Chantal (primary.xml in all modes, updateinfo/filelists/other in filtered mode). In mirror mode, original upstream metadata files are hardlinked unchanged.

RHEL with Client Certificates

repositories:
  - id: rhel9-baseos
    name: RHEL 9 BaseOS
    type: rpm
    feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
    enabled: true
    ssl:
      ca_bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
      client_cert: /etc/pki/entitlement/1234567890.pem
      client_key: /etc/pki/entitlement/1234567890-key.pem
      verify: true

Repository Modes

Chantal supports three repository operation modes for RPM repositories. The default mode is filtered; set mode: mirror explicitly for a full unmodified mirror.

Mirror Mode

Full metadata mirroring - Downloads and publishes ALL metadata types from upstream repository unchanged.

repositories:
  - id: rhel9-baseos-mirror
    name: RHEL 9 BaseOS (Full Mirror)
    type: rpm
    feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
    enabled: true
    mode: mirror  # must be set explicitly; default is 'filtered'

Behavior:

  • ✅ All package files mirrored; primary/filelists/other/updateinfo/comps/modules published

  • ⚠️ primary.xml and repomd.xml are regenerated (package <location>s are rewritten to the republished Packages/ layout), so the published repo is not byte-for-byte identical to upstream

  • ⚠️ zchunk (*_zck) and sqlite (*_db) metadata variants are dropped — see Limitations; clients fall back to primary.xml.gz

  • ✅ Ideal for: complete repository mirrors, compliance requirements

Metadata types mirrored:

  • primary - Package metadata (name, version, arch, dependencies)

  • filelists - File listings for each package

  • other - Changelog data

  • updateinfo - Errata/security advisories

  • comps - Package groups and categories

  • modules - Modular metadata (RHEL 8+)

  • And any other metadata types present in repomd.xml

Filtered Mode

Smart filtering with metadata regeneration - Filters packages and regenerates metadata to match.

repositories:
  - id: epel9-webservers
    name: EPEL 9 - Web Servers Only
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    enabled: true
    mode: filtered
    filters:
      patterns:
        include: ["^nginx-.*", "^httpd-.*", "^php-.*"]
      post_processing:
        only_latest_version: true

Behavior:

  • ✅ Packages filtered based on patterns/filters

  • ✅ Metadata regenerated to match available packages

  • ✅ Updateinfo filtered to include only relevant errata

  • ✅ Filelists, other metadata filtered accordingly

  • ✅ Ideal for: Custom repositories, filtered mirrors, disk space optimization

Metadata regeneration:

  • primary.xml - Regenerated with filtered package list

  • filelists.xml - Regenerated with filtered packages

  • other.xml - Regenerated with filtered packages

  • updateinfo.xml - Filtered to include only errata for available packages

  • comps.xml - Copied unchanged (groups still valid)

  • modules.yaml - Copied unchanged (if present)

GPG Signing (Filtered Mode)

Status: ✅ Available

In filtered mode the regenerated repomd.xml no longer matches the upstream repomd.xml.asc. Configure a gpg section to have Chantal sign the regenerated repomd.xml with its own key, so clients can enable repo_gpgcheck=1.

When signing is enabled, publishing produces:

  • repodata/repomd.xml.asc - detached signature of repomd.xml

  • <repo-root>/key.gpg - the exported public key (filename via public_key_name)

Metadata vs. package signatures are independent. Chantal signs only the repository metadata. The mirrored .rpm packages keep their upstream signatures and are still verified with gpgcheck=1. It is fully supported for the metadata to be signed by a different key than the packages — DNF/YUM accept multiple keys in gpgkey=. Chantal never re-signs packages (that would change their checksums and break content-addressed storage).

The gpg section uses the same options as the APT plugin (per-repository or a global fallback). See APT Plugin → GPG Signing for the full option reference (key_id, key_file, generate_key, passphrase_file, gnupg_home, public_key_name, …).

repositories:
  - id: epel9-webservers
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/
    mode: filtered
    filters:
      patterns:
        include: ["^nginx-.*"]
    gpg:
      key_id: "ABCD1234EF567890"
      gnupg_home: /etc/chantal/gnupg
      passphrase_file: /etc/chantal/keys/passphrase.txt
      public_key_name: RPM-GPG-KEY-chantal   # published at the repo root

Client configuration (/etc/yum.repos.d/chantal.repo):

[chantal-epel9-webservers]
name=Chantal EPEL9 Web Servers (filtered)
baseurl=http://mirror.example.com/repos/epel9-webservers
enabled=1
repo_gpgcheck=1          # verify repomd.xml against our metadata key
gpgcheck=1               # verify packages against the upstream key
gpgkey=http://mirror.example.com/repos/epel9-webservers/RPM-GPG-KEY-chantal
       https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-9

Both public keys are listed in gpgkey=: DNF imports both and uses the Chantal key for the metadata check and the EPEL key for package checks.

Updateinfo Filtering Example:

Upstream has 1000 security advisories, but you only mirror nginx packages:

  • Mirror mode: All 1000 advisories published (irrelevant for your packages)

  • Filtered mode: Only nginx-related advisories published (smart filtering)

# Filtered updateinfo only includes errata matching your packages
# RHSA-2024:1234 for nginx-1.20.1-1.el9 → INCLUDED
# RHSA-2024:5678 for kernel-5.14.0-362.el9 → EXCLUDED (kernel not mirrored)

Hosted Mode

Self-hosted packages - an upload-only repository with no upstream feed. Custom-built RPMs are added with chantal package upload; there is nothing to sync, so chantal sync skips hosted repositories.

repositories:
  - id: custom-rpms
    name: Custom Internal RPMs
    type: rpm
    mode: hosted
    enabled: true
    # note: no 'feed' - hosted repos hold only uploaded packages

Upload one or more local RPMs and publish:

# A single file
chantal package upload --repo-id custom-rpms --file ./nginx-1.20.1-1.el9.x86_64.rpm

# A whole directory (optionally recursive)
chantal package upload --repo-id custom-rpms --directory ./rpms/ --recursive

# Replace an existing package with the same NEVRA but different content
chantal package upload --repo-id custom-rpms --file ./nginx-1.20.1-1.el9.x86_64.rpm --force

# Regenerate repodata so clients can install
chantal publish repo --repo-id custom-rpms --target /srv/repos/custom-rpms

Package metadata (NEVRA, summary, …) is parsed from the RPM header in pure Python - no rpm binary is required. Uploads are content-addressed and deduplicated by SHA-256; re-uploading identical bytes just links the existing pool entry. Uploading a different build of an NEVRA already in the repo requires --force.

Status: ✅ Available (RPM).

Upstream Signature Verification

Status: ✅ Available (repository metadata and package signatures)

Chantal always verifies integrity (SHA256 of every metadata file and package against repomd.xml/primary.xml). A verify section additionally checks authenticity — that the upstream was signed by a key you trust — analogous to dnf’s repo_gpgcheck.

When enabled, the upstream repodata/repomd.xml.asc is fetched and verified against the configured trusted key(s). Because repomd.xml contains the checksums of every other metadata file, a valid signature there transitively authenticates the whole repository.

repositories:
  - id: rocky9-baseos
    type: rpm
    feed: https://download.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os
    verify:
      enabled: true
      repo_gpgcheck: true            # verify repomd.xml.asc
      key_files:
        - /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
      # keys: ["-----BEGIN PGP PUBLIC KEY BLOCK----- ..."]   # inline alternative
      # trusted_fingerprints: ["<fpr>"]                       # optional pinning
      on_missing_signature: fail     # fail | warn | skip
      on_invalid_signature: fail

The verify section can also be set globally (as a fallback for all repositories without their own). Options:

Option

Meaning

enabled

Turn verification on (default false)

repo_gpgcheck

Verify the repository metadata signature (repomd.xml.asc)

gpgcheck

Verify individual .rpm package signatures (header-only OpenPGP signature; default true; requires repo_gpgcheck so the authenticated metadata checksums bind the payload)

key_files / keys

Trusted public keys (file paths / inline ASCII-armored)

trusted_fingerprints

Optional allow-list of key fingerprints (pinning)

on_missing_signature / on_invalid_signature

fail (default), warn, or skip

client_key_name

Filename of the trusted upstream key written into the published repo root (default RPM-GPG-KEY-{repo_id}; {repo_id} is substituted; empty disables)

At least one of key_files or keys is required when enabled: true.

Distributing the upstream key to clients

The mirrored .rpm files keep their upstream signatures, so a downstream client that enables gpgcheck=1 needs the upstream vendor’s public key. When verify is enabled, chantal publishes the configured trust anchor(s) into the repository root as RPM-GPG-KEY-<repo-id> (in both mirror and filtered mode). Clients reference it via gpgkey=:

[rocky9-baseos]
baseurl = http://mirror.example.com/repos/rocky9-baseos/
gpgcheck = 1
gpgkey = http://mirror.example.com/repos/rocky9-baseos/RPM-GPG-KEY-rocky9-baseos

Set client_key_name: "" to disable publishing (e.g. if you distribute the key out-of-band). Multiple trusted keys are concatenated into the one file.

Trust note: the published key travels over the same channel as the repo it secures, so a man-in-the-middle on that channel could swap both. Serve the mirror over HTTPS and/or import the key once out-of-band (e.g. via a *-release RPM) for real authenticity rather than mere corruption-resistance.

How It Works

Sync Process

1. Fetch repomd.xml

GET https://example.com/repo/repodata/repomd.xml

Parse repomd.xml to discover all metadata types:

  • primary - Package metadata (required)

  • filelists - File listings

  • other - Changelog data

  • updateinfo - Errata/advisories

  • comps - Package groups

  • modules - Modular metadata

  • … and any other types

2. Download Metadata

Mirror Mode:

  • Downloads ALL metadata types from repomd.xml

  • Stores in pool: /var/lib/chantal/pool/files/

  • Metadata tracked in RepositoryFile model

Filtered Mode:

  • Downloads primary.xml (required for package discovery)

  • Downloads updateinfo.xml (for errata filtering)

  • Other metadata downloaded as needed

3. Parse Packages

Fetch and parse primary.xml.gz:

GET https://example.com/repo/repodata/abc123-primary.xml.gz

Extract package list with metadata:

  • Name, version, release, epoch, architecture

  • Dependencies, provides, requires

  • SHA256 checksum

  • File location

4. Apply Filters (Filtered Mode Only)

  • Pattern matching (include/exclude regex)

  • Architecture filtering

  • Size/build time filtering

  • RPM-specific filters (exclude source RPMs, etc.)

  • Post-processing (only latest version)

Mirror Mode: No filtering applied.

5. Download Packages

For each package:
  - Calculate expected SHA256
  - Check if exists in pool
  - If not, download to pool
  - Verify checksum

Pool structure:

/var/lib/chantal/pool/content/{sha256[0:2]}/{sha256[2:4]}/{sha256}.rpm

6. Update Database

  • Add packages to database (ContentItem model)

  • Add metadata files to database (RepositoryFile model)

  • Associate with repository

  • Record sync history

Publish Process

1. Query Packages

packages = repository.content_items
metadata_files = repository.repository_files  # Mirror mode only

2. Create Directory Structure

/var/www/repos/repo-id/latest/
├── Packages/
└── repodata/

4. Publish Metadata

Mirror Mode:

  • Hardlink metadata files from pool to repodata/ (zchunk/sqlite variants dropped)

  • Regenerate primary.xml and repomd.xml (locations rewritten, repomd re-signed when a GPG key is configured)

Filtered Mode:

  • Generate primary.xml with filtered package list

  • Generate filelists.xml with filtered packages

  • Generate other.xml with filtered packages

  • Filter updateinfo.xml to include only relevant errata

  • Copy comps.xml unchanged (if present)

  • Generate new repomd.xml with checksums

5. Updateinfo Filtering (Filtered Mode)

Parse upstream updateinfo.xml:

<updates>
  <update type="security" id="RHSA-2024:1234">
    <title>nginx security update</title>
    <pkglist>
      <package name="nginx" version="1.20.1" release="1.el9" arch="x86_64"/>
    </pkglist>
  </update>
  <update type="security" id="RHSA-2024:5678">
    <title>kernel security update</title>
    <pkglist>
      <package name="kernel" version="5.14.0" release="362.el9" arch="x86_64"/>
    </pkglist>
  </update>
</updates>

Filter logic:

  • Extract package NVRAs from each advisory

  • Check if ANY package in advisory is in your filtered repository

  • If yes: Include advisory in filtered updateinfo.xml

  • If no: Exclude advisory

Result:

<updates>
  <update type="security" id="RHSA-2024:1234">
    <!-- nginx advisory INCLUDED (nginx is in filtered repo) -->
  </update>
  <!-- kernel advisory EXCLUDED (kernel not in filtered repo) -->
</updates>

6. Result

Mirror Mode:

/var/www/repos/rhel9-baseos-mirror/latest/
├── Packages/
│   ├── nginx-1.20.2-1.el9.x86_64.rpm
│   ├── kernel-5.14.0-362.el9.x86_64.rpm
│   └── ... (all packages)
└── repodata/
    ├── repomd.xml
    ├── abc123-primary.xml.gz
    ├── def456-filelists.xml.gz
    ├── ghi789-other.xml.gz
    ├── jkl012-updateinfo.xml.gz
    ├── mno345-comps.xml.gz
    └── ... (all metadata types)

Filtered Mode:

/var/www/repos/epel9-webservers/latest/
├── Packages/
│   ├── nginx-1.20.2-1.el9.x86_64.rpm
│   └── httpd-2.4.51-1.el9.x86_64.rpm
├── repodata/
│   ├── repomd.xml (regenerated)
│   ├── repomd.xml.asc (GPG signature, if gpg configured)
│   ├── abc123-primary.xml.gz (regenerated)
│   ├── def456-filelists.xml.gz (regenerated)
│   ├── ghi789-other.xml.gz (regenerated)
│   └── jkl012-updateinfo.xml.gz (filtered)
└── RPM-GPG-KEY-chantal (public key, if gpg configured)

Metadata Files

repomd.xml

Root metadata file:

<?xml version="1.0"?>
<repomd xmlns="http://linux.duke.edu/metadata/repo">
  <revision>1641816000</revision>
  <data type="primary">
    <checksum type="sha256">abc123...</checksum>
    <location href="repodata/abc123-primary.xml.gz"/>
    <timestamp>1641816000</timestamp>
    <size>12345</size>
    <open-checksum type="sha256">def456...</open-checksum>
    <open-size>67890</open-size>
  </data>
</repomd>

primary.xml.gz

Package list (gzip-compressed):

<?xml version="1.0"?>
<metadata packages="2">
  <package type="rpm">
    <name>nginx</name>
    <arch>x86_64</arch>
    <version epoch="0" ver="1.20.2" rel="1.el9"/>
    <checksum type="sha256" pkgid="YES">f256abc...</checksum>
    <summary>High performance web server</summary>
    <description>...</description>
    <packager>...</packager>
    <url>...</url>
    <time file="1641816000" build="1641815000"/>
    <size package="1234567" installed="4567890" archive="1234000"/>
    <location href="Packages/nginx-1.20.2-1.el9.x86_64.rpm"/>
    <format>
      <rpm:license>BSD</rpm:license>
      <rpm:vendor>EPEL</rpm:vendor>
      <rpm:group>System Environment/Daemons</rpm:group>
      <rpm:buildhost>buildvm.example.com</rpm:buildhost>
      <rpm:sourcerpm>nginx-1.20.2-1.el9.src.rpm</rpm:sourcerpm>
      <rpm:provides>...</rpm:provides>
      <rpm:requires>...</rpm:requires>
    </format>
  </package>
</metadata>

Compression Support

Chantal supports all compression formats used by RPM repositories with full read and write capabilities.

Supported Formats

Format

Extension

Read

Write

Magic Bytes

Use Case

Gzip

.gz

1f 8b

Most common (RHEL, CentOS, Fedora)

Zstandard

.zst

28 b5 2f fd

Modern (openSUSE Tumbleweed)

XZ

.xz

fd 37 7a 58 5a 00

High compression (some repos)

Bzip2

.bz2

42 5a 68

Legacy (older repos)

None

-

-

Testing/debugging

Auto-Detection

Chantal automatically detects compression format using two methods:

  1. Extension-based (primary): Checks file extension (.gz, .zst, .xz, .bz2)

  2. Magic byte detection (fallback): Reads first bytes of file to identify format

This ensures compatibility even with misnamed files or when extension is unknown.

Configuration

Control compression format for generated metadata:

repositories:
  - id: my-repo
    type: rpm
    feed: https://example.com/repo/
    metadata:
      compression: auto  # Default - detects from upstream

Options:

  • auto: Detect from upstream repository (default, recommended)

  • gzip: Force gzip compression (universal compatibility)

  • zstandard: Force Zstandard (best compression ratio, modern)

  • bzip2: Force bzip2 (legacy compatibility)

  • none: No compression (not recommended, large files)

Compression Behavior

Mirror Mode:

  • Original metadata files hardlinked from pool (unchanged)

  • No recompression occurs

  • Preserves upstream compression format

Filtered Mode:

  • Metadata regenerated based on filtered packages

  • Uses configured compression format

  • auto mode mirrors upstream compression

  • Primary.xml always regenerated

  • Updateinfo, filelists, other regenerated if filtered

Performance Characteristics

Compression speeds (relative to gzip=100%):

Format

Compression Speed

Decompression Speed

Ratio

Best For

None

-

-

1.0×

Testing only

Gzip (level 6)

100%

100%

~3-5×

Universal compatibility

Zstandard (level 3)

200%

150%

~3-6×

Modern repos (recommended)

Bzip2 (level 9)

30%

80%

~4-6×

Legacy repos only

XZ (level 6)

15%

90%

~5-8×

Slow compression, use sparingly

Note: Zstandard offers the best balance of speed and compression ratio for modern repositories.

Testing

Compression support is thoroughly tested with 39 unit tests:

  • Roundtrip tests: Compress → decompress → verify

  • Compatibility tests: Interop with stdlib and native libraries

  • Compression levels: Test levels 1-22 for zstandard

  • Large data: Test with 1000+ package metadata

  • Magic byte detection: Verify all formats detected correctly

  • Error handling: Invalid formats raise appropriate errors

Run tests:

PYTHONPATH=src python3.12 -m pytest tests/test_rpm_compression.py tests/test_rpm_parsers_zstd.py -v

Examples

openSUSE Tumbleweed (Zstandard):

repositories:
  - id: opensuse-tumbleweed
    name: openSUSE Tumbleweed OSS
    type: rpm
    feed: https://download.opensuse.org/tumbleweed/repo/oss/
    metadata:
      compression: auto  # Detects .zst from upstream

Force Gzip for consistency:

repositories:
  - id: mixed-sources
    name: Multiple Upstream Sources
    type: rpm
    feed: https://example.com/repo/
    metadata:
      compression: gzip  # Force gzip regardless of upstream

RPM-Specific Filters

Exclude Source RPMs

filters:
  rpm:
    exclude_source_rpms: true

Excludes packages ending with .src.rpm.

Group Filtering

filters:
  rpm:
    groups:
      include:
        - "System Environment/Base"
        - "Applications/Internet"

Filter by RPM group metadata.

License Filtering

filters:
  rpm:
    licenses:
      include: ["GPL", "MIT", "Apache"]

Filter by package license.

Supported Distributions

Red Hat Enterprise Linux (RHEL)

  • RHEL 8, 9

  • Requires subscription and client certificates

Example:

repositories:
  - id: rhel9-baseos
    type: rpm
    feed: https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os
    ssl:
      client_cert: /etc/pki/entitlement/xxx.pem
      client_key: /etc/pki/entitlement/xxx-key.pem

CentOS Stream

  • CentOS Stream 8, 9

Example:

repositories:
  - id: centos-stream-9-baseos
    type: rpm
    feed: https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/

Fedora

  • Fedora 38, 39, 40+

Example:

repositories:
  - id: fedora-40-everything
    type: rpm
    feed: https://download.fedoraproject.org/pub/fedora/linux/releases/40/Everything/x86_64/os/

EPEL (Extra Packages for Enterprise Linux)

  • EPEL 8, 9

Example:

repositories:
  - id: epel9-everything
    type: rpm
    feed: https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/

Rocky Linux

  • Rocky Linux 8, 9

Example:

repositories:
  - id: rocky9-baseos
    type: rpm
    feed: https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/

AlmaLinux

  • AlmaLinux 8, 9

Example:

repositories:
  - id: alma9-baseos
    type: rpm
    feed: https://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/

Troubleshooting

Metadata Not Found

Error: Failed to fetch repomd.xml

Solutions:

  • Check feed URL is correct

  • Ensure URL ends with / (e.g., .../os/ not .../os)

  • Verify network connectivity

  • Check SSL certificates if using HTTPS

Checksum Mismatch

Error: SHA256 checksum mismatch for package

Solutions:

  • Corrupted download - retry sync

  • Upstream changed package without updating metadata

  • Network issue - check connection

No Packages After Filtering

Warning: Filtered out all packages, 0 remaining

Solutions:

  • Check filter patterns are correct

  • Verify architecture filter includes needed architectures

  • Review only_latest_version setting

Limitations

  • No Delta RPMs (drpm / prestodelta). Not supported and not planned: for an offline mirror the bandwidth saving (client↔mirror) is marginal, and chantal downloads full RPMs anyway. The prestodelta metadata and .drpm files are not mirrored.

  • zchunk (*_zck) is dropped in every mode. chantal cannot recompute a zchunk’s de-chunked open-checksum without a zchunk library, so it cannot emit a valid repomd entry for it. dnf falls back to primary.xml.gz.

  • sqlite (*_db) is dropped in every mode. chantal regenerates primary.xml with rewritten package locations but cannot rewrite the sqlite databases, whose embedded locations would then be stale. Old yum clients fall back to primary.xml.gz.

(Modular repositories, GPG package-signature verification, comps, updateinfo, and filelists are already implemented — see the sections above.)