pag
git clone https://git.paganlinux.eu/pag.git
| Name↕ | Size↕ | Last change↕ | |
|---|---|---|---|
| pag-lang/ | 4 dni temu | ||
| .gitignore | 28 B | 4 dni temu | |
| pag | 0.2 KB | 4 dni temu | |
| README-EN.md | 0.0 KB | 4 dni temu | |
| README.md | 0.0 KB | 4 dni temu | |
| REAFME-EN.md | 0.0 KB | 4 dni temu |
pag – PaganOS Package Manager
Package manager for PaganOS. Atomic installation (staging → rename), GPG signature verification with fingerprint pinning, per-file SHA256, full transaction rollback, hooks and triggers, and support for immutable systems with deployments.
Diagrams in this README are rendered with Mermaid – supported by the
git.paganlinux.eu portal (and GitHub/Gitea).
pag --version # client version (e.g. pag 3.3.20)
pag # full help (command list)
pag --help # same as above
Table of contents
- Quick start
- How it works
- Commands
- Environment variables
- Paths and files
- Package format
- Hooks and triggers
/etcconfiguration –.pacnew/.pacsave- Examples
- Troubleshooting
- Install and update
- License
Quick start
# Refresh repository indexes (and see what is pending an update)
sudo pag sync
# Install / remove
sudo pag install firefox gimp
sudo pag remove gimp
# Update packages only…
sudo pag update
# …or the whole system: packages + kernel / initramfs / GRUB
sudo pag upgrade
# Base baked into the ISO vs. the repository (full rolling)
pag base # what comes from the image, what pag manages
sudo pag base adopt # adopt the base from the repo (--dry-run = preview)
# Verify the integrity of all files
sudo pag verify --deep
How it works
pag install flow
graph TD
A["pag install pkg"] --> B["Dependency resolution (DFS + provides)"]
B --> C{"Missing dependencies?"}
C -->|yes| C1["Error – abort"]
C -->|no| D["ABI verification (so-name)"]
D --> E["Pre-flight: free space + RW mount"]
E --> F["flock + database snapshot"]
F --> G["Parallel package download"]
G --> H["GPG + package SHA256 verification"]
H --> I["Staging: extract + per-file sums"]
I --> J["Atomic rename of files into the system"]
J --> K["pre/post-install hooks"]
K --> L["Write to SQLite + transaction history"]
L --> M{"PAG_IMMUTABLE=1?"}
M -->|yes| N["New deployment + GRUB entries"]
M -->|no| O["ldconfig + triggers"]
H -->|error| R["Rollback of the whole transaction"]
I -->|error| R
J -->|error| R
R --> S["Restore database and files"]
Key properties:
- Atomicity – files first go to staging on the same partition as
/, then are moved withrename()(no half-install). - Transactionality – if any package fails, the whole transaction is rolled
back (
installed.json, files, backups). - File sharing – a file owned by two packages is not removed when one of them is removed (only the database entry is removed).
Trust chain
graph TD
A["repo.json + repo.json.asc"] --> B["GPG: VALIDSIG line"]
B --> C["Repo fingerprint pinning (TOFU → pin)"]
C --> D["Package index"]
D --> E["package .pag + .asc"]
E --> F["GPG: signature matches repo pin"]
F --> G["Whole-package SHA256"]
G --> H["Safe extraction (anti-traversal)"]
H --> I["sums.json: per-file SHA256"]
I --> J["Strip SUID bit"]
J --> K["Install"]
F -->|"missing / bad signature"| X["Reject package"]
G -->|"SHA256 mismatch"| X
H -->|"traversal / symlink escape"| X
- First use of a key = TOFU, afterwards the fingerprint is pinned
(
pag key-trust/pag key-untrust). - Verification is fail-closed: missing/bad signature = no installation
(override only with
PAG_INSECURE=1, build/dev only). pag self-updategoes through the same path: GPG → SHA256 → syntax check → atomic client replacement.
Immutable system
With PAG_IMMUTABLE=1, installation does not mutate /; it creates a new
deployment. Rollback is just switching the active symlink.
graph TD
R["/"] --> D["/.deployments"]
D --> A["active → 20260723T120000"]
D --> D1["20260723T120000 (new)"]
D --> D2["20260722T090000 (previous)"]
D1 --> U["usr/ bin/ lib/ – system"]
D1 --> S1["var → /var"]
D1 --> S2["etc → /etc"]
D1 --> S3["home → /home"]
D1 --> S4["boot → /boot"]
D2 -.->|"deploy-rollback"| A
/var,/etc,/home,/boot(and otherSHARED_PATHS) are shared between deployments – they are not duplicated./bootshares the kernel and initramfs, saving space per deployment.- Rollback from the bootloader: each deployment has its own GRUB entry
(
pag grub-update).
Rollback
graph TD
T["Transaction"] --> OK{"Success?"}
OK -->|yes| H["History + snapshot + file journal"]
OK -->|no| RB["Automatic transaction rollback"]
H --> R["pag rollback"]
R --> R1["Restore installed.json from snapshot"]
R --> R2["Remove new files from the journal"]
R --> R3["Restore overwritten files from backup"]
R --> R4["Clean up empty directories"]
RB --> R1
RB --> R2
RB --> R3
pag history shows recent transactions (including executed hooks), and
pag rollback reverts the last successful transaction with a snapshot.
Rolling – base baked into the ISO
The PaganOS image is built from sources (glibc, gcc, GTK, XFCE, kernel…).
pag did not install them, so they are not in its database
(/var/lib/pag/installed.json) – and since it does not know them,
pag upgrade will not update them. The image files are not untouchable
though: pag install <name> overwrites them (a backup is kept for
pag rollback).
To make the system fully rolling, tell pag what the image base is:
pag base # report: how many image packages pag manages, how many can
# be adopted from the repo, which stay at the image version
sudo pag base adopt # adopt the base from the repo (--dry-run = preview only)
After pag base adopt the image packages become ordinary repo packages, so
the next sudo pag upgrade updates the whole system. The list of base
packages comes from a manifest baked into the image:
/usr/share/pag/base.json (name + version; the builder appends an entry for
every package it builds). Builder names are mapped onto repo names (e.g.
gtk → gtk3, libX11 → xorg-libx11); names with no repo counterpart are
reported as staying at the image version.
Commands
BASICS
| Command | Description |
|---|---|
pag install <pkg>... |
Install packages (together with dependencies) |
pag install -f <pkg>... |
Force reinstall (even the same version) – restores files, empty directories and hooks |
pag remove <pkg>... |
Remove packages |
pag update |
Update packages to newer versions |
pag sync |
Refresh repository indexes + show how many packages await update |
pag upgrade |
System update: packages + kernel / initramfs / GRUB |
pag list |
List packages available in the repository |
pag list --installed |
List installed packages |
pag search <query> |
Search packages in the repo (+ Flathub) |
pag info <pkg> |
Package details (version, dependencies, size, signature) |
pag files <pkg> |
List files owned by a package |
pag verify |
Verify the integrity of installed files |
pag verify --deep |
Full per-file SHA256 verification |
pag clean |
Clear the download cache |
pag stats |
System statistics (package count, size, cache…) |
pag download <pkg>... |
Download packages to cache (offline mode) |
Smart search: pag <name> (any unknown command) searches the repo and
Flathub and suggests names – e.g. pag firefox will find the package.
SECURITY / GPG KEYS
| Command | Description |
|---|---|
pag key-add <url\|file> |
Import a repository GPG key |
pag key-list |
List trusted keys |
pag key-remove <id> |
Remove a key |
pag key-trust <repo> |
Pin the repo key fingerprint (TOFU disabled) |
pag key-untrust <repo> |
Forget the fingerprint (back to TOFU) |
pag key-trusted |
List pinned repo fingerprints |
ADVANCED
| Command | Description |
|---|---|
pag why <pkg> |
Why a package is installed (who depends on it) |
pag autoremove |
Remove orphaned dependencies |
pag remove-orphans |
Remove orphaned dependencies (alias) |
pag pin <pkg> [version] |
Pin a package to a version (block updates) |
pag unpin <pkg> |
Unpin |
pag pinned |
List pinned packages |
pag history |
Transaction history |
pag rollback |
Revert the last transaction (restore files from backup) |
pag repo-add <url> [name] |
Add a repository (drop-in in /etc/pag/repos/) |
pag repo-list |
List configured repositories |
pag sbom export [spdx\|cyclonedx] |
Export an SBOM manifest of all installed components |
pag self-update |
Update the pag client itself (GPG signature + SHA256 + syntax, atomically) |
ROLLING (BASE FROM THE IMAGE)
| Command | Description |
|---|---|
pag base |
Report: image packages – managed by pag / adoptable from repo / no counterpart |
pag base adopt |
Adopts the base packages from the repo (replaces image files, backup for pag rollback); --dry-run = preview |
pag base adopt <pkg>... |
Adopts only the given base packages |
FLATPAK
| Command | Description |
|---|---|
pag flatpak [<query>] |
Search and install from Flathub |
pag flatpak search <query> |
Search Flathub |
pag flatpak install <id> |
Install a flatpak |
pag flatpak remove <id> |
Remove a flatpak |
pag flatpak list |
List installed flatpaks |
pag flatpak update |
Update all flatpaks |
pag flatpak info <id> |
Flatpak details |
Installation as root forces the system scope (
--system), so the application is visible to all users, not just root.
IMMUTABLE SYSTEM (PAG_IMMUTABLE=1)
| Command | Description |
|---|---|
pag deploy-list |
List deployments |
pag deploy-rollback |
Switch to the previous deployment |
pag deploy-cleanup [N] |
Remove old deployments (keep N, default 3) |
pag initramfs-update |
Rebuild initramfs |
pag grub-update |
Regenerate GRUB entries for all deployments |
Environment variables
| Variable | Meaning |
|---|---|
PAG_ROOT |
Alternative operation root (tests/chroot); default / |
PAG_IMMUTABLE=1 |
Immutable mode – installation creates a new deployment |
PAG_YES=1 |
Automatic confirmation (same as -y / --yes) |
PAG_INSECURE=1 |
Disables the HTTPS requirement and fail-closed GPG (build/dev only!) |
PAG_NO_HOOKS=1 |
Skip hooks and triggers |
PAG_HOOK_TIMEOUT |
Hook timeout in seconds (default 60) |
PAG_LANG_DIR |
Directory with translation files (pl.json, en.json) |
PAG_LANG_NO_FILES=1 |
Ignore translation files (export built-ins) |
PAG_ROOT_DEVICE / PAG_GRUB_ROOT |
Explicit root= for GRUB (ISO/IMG build) |
PAG_IN_CHROOT=1 |
Force chroot mode when detecting the root device |
Paths and files
| Path | Purpose |
|---|---|
/var/lib/pag/ |
State database: installed.json, files.db, world, pinned.json, history.json, pag.lock, hooks/ |
/var/lib/pag/files.db |
SQLite: file owners + SHA256 sums |
/var/cache/pag/ |
Downloaded package cache |
/var/cache/pag/repos/ |
Repository index cache (JSON + ETag + timestamp) |
/etc/pag/repos.conf and /etc/pag/repos/*.conf |
Repositories (drop-in) |
/etc/pag/trusted.json |
Pinned repo key fingerprints |
/etc/pag/gpg/ |
Isolated GPG keyring |
/etc/pag/triggers/*.json |
Custom triggers |
/etc/pag/lang/, /usr/share/pag/lang/ |
Translations (files override built-ins) |
/var/log/pag/audit.log |
Audit: hooks, self-update |
/.pag_staging |
Staging (same partition as / – no EXDEV) |
/.deployments/ |
Deployments (immutable mode) |
Package format
A .pag package is an archive containing:
metadata.json – name, version, release, dependencies, provides/requires (so-name)
data.tar.xz – system files + sums.json (per-file SHA256)
hooks/ – optional: pre-install, post-install, pre-remove, post-remove
Installation is verified per file against sums.json, and extraction is
protected against directory traversal and escape via malicious symlinks.
Hooks and triggers
Hooks run as root (like apt/pacman), in a restricted environment:
pre-install,post-install,pre-remove,post-remove- clean env:
PATH,HOME=/root,LANG/LC_ALL=C.UTF-8,PKG_NAME,PKG_VERSION,PKG_ACTION,PKG_HOOK_API=1 - timeout (
PAG_HOOK_TIMEOUT), optional disable (PAG_NO_HOOKS=1), entries in/var/log/pag/audit.logand in the transaction history
You install code you trust – hooks have full privileges.
Triggers run once per transaction, when matching paths were touched (only if the given binary exists):
| Trigger | Paths | Command |
|---|---|---|
font-cache |
/usr/share/fonts/, /usr/local/share/fonts/ |
fc-cache -fs |
glib-schemas |
/usr/share/glib-2.0/schemas/ |
glib-compile-schemas … |
desktop-database |
/usr/share/applications/ |
update-desktop-database -q … |
mime-database |
/usr/share/mime/ |
update-mime-database … |
You can add your own triggers as /etc/pag/triggers/*.json.
/etc configuration – .pacnew / .pacsave
The /etc directory is shared between deployments (it is not reverted by
deploy-rollback). To avoid losing user changes:
- Updating a configuration file that the user modified: the new version is
written as
<file>.pacnew, and the user's file is kept. - Removing a package with a modified configuration file: the file becomes
<file>.pacsaveinstead of being deleted.
The comparison uses the SHA256 sum recorded at install time.
Examples
# Install and updates
sudo pag install firefox gimp
sudo pag update # packages only
sudo pag upgrade # packages + kernel/initramfs/GRUB
sudo pag sync # refresh indexes + update info
# Repair a package (missing files/directories, e.g. /etc/pulse/default.pa.d)
sudo pag install -f pulseaudio
# Application icons after installing an icon theme (cache built automatically)
sudo pag install papirus-icon-theme
# Security
sudo pag key-add https://repo.paganlinux.eu/stable/paganos.asc
sudo pag key-trust https://repo.paganlinux.eu/stable/
sudo pag verify --deep
# Dependencies and package provenance
sudo pag why libjpeg-turbo
sudo pag autoremove
# SBOM for audit / compliance
sudo pag sbom export cyclonedx > sbom.json
# Revert the last transaction
sudo pag rollback
Troubleshooting
| Symptom | Solution |
|---|---|
| "Another pag instance is running" | Another pag process is active (flock lock). Wait or check pgrep -af pag. |
| "Cannot refresh the index" | The repo cache is read-only for a regular user – run as root: sudo pag sync. |
| "Invalid signature / missing signature" | Import the key: sudo pag key-add <url>, then verify sudo pag key-trusted. |
| Missing files/directories after install | sudo pag install -f <pkg> (restores files, empty directories and hooks). |
System does not boot after grub-update |
Set the root device explicitly: PAG_ROOT_DEVICE=/dev/sda2 sudo pag grub-update. |
| Flatpak app not visible in the menu | Add /var/lib/flatpak/exports/share to XDG_DATA_DIRS and log in again. |
Install and update
# On a running PaganOS, pag is in the base repository:
sudo pag install pag # install from the repository
sudo pag self-update # update the client itself (signed)
# pag is also managed by the package manager – after a new version is
# published in the repo:
sudo pag update
sudo pag upgrade
License
PaganOS / pag – an open source project. See the distribution repository for details.
- 2d9af31 pag v3.3.7: dodano 'pag sync' + drop-in /etc/pag/repos/*.conf
- 49cfe15 v3.3.4
- ac59b92 v3.3.3
- 67baf4e v3.3.2: multi-language USAGE (PL/EN)
- befc42b v3.3.2: fix version string
- 115b374 v3.3.2: full security - anti-downgrade, SUID strip, HTTPS-only, name validation, size limit, lock file, audit log
- aee5315 security: path whitelist - block writes outside /usr /etc /var /opt
- 0a0d5de v3.3.1
- eb3724e feat: --version -V version flags
- 4526207 fix: .2f MB zamiast .1f (30KB nie pokaze 0.0)
- 935308d v3.3.1: fix CRLF -> LF, bump version
- baa435f v3.3.1: bump version
- 265f364 docs: add README.md for pag package manager
- bf32327 v3.3.0
- 198b1ef poprawiono klucze