Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# EditorConfig — https://editorconfig.org. Encodes RigForge's house style so editors match CI
# (shfmt -i 4, yamllint, markdownlint) without per-editor setup.
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

# Shell is the core of the repo: 4-space indent, matching `shfmt -i 4` (see the Makefile lint target).
[*.sh]
indent_size = 4

# Make needs real tabs in recipes.
[Makefile]
indent_style = tab

# YAML and JSON conventionally use 2-space indent.
[*.{yml,yaml,json,json.template}]
indent_size = 2

# In Markdown, two trailing spaces is a hard line break — don't strip it.
[*.md]
trim_trailing_whitespace = false
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ A clear description of the bug — what you expected and what actually happened.

Relevant output from the setup script and/or the miner. On Linux:

```
```bash
sudo journalctl -u xmrig --no-pager | tail -n 50
```

<details>
<summary>Logs</summary>

```
```text
paste logs here
```

Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,33 @@ permissions:
contents: read

jobs:
lint-yaml:
name: Lint (yamllint)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false # zizmor: artipacked
# pipx is preinstalled on ubuntu-24.04 (same path as diff-cover/zizmor); pin the version so the
# ruleset can't drift with the runner image.
- name: Install pinned yamllint
run: pipx install "yamllint==1.38.0"
# Via `make lint-yaml` so the file set + .yamllint config live in one place and can't drift from local.
- name: Run yamllint (make lint-yaml)
run: make lint-yaml

lint-md:
name: Lint (markdownlint)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false # zizmor: artipacked
# node is preinstalled on ubuntu-24.04; `make lint-md` runs the version-pinned markdownlint-cli2
# via npx, reading .markdownlint-cli2.yaml — same invocation as local.
- name: Run markdownlint (make lint-md)
run: make lint-md

lint:
name: Lint (shellcheck + shfmt)
runs-on: ubuntu-24.04
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Links

# Link-checking the docs is kept OFF the PR path on purpose: external links are flaky-by-nature
# (rate limits, transient downtime) and shouldn't block unrelated PRs (#118). Instead it runs on a
# weekly schedule against the default branch, plus on demand via the Actions tab. Run it locally any
# time with `make lint-links`.
on:
schedule:
- cron: "0 6 * * 1" # Mondays 06:00 UTC
workflow_dispatch:

permissions:
contents: read

jobs:
lychee:
name: Link check (lychee)
runs-on: ubuntu-24.04
env:
# Pinned + checksum-verified, like the gitleaks/shellcheck installs. Keep in lockstep with the
# version `make lint-links` expects locally.
LYCHEE_VERSION: "0.24.2"
LYCHEE_SHA256: "1f4e0ef7f6554a6ed33dd7ac144fb2e1bbed98598e7af973042fc5cd43951c9a"
# lychee uses GITHUB_TOKEN to make authenticated GitHub requests and dodge the anon rate limit.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false # zizmor: artipacked
- name: Install pinned lychee
run: |
set -euo pipefail
tarball="lychee-x86_64-unknown-linux-gnu.tar.gz"
curl -fsSL "https://github.com/lycheeverse/lychee/releases/download/lychee-v${LYCHEE_VERSION}/${tarball}" -o "$tarball"
echo "${LYCHEE_SHA256} ${tarball}" | sha256sum -c -
tar -xzf "$tarball"
sudo install "lychee-x86_64-unknown-linux-gnu/lychee" /usr/local/bin/lychee
lychee --version
# Via `make lint-links` so the file set + .lychee.toml config are the same locally and in CI.
- name: Link-check docs (make lint-links)
run: make lint-links
12 changes: 12 additions & 0 deletions .lychee.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# lychee link-checker config for RigForge docs. Run locally via `make lint-links`; in CI it runs on
# a weekly schedule (external links are flaky-by-nature, so link-checking doesn't gate PRs).
max_retries = 3
retry_wait_time = 2
timeout = 20

# GitHub is the main rate-limiter; CI passes a GITHUB_TOKEN so authenticated requests dodge the
# anonymous limit. Still accept 429 so a transient rate-limit on some other host can't fail the run.
accept = ["200..=299", "429"]

