Skip to content

SOW v0.7.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 03:21
· 2 commits to main since this release

SOW 0.7.0 adds flat RPM pruning and a shared password-file signing interface. It also fixes defects in migration, recovery, publication, RPM signature verification, and version ordering found during the release review.

These notes cover the changes since 0.6.1. Database schema v13, configuration schema sow/v3, and the public repository layout stay unchanged. Workspaces on 0.5.0 through 0.6.1 need no schema migration.

Prune old RPM versions

sow prune DIR keeps the highest Epoch/Version/Release for each package name and architecture, publishes the filtered index, then deletes older RPMs.

sow prune /srv/candidate --dry-run --protect age_18 --protect age_18-llvmjit
sow prune /srv/candidate --protect age_18 --protect age_18-llvmjit
  • --dry-run validates and previews without writes. Each repeatable --protect NAME preserves all versions of an exact package name and must match a package.
  • --metadata-timestamp SECONDS sets the index publication time, with the same default of 0 as create.
  • Replacement packages must pass embedded digest checks. SOW binds the verified and indexed bytes to a stable file identity, including change time, and checks it before every deletion and before completion. An in-place rewrite with restored size and mtime stops further deletion.
  • Interrupted cleanup can be resumed. An existing repo_complete marker is refreshed only after successful completion. Errors report completed changes; already deleted packages are not restored.

Prune works on top-level regular binary RPMs in a local publication source. It rejects managed workspaces, DEB packages or indexes, package symlinks, source RPMs, equal EVRs within a name/architecture group, RPM v6 packages, signed repomd.xml, and independent metadata that SOW cannot generate. It does not sign packages. Clients with cached old indexes may still need the old RPMs: account for that before publishing a pruned repository.

See the prune command reference.

Sign with password files

Use --passfile PATH, SOW_GPG_PASSFILE, or a per-key passfile in sow.yml for protected RPM package keys and RPM/APT metadata keys, including GPG agent keys.

sow create ./packages --sign-with 0123456789ABCDEF --passfile /run/secrets/gpg-password

The priority is CLI, per-key configuration (including a legacy passphrase reference), then environment. The file is one nonempty UTF-8 line, at most 64 KiB; one final LF or CRLF is removed without trimming spaces or tabs. Use a literal path, not file://. Relative CLI/environment paths use the current directory; configured paths use the workspace root. No default file is searched.

The interface also covers signing preflight, initialization, migration, leaf export, and recovery of interrupted operations. Credentials do not enter process arguments, repository state, or public files. Password files must be regular files with no symlinks in the path. Keep them outside the repository with private access permissions. Legacy metadata passphrase references remain supported.

See the password-file contract, including command coverage and external GPG requirements.

RPM compatibility

  • ECDSA and EdDSA signatures: accept these header signatures in RPM's tag 267 (RPMSIGTAG_DSA), where modern RPM stores them. Real Ed25519 and ECDSA packages now verify; a mismatched RSA signature in that tag remains rejected.
  • Caret ordering: fix Version and Release comparisons so a snapshot such as 2.0^20250611 sorts before 2.0.1. Managed version limits consequently retain the newer release.
  • Foreign metadata: create keeps its existing behavior of replacing repomd.xml without groups, updateinfo, modules, or unknown records that SOW does not generate. This preserves compatibility with legacy Pigsty repositories, including the modules generated by Pigsty v4.4.0 on EL8/9. Human output now warns about dropped types; JSON output adds dropped_metadata when nonempty. The external metadata files and signatures themselves are not maintained by SOW.
  • Prune metadata guard: prune rejects those independent records before mutation and rechecks before publication. SQLite and zchunk encodings of the package indexes are allowed. Prune also rejects an old index larger than the 16 MiB inspection limit. Create can still replace oversized or malformed indexes, but cannot report types it could not inspect.

If clients need the extra metadata, continue maintaining it with the appropriate generator. Refresh external repomd.xml.asc signatures after rebuilding.

Managed repositories and recovery

  • Migrated repositories remain writable. A completed C2 migration retains the identity of the Generation it created. Later builds no longer cause check, build, add, or gc to reject that migration anchor, and repo rm no longer mistakes a completed migration for an active transition. Affected repositories recover after upgrading without manual database repair.
  • Protect every published pointer. The withdrawal guard now checks the complete published Generation, including views unchanged by the latest publication. Removing a Dist, architecture, or signing companion is rejected while a configured target still publishes it. Retire that target binding first, or publish under a new target name and prefix. Retired public files remain available for you to remove separately; ordinary publication does not withdraw them automatically.
  • Unrelated offline targets no longer block operations. Publication, abort, and target GC compare the selected target against prospective paths of other targets. Actual physical path overlap remains rejected.
  • Recover interrupted plan writes. Empty, partial, or hash-invalid GC plans in the planned phase can be discarded before any deletion. Retained-removal plans can be rebuilt while the original target still exists. Contradictory state after destructive work remains an error.
  • Export carried-forward Dists. export rpm-leaf accepts a clean Dist that a later Generation did not rebuild, with or without signing.
  • Tolerate a backward clock step. Mutation recovery identifies the sole active operation by its ID instead of choosing by wall-clock order.

