Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ assignees: ''

## What happened

A clear description of the bug what you expected and what actually happened.
A clear description of the bug: what you expected and what actually happened.

## Environment

Expand All @@ -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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ Other approaches you thought about, and why they fall short.

## Additional context

Anything else links, related issues, or notes on portability across
Anything else: links, related issues, or notes on portability across
Ubuntu/Debian/macOS.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

- [ ] `make lint` (ShellCheck + shfmt) passes locally
- [ ] Changes are portable bash (Ubuntu/Debian and macOS)
- [ ] Docs updated (README / other) if behaviour or options changed
- [ ] Docs updated (README / other) if behavior or options changed
- [ ] PR is focused and ready for review
22 changes: 22 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Keep the SHA-pinned GitHub Actions current. Dependabot bumps the commit pin AND the trailing
# "# vX.Y.Z" comment together, and opens PRs for any security advisories affecting an action we use.
#
# Scope is github-actions ONLY (#117): RigForge is pure shell — no pip, npm, or docker ecosystems
# to track. The XMRig source is pinned by version+commit and verified at build time, not via a
# package manager, so it isn't a Dependabot ecosystem either.
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/" # github-actions ecosystem watches .github/workflows/
schedule:
interval: "weekly"
commit-message:
prefix: "ci" # -> "ci(deps): bump actions/checkout ..."
include: "scope"
labels:
- "infra"
groups:
# One rollup PR for all action bumps rather than one-per-action — low-noise for a repo this small.
github-actions:
patterns:
- "*"
63 changes: 54 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,43 @@ name: CI

on:
push:
branches: [main]
branches: [main, develop] # develop is the integration branch; main is the release branch
pull_request:

# Least privilege: every job here only reads the repo to lint/test/build — nothing publishes or
# writes. Set the floor once at the top so all jobs inherit a read-only GITHUB_TOKEN (zizmor:
# excessive-permissions).
permissions:
contents: read