# Some hosts reject non-browser user agents; present a common one.
user_agent = "Mozilla/5.0 (compatible; lychee/0.24; +https://github.com/lycheeverse/lychee)"
30 changes: 30 additions & 0 deletions .markdownlint-cli2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# markdownlint-cli2 config for RigForge docs. Run via `make lint-md`.
# Structural rules (blank lines around headings/lists/fences, code-fence languages, heading levels)
# are kept and the docs fixed to satisfy them; purely stylistic rules that fight the repo's
# deliberate house style are turned off below.
config:
default: true
# Long, deliberate prose/command lines — length is a review concern, not a linter one.
MD013: false
# Inline HTML is used on purpose: <details> in issue templates, <img>/badges in the README.
MD033: false
# Bold lead-ins like **HugePages** are inline labels, not headings.
MD036: false
# Templates and partials legitimately don't open with a top-level H1.
MD041: false
# Adjacent-but-separate blockquote callouts are intentional; don't force them to merge.
MD028: false
# Table pipe-spacing is cosmetic; the existing tables are readable and consistent as written.
MD060: false
# Keep-a-Changelog repeats "### Added"/"### Fixed" across version sections — allow non-sibling dups.
MD024:
siblings_only: true
# The repo uses *asterisk* emphasis and **asterisk** strong consistently.
MD049:
style: asterisk
MD050:
style: asterisk
globs:
- "**/*.md"
ignores:
- "node_modules"
29 changes: 25 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,33 @@
# pipx install pre-commit # or: pip install pre-commit
# pre-commit install
#
# Scope here is the secret-scanning gate from #117: gitleaks, pinned to the SAME version CI runs
# (.github/workflows/security.yml) so local catches a leak before it's ever pushed. The broader
# hook set — shellcheck, shfmt, yamllint, markdownlint, and the freebies — is tracked in #118 and
# will be added to this file, keeping the Makefile's SHELL_FILES the source of truth.
# Local == CI: the shell hook calls `make lint`, so the Makefile's SHELL_FILES stays the single
# source of truth (no duplicated file list here). gitleaks is pinned to the same version CI runs
# (.github/workflows/security.yml). The config/docs linters (yamllint, markdownlint, lychee) aren't
# commit-time hooks — run them with `make lint-yaml` / `make lint-md` / `make lint-links`; they gate
# in CI.
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1 # keep in lockstep with GITLEAKS_VERSION in .github/workflows/security.yml
hooks:
- id: gitleaks

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: detect-private-key
- id: check-added-large-files
- id: end-of-file-fixer
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md] # two trailing spaces is a hard line break in Markdown

- repo: local
hooks:
# Reuse `make lint` rather than re-listing files, so shellcheck/shfmt run over the exact same
# SHELL_FILES set as CI and `make lint`. Requires shellcheck + shfmt on PATH (see CONTRIBUTING).
- id: make-lint
name: shellcheck + shfmt (make lint)
entry: make lint
language: system
files: \.sh$
pass_filenames: false
18 changes: 18 additions & 0 deletions .yamllint
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# yamllint config for RigForge, tuned to the repo's house style rather than yamllint's strict
# defaults: workflows carry long, deliberate explanatory comments, and inline comments use a single
# leading space (the same `key: value # note` style as the shell code). Run via `make lint-yaml`.
extends: default

rules:
# The workflows intentionally wrap explanation into long inline comments; enforcing 80 cols here
# would mean butchering them. Length is already governed by review, not a linter.
line-length: disable
# Single-document files — the leading `---` adds nothing, so don't require it.
document-start: disable
comments:
# Match the repo style of one space before an inline comment (yamllint defaults to two).
min-spaces-from-content: 1
truthy:
# Don't flag GitHub Actions' `on:` key as a "truthy" value.
check-keys: false
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to RigForge are documented here. The format is based on
## [Unreleased]

### Added

