Skip to content

unattended-backpack/refine

Refine

Remove the dross from the silver, and a silversmith can produce a vessel.

Refine is an opinionated Rust code formatter. It layers on top of rustfmt to apply small cosmetic adjustments that rustfmt itself cannot express as configuration options.

Refine is not a replacement for rustfmt. Run cargo fmt first, then refine second.

Usage

Refine has two modes:

  • File mode (default) — reads one file (or stdin via -), applies its rules, and writes the result to stdout. The input file is never modified.
  • --all mode — walks the current Cargo workspace (discovered via cargo metadata, honouring .gitignore and .refine_ignore) and rewrites every .rs file in place.
# File mode — formatted output goes to stdout.
refine src/lib.rs
refine src/lib.rs > src/lib.rs.new && mv src/lib.rs.new src/lib.rs
cat src/lib.rs | refine -

# Workspace mode — rewrite every tracked `.rs` file in place.
refine --all

# CI check: fail if --all would change anything.
refine --all
git diff --quiet || { git diff; exit 1; }

# CI check (single file): fail if the formatted output differs.
diff -u src/lib.rs <(refine src/lib.rs)

Options:

--all            Walk the current workspace and rewrite files in place.
--rule <name>    Run only the named rule. Repeatable.
--list-rules     Print every registered rule and exit.
-h, --help       Show help.
-V, --version    Show version.

Exit codes: 0 on success, 1 on I/O or parse errors.

