This is the multi-page printable view of this section. .
Release Notes
- 1: SOW v0.7.1
- 2: SOW v0.7.0
- 3: SOW v0.6.1
- 4: SOW v0.6.0
- 5: SOW v0.5.0
- 6: SOW v0.4.0
- 7: SOW v0.3.0
- 8: SOW v0.2.0
Read the changes and upgrade steps for each SOW release, with the newest version first.
SOW 0.7.1 upgrades to Go 1.27.4, refreshes dependencies, and fixes recovery, input validation, and S3/R2 handling. Workspaces on 0.5.0 through 0.7.0 need no schema migration. See the 0.7.1 upgrade guide.
SOW 0.7.0 adds flat RPM pruning and password-file signing, fixes migration and recovery defects, and updates dependencies. Workspaces on 0.5.0 through 0.6.1 need no schema migration. See the 0.7.0 upgrade guide.
SOW 0.6.1 updates Go to 1.27.3, refreshes dependencies, and improves invalid-input diagnostics. Workspaces already on 0.5.0 or 0.6.0 need no schema migration. See the upgrade guide.
1 - SOW v0.7.1
v0.7.1 ·
SOW 0.7.1 updates the Go toolchain and dependencies. It also fixes recovery, package validation, RPM export, and S3/R2 handling.
Download the release from GitHub or the Download page.
These notes cover changes since 0.7.0. Database schema v13, configuration schema sow/v3, the CLI, and the public repository layout remain compatible. Workspaces on 0.5.0 through 0.7.0 need no schema migration.
Recovery and repository state
- Recover interrupted legacy
dist.newanddist.initoperations when effective signing is absent. - Preserve unproven C2 migration stage files intact under
.sow/<repo>/abandoned/and report their location. Empty stages are removed, repeated recovery is safe, and local GC can proceed. Inspect the reported files before removing them. - Reopen directory cursors between deletion batches so cleanup completes on macOS APFS and BSD filesystems.
- Keep multi-statement SQLite reads in one read-only transaction. Split large Dist membership queries below SQLite’s parameter limit.
- Normalize legacy repository time records with fractional seconds and reject years outside
1..9999.
Package validation and RPM export
- Reject RPM v6 consistently in Plain
create, everyprunepath, and Managed ingestion. - Limit decompressed DEB control archives and APT/RPM metadata streams, including oversized PAX headers.
- Recognize Linux
renameat2unsupported-operation errors and retain the portable fallback. - Allow
export rpm-leafwhen an unrelated filesystem publication target is unmounted. Physical path overlap is still rejected. - Use the selected Dist’s recorded build publication time for the exported metadata signature. A later build of another Dist no longer changes that time. The exported
repomd.xmldata timestamp remains0. - Accept repeated package inputs when
sow addreceives both explicit files and their parent directory.
S3 and R2
The updated AWS SDK retries bodyless HTTP 429 responses. SOW preserves the HTTP error classification when those retries are exhausted.
SOW also finds HTTP status codes inside joined errors. An HTTP 404 during multipart abort means the upload is already removed. Error XML responses for listing and multipart operations now have size limits.
Toolchain and dependencies
Source builds require Go 1.27.4 or newer. All 35 required module versions were checked against the latest available versions during release preparation.
| Component | 0.7.0 | 0.7.1 |
|---|---|---|
| Go | 1.27.3 | 1.27.4 |
| AWS SDK core / S3 | 1.47.8 / 1.114.9 | 1.48.0 / 1.114.10 |
| Smithy | 1.28.8 | 1.28.9 |
| klauspost/compress | 1.20.3 | 1.20.4 |
| modernc/libc | 1.80.1 | 1.81.0 |
| golang.org/x/sys | 0.49.0 | 0.50.0 |
| GoReleaser | 2.20.0 | 2.20.1 |
AWS internals, pprof, x/mod, x/sync, and modernc compiler dependencies are also updated. The local RPM parser security patch is retained. Third-party notices match the new release builds.
Upgrade
Stop workspace writers and back up the complete workspace with hard links preserved. Install 0.7.1, then build and check each configured Repository:
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.
SOW 0.6.1 and older cannot read configurations containing passfile. Remove those fields before downgrading. RPM v6 remains unsupported.
The release includes four Linux/macOS archives, two RPMs, two DEBs, and SHA256SUMS. See the upgrade guide and complete changes.
.rpm
| File | Checksum |
|---|---|
| sow-0.7.1-1PGSTY.aarch64.rpm Linuxarm64SHA-256 | 633dec35eede026280143f272783fddf3453361a71df3b38f134567b9f921b0e |
| sow-0.7.1-1PGSTY.x86_64.rpm Linuxamd64SHA-256 | d4ccae2f3a184d28a92da695cdb46848a46496d137399063ca1d40250fc112c4 |
.deb
| File | Checksum |
|---|---|
| sow_0.7.1-1PGSTY_amd64.deb Linuxamd64SHA-256 | 127559a2fec7d7532ad1a8d41dce0ba2d61ada3454fa7ef7fc82756d3ab99bd1 |
| sow_0.7.1-1PGSTY_arm64.deb Linuxarm64SHA-256 | 8d69f623a1741aff4dc4c001059f3fc4279d5b0430d25c4d72704a72ff77dc4e |
.tar.gz
| File | Checksum |
|---|---|
| sow_0.7.1_darwin_amd64.tar.gz macOSamd64SHA-256 | cc1d68911bc80c473d73ace6cbfd2ab586394ea0fb44709fb597d3b4fd44731c |
| sow_0.7.1_darwin_arm64.tar.gz macOSarm64SHA-256 | 8120188108b98c79beab3bc0c081f0a4bed15c45533ff43bf69f4be8672551a4 |
| sow_0.7.1_linux_amd64.tar.gz Linuxamd64SHA-256 | d1fd60997a86a2048bfe38a5b23a5bcab07e1d99b171133e64ff2b75e4694179 |
| sow_0.7.1_linux_arm64.tar.gz Linuxarm64SHA-256 | 2adbe314ec4033825bc54effd870bfdbdd366858a35145e7831d298f72438f5c |
2 - SOW v0.7.0
v0.7.0 ·
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.
Availability: SOW 0.7.0 is available on GitHub and the Download page.
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.
--dry-runvalidates and previews without writes. Each repeatable--protect NAMEpreserves all versions of an exact package name and must match a package.--metadata-timestamp SECONDSsets the index publication time, with the same default of0ascreate.- 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.
- You can resume an interrupted cleanup by rerunning
sow prune. SOW refreshes an existingrepo_completemarker only after successful completion. Errors report completed changes, and SOW does not restore already deleted packages.
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.
The priority is CLI, per-key configuration (including a legacy passphrase reference), then environment. The file contains one nonempty UTF-8 line, at most 64 KiB. SOW removes one final LF or CRLF 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. SOW searches no default file.
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; SOW still rejects a mismatched RSA signature in that tag. - Caret ordering: fix Version and Release comparisons so a snapshot such as
2.0^20250611sorts before2.0.1. Managed version limits consequently retain the newer release. - Foreign metadata:
createkeeps its existing behavior of replacingrepomd.xmlwithout 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 addsdropped_metadatawhen nonempty. SOW does not maintain the external metadata files or signatures themselves. - Prune metadata guard: prune rejects those independent records before mutation and rechecks before publication. Prune allows SQLite and zchunk encodings of the package indexes. 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, orgcto reject that migration anchor, andrepo rmno 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. SOW rejects removing a Dist, architecture, or signing companion 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. SOW still rejects actual physical path overlap.
- Recover interrupted plan writes. SOW can discard empty, partial, or hash-invalid GC plans in the planned phase before any deletion. It can rebuild retained-removal plans while the original target still exists. Contradictory state after destructive work remains an error.
- Export carried-forward Dists.
export rpm-leafaccepts 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. This release updates the bounded local RPM parser patch and third-party notices 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 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:
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.
SOW 0.6.1 and older cannot load a configuration that contains passfile; remove those fields before downgrading. The no-symlink rule for password files remains in force. SOW does not support RPM v6.
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.
.rpm
| File | Checksum |
|---|---|
| sow-0.7.0-1PGSTY.aarch64.rpm Linuxarm64SHA-256 | ea62ad17c62c39c606c2c942d6f0b0acbfb1d0788df71d872746b653753fefdf |
| sow-0.7.0-1PGSTY.x86_64.rpm Linuxamd64SHA-256 | 3111afe9857fc44d22a63072ab520d47cd96df4074b632f255c4087030833055 |
.deb
| File | Checksum |
|---|---|
| sow_0.7.0-1PGSTY_amd64.deb Linuxamd64SHA-256 | 9e579c560b0564bd45481f5d205cfa76edadcb1eedd6e787bd845ed5aba5425f |
| sow_0.7.0-1PGSTY_arm64.deb Linuxarm64SHA-256 | 4384d343890e84dec8f917c5f8d6a8612bc98af28b55aec96000f1ea9d2bb59b |
.tar.gz
| File | Checksum |
|---|---|
| sow_0.7.0_darwin_amd64.tar.gz macOSamd64SHA-256 | 21f276d940b44264be67ac1b020e50004ec9e77292f12061b880093175f01af1 |
| sow_0.7.0_darwin_arm64.tar.gz macOSarm64SHA-256 | bd4232eec5d329a51ed2db8f58d43341c30875e8693278b4c5d10c946d814433 |
| sow_0.7.0_linux_amd64.tar.gz Linuxamd64SHA-256 | 4ad5c1faa853f3e295abab3b1c070b1e9d2c337af3afcbca7384808c3c3df291 |
| sow_0.7.0_linux_arm64.tar.gz Linuxarm64SHA-256 | 9453c84501406a0a31044120c9b26ef0eb4865bf45c0d204efd043cf650b323c |
3 - SOW v0.6.1
v0.6.1 ·
SOW 0.6.1 is a maintenance release with updated dependencies and clearer error messages. It keeps the CLI, database schema v13, configuration sow/v3, and public repository layout. Workspaces already on 0.5.0 or 0.6.0 need no schema migration.
Get the packages and archives from the download page, with checksums from the v0.6.1 release.
Toolchain and dependencies
Source builds now require Go 1.27.3 or newer. All release binaries use Go 1.27.3. The release updates the libraries used for encryption, S3 access, compression, SQLite, and Debian package parsing.
| Dependency | Version |
|---|---|
| ProtonMail go-crypto | 1.5.2 |
| AWS SDK for Go / S3 | 1.47.3 / 1.114.4 |
| klauspost/compress | 1.20.3 |
| modernc SQLite / libc | 1.61.0 / 1.79.0 |
| pault.ag/go/debian | 0.21.1 |
| go.yaml.in/yaml/v3 | 3.0.5 |
| golang.org/x/crypto / x/sys | 0.58.0 / 0.49.0 |
YAML parsing moves to the module maintained by the YAML organization. Existing sow.yml files use the same format.
The RPM parser retains its existing local security patches.
Updated third-party notices ship with every archive and Linux package.
Maintenance fixes
- Invalid paths and OpenPGP armor now produce useful diagnostics instead of
%!w(<nil>). The fixes cover log export, RPM metadata generation, signature validation, and workspace checks. SOW still rejects the same invalid inputs. - CI snapshot packages read their version from the Makefile, removing a hard-coded version. This release updates release tools and GitHub Actions, including GoReleaser 2.18.3, deadcode 0.52.0, and govulncheck 1.9.0.
Upgrade
Stop workspace writers and back up the complete workspace before replacing the executable. Install 0.6.1, then build and check each Repository:
Replace REPOSITORY with a name from sow.yml. An unchanged repository reports a no-op build and keeps its Generation and timestamps.
See the installation guide for package commands and migration from 0.3 or 0.4.
Release validation covered package tests, race checks, APT/DNF clients, S3-compatible transport, and 50,000-package RPM metadata generation. Upgrade and rollback checks used RPM/DEB workspaces created by the published 0.6.0 binary, operated by 0.6.1, then reopened by 0.6.0.
Vulnerability scan result
Source analysis and a control build with symbols found no affected symbols or imported packages.
GO-2026-5932 concerns the unused legacy golang.org/x/crypto/openpgp package.
SOW uses the maintained ProtonMail fork; the legacy package is absent from all four release-target import graphs.
The release build strips symbol tables from the release binaries. For these binaries, govulncheck -mode=binary falls back to module-level precision and reports that notice.
This explains why its binary scan differs from the source scan.
The release includes Linux and macOS archives for amd64 and arm64, two RPMs, two DEBs, and SHA256SUMS.
See the complete changes for the source diff.
4 - SOW v0.6.0
v0.6.0 ·
SOW 0.6.0 improves repository updates, file verification, and recovery after an interruption. It keeps the current command set, configuration format, and public repository layout. A Managed workspace already on 0.5.0 needs no database migration.
This note covers the changes since 0.5.0. Use the installation guide for upgrade steps and the download page for release availability.
Changes for repository operators
| Area | Change in 0.6.0 | Effect on your workflow |
|---|---|---|
| Plain RPM updates | Keep current and immediately previous checksum-named metadata | Clients can finish fetching metadata referenced by the previous index |
| Managed builds | Record one publication time for metadata and signatures | Recovery preserves the original time; unchanged builds keep their existing output |
| File verification | Check file identity throughout authenticated reads | SOW detects replaced or rewritten files, including rewrites that restore the modification time |
| Signing keys | Read complete OpenPGP key bundles | SOW checks all supplied trusted keys and rejects malformed input |
| State and recovery | Preserve locks, consistent reads, and committed results | Maintenance errors do not make completed changes appear to have rolled back |
| Large repositories | Reuse verified data and limit parallel work | Builds, imports, checks, and publication avoid repeated work |
Plain RPM updates keep the previous indexes
A client first downloads repomd.xml, then requests the metadata files named inside it.
An update between those requests could previously remove the old metadata files before the client fetched them.
Plain sow create now keeps the current and immediately previous checksum-named RPM metadata sets.
An unchanged run does not advance this window. SOW can remove older metadata after the next changed index.
The small .sow-plain-rpm-history.json file records the retained references.
Keep it when copying a directory for further builds. It is not an operation journal; interrupted Plain builds still recover by rerunning create.
This window does not retain removed package files or cover every client cache lifetime. For caches that span several updates, keep the required packages and metadata in your publication layer. The YUM migration guide explains publication order, signatures, and cached clients.
Plain timestamps remain explicit. --metadata-timestamp still defaults to 0.
Keep the greatest published timestamp when replacing another generator or restoring older package content.
Managed builds keep one publication time
A new Managed build records one UTC time, with whole-second precision, before it publishes the affected Dist indexes.
The same value supplies APT Release dates, RPM repomd.xml data timestamps, and metadata signature times.
RPM revision remains the Generation number.
The chosen time respects previous build times and the selected signing key’s activation time. An unusable or not-yet-valid key causes an error. Keep the host clock correct.
Recovery reuses the recorded time. It rejects a changed time before publishing further Dist entry points. A no-op build creates no new Generation and does not refresh timestamps or signatures.
This behavior applies to new metadata-building operations, including automatic builds from add and rm, and new Dists.
Layout migration and older journals keep their previous timestamp rules.
Standalone export rpm-leaf output still uses RPM data timestamp 0.
An rm --check preview remains read-only. It predicts membership, paths, actions, and the resulting revision and Generation.
Execution chooses its own publication time. Time-dependent bytes, hashes, and sizes can therefore differ from the preview.
Verify the file that was actually read
Metadata and package checks now bind the digest to the opened file’s identity before and after reading. The same checks apply to fast validation and reused verification results. They detect file replacement and same-size rewrites, including changes that restore the original modification time.
Concurrent hard-link creation can change file attributes without changing package bytes. SOW handles this case and retains the identity from the successful verification. This keeps read-only hard-link exports compatible with repository checks.
Path traversal also checks that opened entries match the entries inspected earlier. Parent directories need traversal permission; they no longer need directory-listing permission merely to reach a known child. Package files still need read access, and controlled paths still reject unsafe symlinks and file types.
Read complete signing-key bundles
A trusted-key file can contain several public keys or consecutive armored key blocks. SOW now reads the complete input instead of stopping after the first block. It rejects malformed, truncated, or unsupported key material instead of silently skipping it.
A signing key reference must still identify exactly one primary key.
Put bundles in trusted_keys; use one signing identity for each metadata or package-signing setting.
The signing reference describes both cases.
Keep state and recovery results consistent
SQLite identity checks now preserve locks held by existing connections. Composite repository queries read related state from one database snapshot. Eligible WAL databases undergo validation once per open, avoiding repeated full validation during one connection’s work.
A database commit can succeed before a later checkpoint or cleanup fails.
SOW now preserves the committed command result in that case.
Inspect the result, sow status, and sow log before retrying; a nonzero exit does not prove rollback.
Dist status also reports unfinished repository maintenance, including local GC and log pruning. Matching Desired and Built package counts no longer hide this pending work. Removal logs preserve policy-driven outcomes as well as explicitly selected removals.
For an already-started development-era C2 layout transition, repo migrate --abort keeps the trusted transition marker.
It can also finish before the first journal or base manifest exists.
If a journal binds a plan, SOW verifies that plan against its recorded base manifest and rejects conflicting control records.
A nonempty temporary migration stage moves intact into .sow/<repo>/abandoned/.
The command reports the retained path or cleanup problem in stderr and JSON warnings.
Stage-cleanup warnings do not prevent abandonment. The public tree remains unchanged.
Once selected, the Repository name remains available in migration failure responses.
A fresh C2 repository still cannot start a migration.
An older abort that already removed its trusted marker requires a matching backup or a new workspace.
See repo migrate for the supported recovery paths.
Reduce repeated work
The release reduces I/O without adding another full repository scan or recovery state machine:
- Reuse authenticated DEB bytes for parsing and checking within the same operation.
- Reuse current payload and Dist verification results where their file identities still match.
- Reuse verified RPM export output instead of reading the same copy again.
- Avoid duplicate writes while staging imports and remove an unused initial output-tree hash.
- Query memberships for the selected packages and reuse package data already loaded for the operation.
- Keep package-staging workers independent and bounded by the requested concurrency.
sow check still reads and hashes each unique physical package on every run.
These changes do not turn it into a fingerprint-only check.
R2 inventory checks now use at most eight concurrent HEAD requests per page. The queued work and completed results stay bounded, including cancellation and failures. Upload retries no longer restart the idle timeout merely by seeking in the source file. Actual transfer progress is required. R2 garbage collection remains report-only.
Build, packaging, and validation
Source builds require Go 1.27.2 or newer. Quality checks use staticcheck 0.8.2. Upstream verification for the patched RPM parser also works when Go selected a downloaded toolchain.
The release targets remain Linux and macOS on amd64 and arm64.
Packaging produces four archives, two RPMs, two DEBs, and SHA256SUMS.
Archives and packages retain their license files and third-party notices.
Deterministic source delivery excludes local agent instructions from the delivered product source.
Regression tests cover file replacement, restored modification times, concurrent hard links, and complete key bundles. They also cover commit cancellation, post-commit failures, metadata-time recovery, migration abort, Plain index retention, and bounded R2 requests. The release also removes unused code and brittle Go runtime I/O instrumentation.
Local release checks covered the macOS and Linux suites, race checks, APT/DNF integration, and S3-compatible transport. They also covered 50,000-package RPM metadata generation, packaging, and an upgrade from the published 0.5.0 binary. Use your actual package clients and publication target for deployment acceptance.
Upgrade from 0.5.0
Database schema v13, configuration schema sow/v3, and the public pool/ + dists/ layout remain unchanged.
- Stop workspace writers.
- Back up the complete workspace, preserving hard links.
- Install SOW 0.6.0.
- Run these commands for each Repository:
Replace REPOSITORY and /srv/sow with your values.
A current 0.5.0 repository needs no schema migration or forced rebuild; build reports a no-op.
Publish only when you intend to deliver a new Built Generation to a configured target.
For 0.3 or 0.4 workspaces, run sow repo migrate REPOSITORY before building.
See the complete upgrade procedure.
5 - SOW v0.5.0
v0.5.0 ·
SOW 0.5.0 adds publication timestamps for existing YUM repositories and fixes Managed repository recovery, signing, and package-path handling. It also reduces repeated package verification during builds.
Install the release from Download SOW. If you use a Managed workspace from 0.3 or 0.4, migrate each Repository before further writes.
Upgrade a Managed workspace
- Stop commands that write to the workspace.
- Back up the complete workspace, including
sow.yml,.sow/, and all Repository roots. - Install SOW 0.5.0.
- Migrate, build, and check each Repository. Replace
pgsqland/srv/sowwith your names.
The migration updates the database to schema v13. Configuration remains sow/v3, and the
public layout remains pool/ plus dists/. The first build refreshes RPM authentication
and APT metadata records. Later builds reuse matching RPM verification records.
Use SOW 0.5.0 or newer with the migrated database. For backup and installation steps, see Install and upgrade.
Preserve YUM publication time
EL7 YUM can reject a new repomd.xml if its largest data timestamp is older than the
cached value. Changing the checksum, revision, or file modification time does not satisfy
that comparison.
Use the new option when replacing an existing metadata generator:
| Setting | Result |
|---|---|
| Default | RPM data timestamps remain 0 |
--metadata-timestamp SECONDS |
Sets the timestamp of all three RPM data records |
| Accepted value | An integer from 0 to 253402300799 |
Plain repomd.xml revision |
Remains 0 |
| Package bytes and DEB indexes | Unchanged by this option |
| Compressed XML and gzip headers | Unchanged when only the timestamp changes |
The option applies to create. Managed builds, publication, and RPM leaf export do not
accept it. A repeated build with the same package bytes and options produces the same
metadata; forced package re-signing can change the input bytes.
Keep the highest published timestamp in your maintenance script. Increase it when content changes, including when you restore an older package set. If a previous conversion reset timestamps to zero, use the pre-conversion publication history to recover that value.
If clients verify repository signatures, sign the final repomd.xml after each change.
--sign-with signs RPM packages; it does not sign the index. The
YUM migration guide covers timestamp selection, index
signing, and testing with existing client caches.
Repository and publication fixes
- Dist removal no longer deletes a package that was later added to another Dist.
- SOW checks signing policies and pool-path conflicts before committing Desired changes.
- Recovery preserves committed package selections and completes interrupted cleanup.
- A published package path stays bound to its content after local garbage collection. Publication recovery does not overwrite that path with different bytes.
- File names that differ only by case cannot create a second Pool URL, even for identical bytes. Case-insensitive workspaces and filesystem targets also reject directory aliases.
- Concurrent
export rpm-leaf --hardlinkandcheckcommands no longer report unchanged package bytes as corrupt. - Local
gcskips publication records whose packages exist only on the remote target. - Input paths can use symlinked parent directories. Package files themselves must pass the existing file checks.
- SQLite checkpoints delayed by readers no longer turn a completed write into a reported
failure. macOS writable connections use
fullfsync.
Signing and command output
APT signature verification now accepts GnuPG’s final-newline convention. New metadata signatures use SHA-256, and new builds check whether the signing key is currently usable. Agent signing fixes the signing time and selects the available signing subkey. New APT publications reject weak signature digests; historical verification keeps its recorded rules.
sow repo migrate reports the old and new schema versions. An unmigrated Repository shows
the migration command. Commands interrupted by SIGINT or SIGTERM return exit code 130. Rejected add batches
show per-file errors. file:// R2 credentials must point to regular files.
RPM dependencies
New regression cases cover pre-transaction and post-transaction script requirements, including combinations used by Cloudberry, Percona, and Grafana packages. Dependency rendering continues to follow modern createrepo_c behavior. See createrepo_c PR #427 for the upstream change.
For package-signing workflows, use RPM format v4. SOW 0.5.0 does not support RPM format v6 signatures. The generated repository metadata uses XML; it does not include SQLite rpm-md or module streams. See Compatibility for formats and client coverage.
Builds and packages
Source builds require Go 1.27.1 or newer. The release uses x/crypto v0.56.0 and
GoReleaser v2.18.2. Archives and native packages include THIRD_PARTY_NOTICES.
The release contains four Linux/macOS archives, two RPMs, two DEBs, and SHA256SUMS.
Get a specific artifact from the v0.5.0 release.
Compatibility tests are in qa/compat/; performance tests are in qa/perf/.
The S3 integration fixture uses a digest-pinned pgsty/silo image.
6 - SOW v0.4.0
v0.4.0 ·
SOW 0.4.0 improved Managed repository verification and recovery. check reads each physical package once for its content hash. RPM verification keeps separate trust decisions for separate key sets. Publication targets can change their public URL or cache lifetime through an audited rebind operation.
Plain behavior and the public pool/ and dists/ layout stayed the same. This page describes version 0.4.0; use the installation guide to upgrade to the current release.
Upgrade from 0.3 to 0.4
Stop workspace writers and back up the complete workspace, preserving hard links. Install 0.4.0, then migrate each configured Repository before continuing maintenance:
The example has repositories named pigsty and pgsql; use the names from your sow.yml. Keep the backup for rollback because SOW 0.3 cannot open the migrated database.
Schema v11 fixed a 0.3 status bug: a Repository could appear clean while one of its Dists remained dirty. Status is now updated in the transaction that changes the Dists. Migration also repairs recorded publication and signer information. A historical signing identity that was never recorded remains unverified.
Schema v12 added an append-only history of publication-target bindings. Initial bindings, migration backfills, and later rebinds have separate revisions.
One content hash per physical package
Each sow check performs one complete content hash for each unique physical package, including files whose cached fingerprint still matches. Hard links to the same file share that result. SOW ties verification to the file it read and detects replacements or changes during the check.
The same result is reused when checking retained generations, the final manifest, and changes. Adding Dists or retained generations does not multiply package hashing. DEBs and unsigned RPMs need one full read. A signed RPM uses at most one additional read from the main header to the end of the file for signature verification.
Package-cache queries are limited to the selected digests and run in bounded SQLite batches. A warm build of the 64 MiB test package reads no package content. A changed fingerprint and missing cache row share one verification pass.
Verify each RPM trust set separately
RPM signature packets are checked against each candidate key set independently. Every recognized packet must verify within that set, and at least one verified signature must authenticate the payload.
This supports historical CentOS signatures and deliberately dual-signed packages. It also prevents SOW from combining partial successes across unrelated key sets into a false single-key verification result.
The current policy keys, retained-generation keys, and combined trusted keys use the same signature read. Additional keys change trust decisions without adding package reads.
Update publication-target settings
Use sow publish TARGET --rebind to update mutable target settings while preserving its storage identity and recovery state:
May change with --rebind |
Requires a new target |
|---|---|
| Target name | Repository identity |
public_endpoint |
Provider or storage endpoint |
max_cache_ttl |
Region, bucket, or prefix |
A normal publish reports changed settings and requests --rebind. Rebind takes the publication locks, records a revision, and can resume an interrupted publication after its commit decision. Pending cleanup restricts TTL and filesystem public-URL changes. Previously recorded cache deadlines remain in effect.
Check public files and recover interrupted uploads
Filesystem and R2 HTTP(S) checks now use separate deadlines for response headers and stalled bodies. Large files can take more than two minutes as long as data continues to arrive.
SOW checks the ordinary client URL. Stale content and 404 responses wait up to max_cache_ttl; temporary 408, 425, 429, and 5xx responses use a shorter retry window. Oversized responses fail verification. Filesystem cleanup checks for a public 404 or 410 after deletion. R2 cleanup remains report-only.
Other publication changes include:
- Check filesystem path aliases before creating a target binding, including case aliases on case-insensitive volumes.
- Resume an interrupted pointer update when it contains the recorded old or new bytes. Report unexpected content for investigation.
- Verify the changed public objects instead of downloading the complete generation on every publication.
- Use retryable reads and writes, idle timeouts, and bounded conditional multipart uploads for R2. Check the whole-object SHA-256 before completing an upload.
CLI and maintenance fixes
- Repeating
sow addbuilds a selected Dist left dirty by--skipor a configuration change, even if the package is already in the pool. sow rm --checkuses the same configuration checks as removal and returns a read-only preview.- Every Managed command has readable text output. The
sow.cli/v1JSON format preserves partial or diagnostic results when a command fails. - Signer records stay consistent through partial builds, Dist changes, migration, retention, and garbage collection.
- Retired APT builder, external-sort, empty-Dist, and Git-tracked by-hash code was removed.
Build and release checks
The release used Go 1.27.0, up from Go 1.26.5 in 0.3. AWS SDK, SQLite, compression, and cryptography dependencies were updated. Build checks pinned staticcheck v0.8.1, deadcode v0.49.0, and govulncheck v1.7.0.
Release checks covered Go tests, static analysis, vulnerability and RPM-fork source checks, race tests, Linux amd64/arm64 builds, and the package-read limits described above.
The release includes four Linux/macOS archives, two RPMs, two DEBs, and SHA256SUMS. Archives contain sow, README.md, CHANGELOG.md, and LICENSE. Linux packages install the license with the executable.
Get version 0.4.0
Use the v0.4.0 GitHub release for this version’s artifacts and checksums. Run sow version after installation, then follow the migration steps above for a 0.3 workspace.
For a new installation today, use the current download page. Current behavior is documented in Managed Workspaces, Signing Model, and Publication & Recovery.
7 - SOW v0.3.0
v0.3.0 ·
SOW 0.3.0 reduced repeated package reads and database queries. Plain generation uses one pass over package content. Managed builds cache parsed package data and commit new pool files in batches. This release also removed retired runtime and publication code.
Plain: read each package once
The default unsigned sow create path hashes and parses each RPM or DEB once. --jobs controls parallel work. SOW renders metadata from the parsed results, then checks that the package set and file attributes still match before writing the indexes.
An interrupted Plain build can be rerun from the package directory. Version 0.3 removed its operation journal, rollback copies, and repeated package hashing; Managed recovery remained unchanged.
Pigsty preprocessing now keeps RPMs whose headers report i386, i486, i586, or i686. They remain in the repository metadata and repo_complete checksum manifest. The DEB i386 and exact Patroni 3.0.4 filters remain in place.
Managed: fewer queries and package reads
Membership tables gained reverse indexes by package SHA-256. SOW now loads Desired and Built membership in one ordered query instead of querying each object. In the project’s benchmark, listing a 5,000-object Dist fell from about 4.1 seconds to 33 milliseconds. A 50,000-object Dist completed in under a second.
Schema v10 added a rebuildable cache of parsed package data, keyed by package SHA-256. Import verifies and parses a new package, then saves the data needed to render its metadata. Builds load this data in batches. Missing or damaged cache entries are rebuilt from verified package files.
For an unchanged pool, warm builds use device, inode, size, modification time, and change time to recognize unchanged files. A changed fingerprint triggers a full SHA-256 check. sow check continues to read and verify the complete package content.
RPM metadata and DEB architecture indexes use bounded --jobs concurrency. Generation manifests and change records are written in batches.
Batch commits and build progress
Managed builds move packages into the public pool in batches of up to 512 objects or 1 GiB. SOW persists each destination directory before removing pending names. Recovery handles an interrupted batch whether a package exists in the pending directory, the pool, or both.
Pending files use their final 0644 mode inside a private 0700 directory. Builds no longer hold a file descriptor for every pending package throughout the operation, which reduces resource use in large repositories.
Long builds write build_progress events for rendering, package promotion, Dist publication, normalization, and finalization. Use sow log to inspect this progress.
One active repository implementation
The release removed the retired V1 CLI and runtime, cloud/CDN publication code, Edge worker, completed migration program, and their obsolete tests. The active CLI uses one repository implementation.
R2 publication keeps the storage operations SOW needs: list, HEAD, GET, and conditional PUT. Remote garbage collection reports candidates without deleting them.
Other changes
- Local garbage collection handles a unique recorded pool-path alias on case-insensitive filesystems. It checks the package path, size, and digest before removal.
- Archives include
LICENSE. RPM and DEB packages install Apache-2.0 license files at/usr/share/licenses/sow/LICENSEand/usr/share/doc/sow/copyright. - CI covers formatting, module consistency, static analysis, dead-code checks, tests, race detection, source delivery, and package builds.
- Integration tests cover mixed RPM/DEB workflows and an unsigned Plain APT installation on Ubuntu 22.04.
They also test DNF signature transitions on AlmaLinux 8/9 and
pgsty/el10, plus conditional S3 operations against a pinned MinIO version.
Get version 0.3.0
Use the v0.3.0 GitHub release for that version’s Linux/macOS archives, Linux RPM/DEB packages, and SHA256SUMS. Run sow version after installation. The source tag requires Go 1.26.5 or newer.
For a new installation today, use the current download page. Current behavior is documented in Plain Mode, Managed Workspaces, and Platforms & Integrations.
8 - SOW v0.2.0
v0.2.0 ·
SOW 0.2.0 introduced Plain and Managed workflows for RPM and DEB repositories. It builds static package repositories with one Go executable on Linux or macOS.
This page describes the 0.2.0 release. Use the current documentation for installation and operations today.
Build a flat repository
Plain mode indexes RPM and DEB files at the top level of a directory:
For RPMs, it writes repodata/. For DEBs, it writes Packages and Packages.gz. A mixed directory gets both. Plain mode uses the directory contents as its state and needs no workspace or database.
The release also added --sign-with to sign unsigned RPM packages. Use --overwrite to replace existing RPM signatures. Plain mode does not generate or sign an APT Release file.
Manage a repository over time
Managed mode records package membership and builds named Dists:
Each Repository stores a package file once under pool/. Its Dists contain RPM or APT metadata under dists/. Builds record generations so SOW can report changes and retain selected repository states.
Version 0.2.0 added:
sow/v3configuration and package membership policies;- metadata signing for RPM and APT, plus RPM package signing;
status,check,changes, and operation logs;- recoverable publication to filesystem and R2 targets;
- retained generations and local garbage collection;
rpm-leafexport for tools that need a standalone RPM directory.
Serve or publish the complete Repository tree so metadata can reach the shared package pool. sow publish manages upload order and recovery for configured targets. R2 cleanup reports candidates without deleting remote objects.
Release testing and source
The release added APT/DNF and S3-compatible integration workflows, plus a tag-driven GoReleaser pipeline for Linux/macOS archives and Linux RPM/DEB packages. Historical code and tests are available under the v0.2.0 source tag.
For the current release, use Download. Current client and storage coverage is listed in Platforms & Integrations.