- **Supply-chain & secret-scanning CI gates (#117).** Three cross-cutting hardening gates on top of
the existing SHA-pinned actions and commit-verified XMRig build:
- **gitleaks** — a new `Security` workflow scans the full git history for committed secrets (pool
Expand All @@ -22,10 +23,22 @@ All notable changes to RigForge are documented here. The format is based on
Advisory Database. Runs on push/PR plus a weekly schedule, so a CVE disclosed against a pinned
action trips the gate even with no open PRs. Hardened the existing `ci.yml`/`release.yml` to a
read-only default token and `persist-credentials: false` on checkout to make the audit clean.
- **DX glue + config/docs lint (#118).** Rounds out the non-shell tooling around the existing
shellcheck/shfmt + kcov core:
- **`.editorconfig`** — encodes the whitespace house style (`shfmt -i 4`, LF, final newline) so
editors match CI without per-editor setup.
- **pre-commit** — `.pre-commit-config.yaml` now orchestrates `make lint` (shellcheck/shfmt via the
Makefile's `SHELL_FILES`, no duplicated list), the existing gitleaks hook, and freebie hygiene
hooks (private-key detection, large-file guard, end-of-file + trailing-whitespace fixers).
- **yamllint + markdownlint** — new CI gates (and `make lint-yaml` / `make lint-md`) over the
workflows/configs and the docs, each with a tuned config (`.yamllint`, `.markdownlint-cli2.yaml`).
- **lychee** — a link-checker (`make lint-links`) that runs on a weekly schedule rather than per-PR,
since external links are flaky-by-nature.

## [1.0.1] - 2026-06-13

### Fixed

- **HugePage sizing is now NUMA-aware (1 GB pages) (#111).** RandomX fast mode keeps a NUMA-local copy of the
~2080 MB dataset **per NUMA node**, but the reservation math multiplied the per-dataset 1 GB pages by the
**socket** count, not the NUMA-node count. On a single-socket, multi-NUMA CPU — e.g. an EPYC 7642 with 4
Expand Down Expand Up @@ -99,6 +112,7 @@ The full walkthrough — prerequisites, the Linux reboot, and verification — i
<summary><strong>Full 1.0.0 feature list</strong> — every capability and hardening that went into this release</summary>

#### Added

- **Privacy & security, documented up front (#109).** A new README "Privacy & security" section and a
SECURITY.md "What RigForge exposes (and what it doesn't)" section state it plainly: **no telemetry** (the
only outbound traffic is your pool, the commit-verified XMRig clone, and your distro's package mirrors);
Expand Down Expand Up @@ -324,6 +338,7 @@ The full walkthrough — prerequisites, the Linux reboot, and verification — i
Release with `.zip`/`.tar.gz` deploy bundles, `SHA256SUMS`, and changelog-derived notes (#3, #36).

#### Changed

- **Live auto-tuning converges in one run.** Each `autotune` run **live-sweeps every prefetch mode**
against the running miner and adopts the fastest (median measurement + a margin gate, else it keeps the
current mode), converging in a single ~minutes-long pass. The safety-net timer fires **monthly** by
Expand Down Expand Up @@ -389,6 +404,7 @@ The full walkthrough — prerequisites, the Linux reboot, and verification — i
fixes across the docs.

#### Fixed

- **`setup` re-run now applies your `config.json` edits (#109).** On a no-rebuild re-run, the regenerated
config was written to the worker root instead of the build directory the service loads
(`--config=$BUILD_DIR/config.json`), so an edit-then-`setup` silently kept mining the old config. setup
Expand Down
25 changes: 21 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,34 @@ RigForge is portable Bash that has to run on Ubuntu/Debian and macOS, so:
`shfmt` formatting.)
- Update the README or other docs when you change behaviour or add options.

## Secret scanning
## Pre-commit hooks

CI runs [gitleaks](https://github.com/gitleaks/gitleaks) over the full history on every push and PR,
so an accidentally committed token or pool credential blocks the merge. Catch it locally first by
installing the pre-commit hook (it runs the same pinned gitleaks on staged changes):
Install the hooks once and they run on every commit, catching issues before they reach CI:

```bash
pipx install pre-commit # or: pip install pre-commit
pre-commit install
```

This runs `make lint` (ShellCheck + shfmt over the Makefile's `SHELL_FILES`),
[gitleaks](https://github.com/gitleaks/gitleaks) secret scanning (the same pinned version CI runs, so
a committed token or pool credential is caught before it's pushed), and a few hygiene checks
(private-key detection, a large-file guard, final-newline and trailing-whitespace fixers).

### Config & docs linting

The YAML, Markdown, and link checks gate in CI and have matching Make targets for local runs:

```bash
make lint-yaml # yamllint the workflows + configs (.yamllint)
make lint-md # markdownlint the docs (.markdownlint-cli2.yaml; needs node)
make lint-links # lychee link-check the docs (.lychee.toml; needs lychee — runs weekly in CI)
make lint-all # shell + yaml + markdown in one go
```

An [`.editorconfig`](./.editorconfig) encodes the whitespace conventions (`shfmt -i 4`, LF, final
newline) so most editors match these checks automatically.

## Branching

RigForge uses a two-branch model (same as [Pithead](https://github.com/p2pool-starter-stack/pithead)):
Expand Down
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# Local test entry points (mirror the GitHub Actions CI jobs).
.PHONY: help test test-suite test-e2e test-e2e-macos smoke coverage e2e-real lint fmt
.PHONY: help test test-suite test-e2e test-e2e-macos smoke coverage e2e-real lint fmt lint-yaml lint-md lint-links lint-all

SHELL_FILES = rigforge.sh util/proposed-grub.sh tests/run.sh tests/e2e/linux.sh tests/e2e/in-container.sh tests/e2e/macos.sh tests/smoke.sh tests/coverage.sh tests/e2e-real.sh

# Config/docs lint file sets, derived from what's tracked so CI and local stay in sync (like SHELL_FILES).
YAML_FILES = $(shell git ls-files '*.yml' '*.yaml')
MD_FILES = $(shell git ls-files '*.md')
MARKDOWNLINT_VERSION = 0.22.1

# Keep `make` (no target) running the default dev check; `make help` lists every target.
.DEFAULT_GOAL := test

Expand Down Expand Up @@ -35,3 +40,14 @@ lint: ## shellcheck + shfmt (check) the script, utilities, and test scripts

fmt: ## auto-format all shell scripts with shfmt (resolves shfmt lint failures)
shfmt -i 4 -w $(SHELL_FILES)

lint-yaml: ## yamllint the YAML (workflows, dependabot, configs) — uses .yamllint, strict
yamllint --strict $(YAML_FILES)

lint-md: ## markdownlint the docs — uses .markdownlint-cli2.yaml (needs node/npx)
npx --yes markdownlint-cli2@$(MARKDOWNLINT_VERSION) $(MD_FILES)

lint-links: ## lychee link-check the docs — uses .lychee.toml (needs lychee; hits external links)
lychee $(MD_FILES)

lint-all: lint lint-yaml lint-md ## run every fast linter (shell + yaml + markdown; not the link check)
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# RigForge

### Provision a hardware-tuned XMRig miner in one command.
<h3 align="center">Provision a hardware-tuned XMRig miner in one command</h3>

[![CI](https://github.com/p2pool-starter-stack/rigforge/actions/workflows/ci.yml/badge.svg)](https://github.com/p2pool-starter-stack/rigforge/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
Expand Down Expand Up @@ -198,7 +198,9 @@ For how RigForge is versioned and released, see [RELEASING.md](./RELEASING.md) a

If RigForge saved you time and you'd like to support it, donations to this XMR wallet are appreciated:

486aGn4qhH1MkaASjnEWMDN7stD1SVtPF5fvihmjffeBE5ACL1u1jU95KxiqmoiaPZMexi4R4W11MLXut66XWVVF8wjAE5R
```text
486aGn4qhH1MkaASjnEWMDN7stD1SVtPF5fvihmjffeBE5ACL1u1jU95KxiqmoiaPZMexi4R4W11MLXut66XWVVF8wjAE5R
```

---

Expand Down
Loading