Dependencies and release checks

Component 0.6.1 0.7.0
AWS SDK core / S3 1.47.3 / 1.114.4 1.47.8 / 1.114.9
Smithy 1.28.6 1.28.8
SQLite / libc 1.61.0 / 1.79.0 1.62.0 / 1.80.1
Debian package parser 0.21.1 0.21.3
YAML go.yaml.in/yaml/v3 3.0.5 go.yaml.in/yaml/v4 4.0.0
GoReleaser 2.18.3 2.20.0

Go 1.27.3 remains the build baseline. YAML retains strict single-document validation and canonical configuration output. The bounded local RPM parser patch and third-party notices are updated with the dependency changes.

Integration now requires protected-key signing tests on EL8, EL9, and EL10. The EL8 test detects whether rpmsign --rpmv3 exists and skips only the unsupported repeated-signature case. Release gates cover unit and race tests, APT/DNF clients, S3-compatible publication, static analysis, vulnerability reachability, reproducible clean-source builds, and archive/RPM/DEB contents. Hosted R2 live testing is optional and was not run for this review; macOS amd64 was cross-built but not executed on the arm64 review host.

Upgrade

Stop writers, back up the complete workspace while preserving hard links, install 0.7.0, then run these commands for each configured Repository:

sow version
sow build -r REPOSITORY -C /srv/sow
sow check -r REPOSITORY -C /srv/sow

An unchanged build is a no-op. Workspaces from 0.3 or 0.4 still need sow repo migrate REPOSITORY first. Plain repositories have no database migration.

A configuration containing passfile cannot be loaded by 0.6.1 or older; remove those fields before downgrading. The no-symlink rule for password files remains in force. RPM v6 is not supported.

The release produces Linux and macOS archives for amd64 and arm64, two RPMs, two DEBs, and SHA256SUMS. See the installation guide and all changes since 0.6.1.

Release verification

Tag v0.7.0 resolves to 03ff02958ce0477baddb2f3686b81c2d4fccc872. The exact commit passed CI, Integration, and the Release build. Managed race tests completed in 1,869.227 seconds.

All eight release archives and packages were downloaded and verified against SHA256SUMS and GitHub asset digests. Packaged binaries, source documents, licenses and third-party notices match the release. Linux amd64, Linux arm64 and Darwin arm64 binaries ran successfully; Darwin amd64 was cross-built and inspected.

An upgrade check used the published 0.6.1 binary to create RPM/DEB repositories. Version 0.7.0 opened them and preserved the Generation on an unchanged build. Version 0.6.1 could reopen and check the workspace after a 0.7.0 mutation when no new configuration fields were used.

Additional acceptance on m3 (Ubuntu 26.04, Linux amd64) tested the exact uploaded release executable and a clean checkout of the tag:

  • Full source and patched RPM-module tests passed in 207.609 seconds; core race tests passed in 1,062.797 seconds (managed package: 1,031.057 seconds).
  • Actual RPM/DEB installation, workspace upgrade, rollback, and re-upgrade passed on EL7/8/9/10, Ubuntu 20.04/22.04/24.04/26.04, and Debian 11/12/13. These are container userspaces on the m3 kernel.
  • Real APT clients installed packages from the release binary's generated indexes on all seven Debian/Ubuntu targets. YUM/DNF clients on EL7–EL10 installed an old package, then upgraded through the same repository ID after pruning with an explicit newer metadata timestamp.
  • Protected-key signing passed on EL8/9/10. EL10-generated Ed25519, ECDSA and RSA packages passed verification, while wrong trust keys and payload tampering were rejected.
  • Thirteen additional executable-level cases and independent fault-injection regressions passed, including replacement corruption, interrupted GC plan writes, carried-forward exports, clock rollback, offline targets and published-view protection.
  • Six fuzz targets completed 6,876,340 executions in short bounded runs. The 50,000-package synthetic RPM streaming test passed; the measured generation phase took 5.291 seconds.
  • Static analysis, vulnerability reachability, upstream provenance, S3 compatibility and clean-source delivery passed. The Linux source archive matched the earlier macOS archive byte for byte (7a788bcfdc99c0532b147d878624d27f122065f29d825d2dc05812c5420d56e7).

No additional code-level release blockers were found in this acceptance scope. Two documentation inaccuracies were corrected in documentation PR #3.