Rules

  • blank-line-before-comment — ensures exactly one blank line precedes every comment block (//, ///, //!, or /* ... */) and any outer attributes that sit directly above it. A "comment block" is a contiguous run of comment lines; attribute lines (#[...]) directly adjoining the block are folded into the same unit so the blank line lands above the whole header rather than between pieces of it. Respects #[rustfmt::skip] and leaves blocks at the top of a file alone.

Integration

Add a recipe to your justfile or Makefile:

fmt:
	cargo +nightly fmt
	refine --all

fmt-check:
	cargo +nightly fmt --check
	refine --all
	git diff --quiet

Adding a new rule

Each rule lives in its own file under src/rules/. To add one:

  1. Create src/rules/my_rule.rs with a struct implementing the Rule trait. Use syn only to locate byte ranges; return Edits that operate on the original source text.
  2. Register the rule in src/rules/mod.rs inside rules().
  3. Add fixture pairs under tests/fixtures/my_rule/ (NN_case.input.rs + NN_case.expected.rs). Extend tests/integration.rs and tests/idempotence.rs to pick up the new fixture directory.
  4. Every rule must be idempotent: running it on its own output must be a no-op. The idempotence test enforces this on every *.expected.rs.

Ignoring files

refine --all honours both .gitignore and .refine_ignore. The latter uses the same syntax as .gitignore but is scoped to refine: use it to exempt files you want tracked in git but not rewritten. This repository ships one that exempts tests/fixtures/ so the fixture harness doesn't get clobbered.

Design notes

  • Refine parses each file with syn for structural information only; it never re-emits the AST. All modifications are textual edits against the original source, which avoids syn's whitespace-loss problem.
  • Edits are collected per-rule, sorted, validated for non-overlap, and applied in descending order so earlier edits don't shift later offsets.
  • Macro invocations and macro_rules! bodies are opaque and not modified.

Building

To build locally, you should simply need to run make; you can see more in the Makefile. This will default to building with the maintainer-provided details from .env.maintainer, which we will periodically update as details change.

You can also build container images using make docker, which uses a BUILD_IMAGE for building dependencies that are packaged to run in a RUNTIME_IMAGE. Configuration values in .env.maintainer may be overridden by specifying them as environment variables, including specific image names.

REFINE_NAME=refine make docker
BUILD_IMAGE=registry.digitalocean.com/sigil/petros:latest make build
RUNTIME_IMAGE=debian:bookworm-slim@sha256:... make build

Runner-Local Secrets

All automated build secrets must be stored on the self-hosted runner at /opt/github-runner/secrets/. These files are mounted read-only into the release workflow container; they are never stored in git.

Required Secrets

GitHub Access Tokens (for creating releases and pushing to GHCR):

  • ci_gh_pat - A GitHub fine-grained personal access token with repository permissions.
  • ci_gh_classic_pat - A GitHub classic personal access token for GHCR authentication.

Registry Access Tokens (for pushing container images):

  • do_token - A DigitalOcean API token with container registry write access.
  • dh_token - A Docker Hub access token.

GPG Signing Keys (for signing release artifacts):

  • gpg_private_key - A base64-encoded GPG private key for signing digests.
  • gpg_passphrase - The passphrase for the GPG private key.
  • gpg_public_key - The base64-encoded GPG public key (included in release notes).

Registry Configuration (registry.env file):

This file contains non-sensitive registry identifiers and build configuration:

# The Docker image to perform release builds with.
# If not set, defaults to unattended/petros:latest from Docker Hub.
# Examples:
#   BUILD_IMAGE=registry.digitalocean.com/sigil/petros:latest
#   BUILD_IMAGE=ghcr.io/your-org/petros:latest
#   BUILD_IMAGE=unattended/petros:latest
BUILD_IMAGE=unattended/petros:latest

# The runtime base image for the final container.
# If not set, uses the value from from .env.maintainer.
# Example:
#   RUNTIME_IMAGE=debian:trixie-slim@sha256:66b37a5078a77098bfc80175fb5eb881a3196809242fd295b25502854e12cbec
RUNTIME_IMAGE=debian:trixie-slim@sha256:66b37a5078a77098bfc80175fb5eb881a3196809242fd295b25502854e12cbec

# The name of the DigitalOcean registry to publish the built image to.
DO_REGISTRY_NAME=

# The username of the Docker Hub account to publish the built image to.
DH_USERNAME=unattended

Public Configuration

Public configuration that anyone building this project needs is stored in the repository at .env.maintainer:

  • REFINE_NAME - The published name for the Refine image.
  • BUILD_IMAGE - The builder image for compiling Rust code (default: unattended/petros:latest).
  • RUNTIME_IMAGE - The runtime base image (default: pinned debian:trixie-slim@sha256:...).

This file is version-controlled and updated by maintainers as infrastructure details change.

Verifying Release Artifacts

All releases include GPG-signed artifacts for verification. Each release contains:

  • image-digests.txt - A human-readable list of all container image digests.
  • image-digests.txt.asc - A GPG signature for the digest list.
  • Per-image manifests and signatures for each built image:
    • <image>-ghcr-manifest.json / <image>-ghcr-manifest.json.asc - GitHub Container Registry OCI manifest and signature.
    • <image>-dh-manifest.json / <image>-dh-manifest.json.asc - Docker Hub OCI manifest and signature.
    • <image>-do-manifest.json / <image>-do-manifest.json.asc - DigitalOcean Container Registry OCI manifest and signature.

Quick Verification

Download the artifacts and verify signatures:

# Import the GPG public key (base64-encoded in release notes).
echo "<GPG_PUBLIC_KEY>" | base64 -d | gpg --import

# Verify digest list.
gpg --verify image-digests.txt.asc image-digests.txt

# Verify image manifests for each image.
gpg --verify <image>-ghcr-manifest.json.asc <image>-ghcr-manifest.json
gpg --verify <image>-dh-manifest.json.asc <image>-dh-manifest.json
gpg --verify <image>-do-manifest.json.asc <image>-do-manifest.json

Manifest Verification

The manifest files contain the complete OCI image structure (layers, config, metadata). You can use these to verify that a registry hasn't tampered with an image.

# Pull the manifest from the registry.
docker manifest inspect ghcr.io/unattended-backpack/...@sha256:... \
  --verbose > registry-manifest.json

# Compare to the signed manifest.
diff ghcr-manifest.json registry-manifest.json

This provides cryptographic proof that the image structure (all layers and configuration) matches what was signed at release time.

Cosign Verification

Images are also signed with cosign using GitHub Actions OIDC for keyless signing. This provides automated verification and build provenance.

To verify with cosign:

# Verify image signature (proves it was built by our workflow).
cosign verify ghcr.io/unattended-backpack/...@sha256:... \
  --certificate-identity-regexp='^https://github.com/unattended-backpack/.+' \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com

Cosign verification provides:

  • Automated verification (no manual GPG key management).
  • Build provenance (proves image was built by the GitHub Actions workflow).
  • Registry-native signatures (stored alongside images).

Note: Cosign depends on external infrastructure (GitHub OIDC, Rekor). For maximum trust independence, rely on the GPG-signed manifests as your ultimate root of trust.

Local Testing

This repository is configured to support testing the release workflow locally using the act tool. There is a corresponding goal in the Makefile, and instructions for further management of secrets here. This local testing file also shows how to configure the required secrets for building.

Security

If you discover any bug; flaw; issue; dæmonic incursion; or other malicious, negligent, or incompetent action that impacts the security of any of these projects please responsibly disclose them to us; instructions are available here.

License

The license for all of our original work is LicenseRef-VPL WITH AGPL-3.0-only. This includes every asset in this repository: code, documentation, images, branding, and more. You are licensed to use all of it so long as you maintain maximum possible virality and our copyleft licenses.

Permissive open source licenses are tools for the corporate subversion of libre software; visible source licenses are an even more malignant scourge. All original works in this project are to be licensed under the most aggressive, virulently-contagious copyleft terms possible. To that end everything is licensed under the Viral Public License coupled with the GNU Affero General Public License v3.0 for use in the event that some unaligned party attempts to weasel their way out of copyleft protections. In short: if you use or modify anything in this project for any reason, your project must be licensed under these same terms.

For art assets specifically, in case you want to further split hairs or attempt to weasel out of this virality, we explicitly license those under the viral and copyleft Free Art License 1.3.

About

Remove the dross from the silver, and a silversmith can produce a vessel.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors