Manifest Reference
The manifest tells rmqa what every release must contain. It’s a small TOML file, rmqa.toml by default, kept next to your code. rmqa init writes a first version from a release you know is good; this page covers every setting, every command and every finding code.
An Example
This is the manifest rmqa uses for its own releases:
project = "rmqa"
version_file = "VERSION" # or version = "1.4.2", or --version on the command line
[[platform]]
os = "linux"
arch = "amd64"
[[platform]]
os = "linux"
arch = "arm64"
[[platform]]
os = "darwin"
arch = "arm64"
[[platform]]
os = "darwin"
arch = "amd64"
[[platform]]
os = "windows"
arch = "amd64" # archive = "zip" and exe = ".exe" are the Windows defaults
[[artifact]]
name = "rmqa_{os}_{arch}.{archive}" # one archive per platform
binaries = ["rmqa{exe}"] # the program inside, checked against the platform
files = ["LICENSE", "NOTICE", "THIRD_PARTY_LICENSES.md", "README.md", "CHANGELOG.md"]
run = ["version"] # run it where it can run, and look for the version
min_size = 500000
[[artifact]]
name = "SHA256SUMS"
checksums = "sha256" # must list every other file, with the right hash
Platforms
Each [[platform]] needs os and arch in Go’s spelling
(linux, darwin, windows, freebsd; amd64, arm64, 386, arm,
riscv64, and universal for a macOS universal binary). Any other string
in a platform becomes a template variable, so names that spell platforms
their own way still fit:
[[platform]]
os = "darwin"
arch = "amd64"
target = "x86_64-apple-darwin" # use as {target}
[[artifact]]
name = "tool-{version}-{target}.tar.gz"
Template Variables
Template variables, in names, file lists and binaries, are {version},
{project}, {os}, {arch}, {archive} (tar.gz, or zip on Windows),
{exe} (.exe on Windows, empty elsewhere) and any variables your
platforms define. An artifact whose name uses a platform variable is
expected once for every platform.
Artifact Settings
| Setting | Meaning |
|---|---|
name |
File name, with template variables. Required. |
files |
Files that must be inside the archive and not empty. Patterns such as licenses/* work. |
binaries |
Programs inside the archive. rmqa checks that each is a real executable for the artifact’s platform, that it’s marked executable, and that it contains the version. |
binary = true |
The file itself is the program, for releases that ship bare executables. |
run |
Arguments that make the program print its version, such as ["--version"]. rmqa runs it when it fits the machine rmqa runs on, and skips it otherwise. |
check_version = false |
Don’t look for the version string inside the programs. |
root |
"auto" (default) removes one folder that wraps everything; "none" keeps paths as they are; or a template such as "tool-{version}-{os}" that must match exactly. |
checksums |
"sha256" or "sha512": this file lists checksums of the other files. |
min_size, max_size |
Size limits in bytes. |
optional = true |
Missing is fine. |
only |
For per-platform artifacts that exist for some platforms only, for example ["linux/*"]. |
Top-Level Settings
The top-level settings are project, version, version_file (read relative
to the manifest), extra_files ("error" by default, or "warn" or
"ignore") for files in the release that the manifest doesn’t mention, and
forbid, a list of patterns that must never be inside an archive. The
default forbid list catches .env, *.pem, *.key, id_rsa,
id_ed25519, .git/*, .npmrc and .pypirc.
The version comes from, in order: --version, the RMQA_VERSION
environment variable, version_file, version, and for --github the
release tag. A leading v is dropped.
rmqa reads the parts of TOML a manifest needs: tables, arrays of tables, strings, whole numbers, booleans and lists. Anything else, and any unknown setting, is an error with its line number, so a typo can’t quietly switch a check off.
Commands
rmqa check [DIR] check the release files in DIR (default: dist)
rmqa init [DIR] write a manifest from a release that is known to be good
rmqa inspect FILE... show what is inside archives and programs
rmqa version print the rmqa version
check options: --manifest FILE, --version V, --github OWNER/REPO[@TAG],
--format text|json|github|markdown, --strict (fail on warnings too),
--verbose (show notes), --no-run (never run the programs).
init options: --project NAME, --version V, --github OWNER/REPO[@TAG],
-o FILE (it won’t overwrite an existing file). The manifest it writes is
checked against the release it came from before it’s printed.
--format github prints each problem as a GitHub Actions annotation, and
writes a summary table to the job summary when $GITHUB_STEP_SUMMARY is set.
--format json gives the full result for your own scripts.
rmqa reads .tar.gz, .tgz, .tar.bz2, .tar, .zip and .gz archives.
Other files, such as .deb, .msi or .dmg, can be listed in the manifest
and are checked for presence, size and checksums, but not opened.
Finding Codes
Every finding has a stable code, so scripts can match on it.
| Code | Severity | What happened |
|---|---|---|
missing-artifact |
error | A file the manifest expects is not in the release. |
extra-file |
error (configurable) | A file in the release that the manifest doesn’t mention. |
empty-file |
error | A release file, a required file or a program is 0 bytes. |
size-out-of-range |
error | Outside min_size or max_size. |
archive-corrupt |
error | The archive can’t be read to the end: cut off, damaged, or too large to be real. |
unsupported-archive |
error | Files were listed for an archive type rmqa can’t open. |
archive-layout |
error | The archive isn’t laid out as root says. |
unsafe-path |
error | An entry would unpack outside the target folder: .., an absolute path, or a link out. |
forbidden-file |
error | A file matching forbid, such as .env or a private key. |
junk-file |
warning | Clutter such as .DS_Store or __MACOSX/. |
missing-file |
error | A file listed in files is not in the archive. |
missing-binary |
error | A program listed in binaries is not in the archive, or is only a link. |
not-executable |
error | The program isn’t an ELF, Mach-O or PE executable (a script, a text file, a damaged build). |
wrong-os |
error | The program was built for another operating system. |
wrong-arch |
error | The program was built for another processor. |
duplicate-binary |
error | Two platforms’ downloads hold the same program, byte for byte. |
no-exec-bit |
error | The program isn’t marked executable in a tar archive. |
exec-bit-unknown |
warning | A zip made on Windows stores no Unix permissions, so the program won’t be executable after unpacking on Linux or macOS. |
version-missing |
error | The program doesn’t contain the version string. |
version-run-mismatch |
error | Running the program failed, or what it printed doesn’t contain the version. |
checksum-mismatch |
error | A checksum doesn’t match its file. |
checksum-missing-entry |
error | A release file has no checksum. Signature files (.sig, .asc, .pem, sigstore bundles) are exempt. |
checksum-stale-entry |
error | A checksum for a file that isn’t in the release. |
checksum-format |
error | A line of the checksums file can’t be read, or a hash has the wrong length. |
run-skipped |
note | The program wasn’t run because it’s for another platform. |
optional-missing |
note | An optional file isn’t in this release. |
version-unknown |
note | No version was given, so programs weren’t checked for one. |
The Version Check
rmqa looks for the version string inside each
program. It won’t accept 1.4.2 inside 11.4.2 or 1.4.2.1, but it will
accept it when a digit follows, because compilers pack strings end to end
with nothing between them. So a build of 1.4.20 would pass a check for
1.4.2. Running the program with run closes that gap on the platforms
your machine can run.