jobs:
lint-yaml:
name: Lint (yamllint)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
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 All @@ -15,7 +48,9 @@ jobs:
SHFMT_VERSION: "3.13.1"
SHFMT_SHA256: "fb096c5d1ac6beabbdbaa2874d025badb03ee07929f0c9ff67563ce8c75398b1"
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # no pushes from CI; don't leave the token in .git/config (zizmor: artipacked)
# Install PINNED, checksum-verified shellcheck + shfmt instead of the runner's preinstalled
# builds, so lint/format results are reproducible and don't drift with the runner image (#6).
# Downloaded straight from the upstream releases — no `apt-get update`, avoiding the mirror
Expand Down Expand Up @@ -45,7 +80,9 @@ jobs:
name: Test suite
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # zizmor: artipacked
# Ubuntu is RigForge's supported target. The suite still exercises the macOS code path here via
# stubs (OS_TYPE=Darwin + faked sysctl), so the macOS config profile is covered without a Mac
# runner; contributors on macOS can also run `make test` locally. jq is preinstalled on the runner.
Expand All @@ -56,7 +93,9 @@ jobs:
name: Test suite (macOS)
runs-on: macos-14 # Apple silicon; pinned (not macos-latest) to avoid image drift
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # zizmor: artipacked
# The Linux job only SIMULATES macOS (STUB_UNAME_S=Darwin + stubbed sed/launchctl). Here the suite
# runs on real macOS, natively exercising the Darwin paths — BSD `sed` (the donate.h patch), the
# macOS config profile, `mac_*` process control + the launchd login agent, and BSD `tar`/`date`
Expand All @@ -78,7 +117,9 @@ jobs:
name: End-to-end (Docker)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # zizmor: artipacked
# Runs the real script end-to-end inside a disposable Ubuntu container (RigForge's documented
# Linux target), exercising the genuine Linux deploy path and /etc idempotency with real tools.
- name: Run end-to-end suite
Expand All @@ -91,12 +132,16 @@ jobs:
# Pin diff-cover (the patch-coverage gate); kcov + jq are pinned inside tests/coverage.sh.
DIFF_COVER_VERSION: "10.3.0"
PATCH_COVERAGE_MIN: "90" # new/changed lines in rigforge.sh + util must be this % covered
# Diff the PR against the branch it targets (develop or main). On a push, github.base_ref is empty,
# so fall back to the pushed branch itself — that's an empty diff that trivially passes.
BASE_REF: ${{ github.base_ref || github.ref_name }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0 # diff-cover needs history to diff the PR against origin/main
fetch-depth: 0 # diff-cover needs history to diff the PR against its base branch
persist-credentials: false # the fetch below is read-only on a public repo (zizmor: artipacked)
- name: Fetch base branch for diff-cover
run: git fetch --no-tags origin main
run: git fetch --no-tags origin "$BASE_REF"
# Runs tests/run.sh under a digest-pinned kcov image, reports rigforge.sh + util/proposed-grub.sh
# coverage, and fails if the total drops below the committed floor (tests/coverage-floor.txt).
- name: Measure coverage (kcov) + enforce the total floor
Expand All @@ -106,4 +151,4 @@ jobs:
- name: Install pinned diff-cover
run: pipx install "diff-cover==${DIFF_COVER_VERSION}"
- name: Enforce patch coverage on changed lines
run: diff-cover coverage/cobertura.xml --compare-branch=origin/main --fail-under="${PATCH_COVERAGE_MIN}"
run: diff-cover coverage/cobertura.xml --compare-branch="origin/$BASE_REF" --fail-under="${PATCH_COVERAGE_MIN}"
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
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
8 changes: 6 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Releasing goes through `gh` with GH_TOKEN below, not `git push`, so the checkout never
# needs the token left in .git/config (zizmor: artipacked).
persist-credentials: false

- name: Verify the tag matches VERSION
run: |
Expand All @@ -38,7 +42,7 @@ jobs:
stage="rigforge-$TAG"
mkdir -p "$stage"
# Runtime files a user needs to deploy a worker — no tests/, .github/, or dev cruft.
cp -a rigforge.sh util systemd config.json.template config.advanced.example.json README.md docs images LICENSE VERSION "$stage/"
cp -a rigforge.sh util systemd config.minimal.json config.reference.json README.md docs images LICENSE VERSION "$stage/"
zip -rq "$stage.zip" "$stage"
tar -czf "$stage.tar.gz" "$stage"
sha256sum "$stage.zip" "$stage.tar.gz" > SHA256SUMS
Expand Down
75 changes: 75 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Security

# Supply-chain & secrets gates (#117):
# - gitleaks: scan the full git history for committed secrets (pool creds, the stratum
# access-password from #113, tokens) on every push and PR.
# - zizmor: static-audit the GitHub Actions workflows themselves (template injection,
# over-broad GITHUB_TOKEN, unpinned actions, credential persistence) AND cross-reference the
# actions we pin against the GitHub Advisory Database (online audit).
# Dependabot (github-actions) lives in .github/dependabot.yml; the matching gitleaks pre-commit
# hook lives in .pre-commit-config.yaml.

on:
push:
branches: [main, develop] # develop is the integration branch; main is the release branch
pull_request:
# Re-audit main on a schedule so a newly-published advisory against an action we pin trips the gate
# even during quiet periods with no pushes — the online zizmor audit is time-varying by design.
schedule:
- cron: "0 7 * * 1" # Mondays 07:00 UTC

# Both jobs only read the tree to scan it. Pin the floor to read-only (zizmor: excessive-permissions).
permissions:
contents: read

jobs:
gitleaks:
name: Secret scan (gitleaks)
runs-on: ubuntu-24.04
# The weekly tick exists for zizmor's advisory re-audit; history doesn't change between pushes, so
# there's nothing new for gitleaks to scan on a schedule.
if: github.event_name != 'schedule'
env:
# Pinned + checksum-verified, same as the shellcheck/shfmt installs in ci.yml — reproducible and
# immune to runner-image drift. Keep GITLEAKS_VERSION in lockstep with .pre-commit-config.yaml.
GITLEAKS_VERSION: "8.30.1"
GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0 # scan EVERY commit, not just the tip — a secret is still a leak once pushed
persist-credentials: false # zizmor: artipacked
- name: Install pinned gitleaks
run: |
set -euo pipefail
tarball="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${tarball}" -o "$tarball"
echo "${GITLEAKS_SHA256} ${tarball}" | sha256sum -c -
tar -xzf "$tarball" gitleaks
sudo install gitleaks /usr/local/bin/gitleaks
gitleaks version
# Full-history scan with the built-in ruleset. --redact keeps any match out of the public logs;
# the job still fails (non-zero exit) so a leak blocks the merge.
- name: Scan git history for secrets
run: gitleaks git . --redact --no-banner --verbose

zizmor:
name: Workflow audit (zizmor)
runs-on: ubuntu-24.04
env:
ZIZMOR_VERSION: "1.25.2"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # zizmor: artipacked
# pipx is preinstalled on ubuntu-24.04; same install path as diff-cover in ci.yml's coverage job.
- name: Install pinned zizmor
run: pipx install "zizmor==${ZIZMOR_VERSION}"
# Online audits ON (zizmor's default): GH_TOKEN lets the `known-vulnerable-actions` audit query
# the GitHub Advisory Database, so a CVE disclosed against an action we pin fails the gate. The
# built-in token (read-only here) is enough — advisory data is public; it's only for API access.
# This complements Dependabot: zizmor blocks the merge, Dependabot opens the bump.
- name: Audit GitHub Actions workflows
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: zizmor .github/workflows/
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# User-generated config (created from config.json.template)
# User-generated config (created from config.minimal.json)
config.json

# Runtime artifacts
Expand Down
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"
Loading
Loading