Skip to content

release: v1.14.0#764

Merged
VijitSingh97 merged 26 commits into
mainfrom
develop
Jul 24, 2026
Merged

release: v1.14.0#764
VijitSingh97 merged 26 commits into
mainfrom
develop

Conversation

@VijitSingh97

Copy link
Copy Markdown
Collaborator

Release merge for v1.14.0 — published at v1.14.0, tag commit 4285d37 (= develop HEAD; nothing landed after the cut, so this is a straight develop→main merge).

Real merge, never squash — main must stay an ancestor of develop.

In this release

Pre-cut verification

Ponytail review: release merge of already-reviewed commits, no new code — nothing to cut.

🤖 Generated with Claude Code

VijitSingh97 and others added 26 commits July 22, 2026 23:26
back-merge: main → develop after v1.13.0
The ratified architecture decision record for shipping Pithead through
three channels from one release manifest: curl-installed Compose stack,
flashable immutable appliance (Debian 13 + Rugix A/B, Podman Quadlet),
and git clone. Records the rejected alternatives (bootc, Podman
everywhere, apt channel) with evidence, the appliance mechanics (commit
gate, migration-deadlock rule, Tor-routed updates, two-tier reset), the
phase 0 go/no-go gates, and the risk register.

Dev doc only — no behaviour change. Sequencing lives in #394.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ution-releases-9bdf8c

docs(dev): dual-distribution plan — the #77/#78 ADR
Add `tari.mode: remote`, mirroring the existing Monero remote-node mode, so
operators can merge-mine against an external Tari base node instead of the
bundled container — offloading Tari's RAM and ~170 GiB of disk, and letting one
node serve several stacks (each with its own wallet; the mining-template gRPC is
request-scoped).

- config: `tari.remote.host` (required in remote mode) + `tari.remote.grpc_port`
  (default 18142); `tari.mode` gets an explicit local/remote validation.
- render: pithead renders TARI_GRPC_ADDRESS for both modes; `local_tari` compose
  profile gates the bundled tari container (mirrors monerod's `local_node`).
  Remote mode skips the Tari mem-limit calc, refuses tari.view_key (payout
  confirmation is local-only), and drops the Tari/Monero disk budget from
  doctor/preflight (was demanding the full chain budget on the small-disk hosts
  remote mode exists for — the Monero side was a pre-existing sibling bug).
- compose: p2pool `--merge-mine`, the dashboard, and the (profile-gated) payout
  wallet all read TARI_GRPC_ADDRESS; p2pool's depends_on is dropped since both
  nodes can be profiled off in remote mode.
- security: charset-guard monero.remote.host / tari.remote.host (and their ports)
  with the existing is_valid_host/is_valid_port — a comma in the host would
  otherwise inject socat address options in the p2pool bridge command. The
  central control-char guard already covered newline .env-injection.
- docs: "Remote Tari node" section + trust boundary (plaintext, unauthenticated
  gRPC — use a trusted/LAN/WireGuard node; a malicious node can redirect Tari
  rewards, Monero mining unaffected); privacy.md clearnet-egress + DNS notes.

Tier-1 coverage in tests/stack/ for render, profile gating, disk budget, the
validation guards, and compose resolution with local_tari omitted. Live
different-machine e2e folds into the release e2e per the feasibility verdict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… node values

Follow-up hardening + wiring cleanup on the remote-node path, from an
injection-surface audit of the whole config→sink chain.

- assert_safe_dir: reject ':' in a data dir. It renders unquoted into the
  compose bind-mount short syntax (${MONERO_DATA_DIR}:/dest), so a dir ending
  ':ro' forged a third MODE field — flipping a data mount read-only or breaking
  `compose up`. Operator-set but, since #728, also dashboard-committable.
- tari.wallet_address: reject the untouched placeholder and any embedded
  whitespace — both cause the silent mine-to-nowhere that monero.wallet_address
  already guards against (#250). No exact-format gate: Tari addresses come in
  base58 AND emoji forms (RFC-0155), so a strict regex would false-reject valid
  addresses; the node rejects a subtler typo at merge-mine time.
- render_env: reuse the parse-time validated remote host/port globals
  (MONERO_REMOTE_*, TARI_REMOTE_*) instead of re-reading them from config.json.
  Removes six duplicate jq reads and the drift risk of validating one value and
  rendering another — the validated value is now the rendered value.

Tier-1 tests for all three. The .env newline-injection vector an earlier review
raised was already closed by the central control-char guard, so no change there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Internal GitHub #NNN references carry no meaning for an operator reading a
warning, an error, the apply preview, or the dashboard — they read as noise.
Remove them from user-facing product strings while keeping the explanatory
prose intact. Comments and test labels keep their #NNN (developer-facing).

- pithead: strip #NNN from log/warn/error/info/echo messages, the --help command
  descriptions, and describe_change's msg= apply-preview text (which the #33
  control channel also renders in the dashboard config editor). Grammar
  preserved; load-bearing words kept (e.g. "removed in v1.9" stays, only the
  "#506," goes). Also dropped a stale "v1.6" reference while there.
- dashboard: chart.mjs "Avg:" control tooltip.
- Regression guard: scripts/lint-operator-strings.sh (wired into `make lint` and
  CI) fails if a #NNN reaches a pithead message or a dashboard frontend string;
  it exempts comments and CSS hex colours. Documented in CONTRIBUTING.md.

Telegram, webhook, and ntfy message bodies were already clean (issue refs there
live only in docstrings). No behaviour change. Stack suite 1622/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The guard's frontend scanner is non-trivial awk (comment-stripping + CSS
hex-colour skip); a silent regression would make it stop catching leaks while
still exiting 0. Extract the two scanners into functions and add a `--self-test`
mode that drives fixtures through them — planted #NNN must be flagged, hex
colours and comments must not. Wired into the stack suite (make test-stack/CI).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…up guard

Follow-ups from the PR review pass:

- Clear MONERO_REMOTE_*/TARI_REMOTE_* to empty before the mode branch, so the
  "globals reflect only the current config" invariant holds even if a caller
  ever parses twice in one process (each real apply is a fresh process, so this
  is defensive, not a live bug).
- Rename TARI_REMOTE_PORT -> TARI_REMOTE_GRPC_PORT to match the config key
  (tari.remote.grpc_port) and Monero's MONERO_REMOTE_*_PORT convention.
- Drop the redundant tari.wallet_address placeholder check — the shared
  template-placeholder guard right below already covers it; keep only the unique
  whitespace check. Test updated to assert the shared message.
- Scrub the three new operator-facing (#103) strings (the view-key error and the
  two node-switch preview messages) so they conform to the operator-strings
  convention #755 enforces, avoiding a straggler once both land.

Stack suite 1652/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mote-tari

feat(tari): remote Tari base-node mode (#103)
…rub-issue-numbers

chore: scrub internal issue/PR numbers from operator-facing text (#755)
The help line dated from when 'git pull' was the only update path; upgrade
is also what the extracted release bundle and the dashboard's one-click
upgrade run. Say so, and name the re-render step it performs first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs(cli): upgrade help text covers the bundle path
…r, testing plan

Three additions to the dual-distribution ADR from the runtime-independence
review:

- A "Runtime port surface" section: the three engine-neutral contracts
  (OCI images by digest, four container-API endpoints behind the proxy
  allowlists, config.json as the only path to runtime files), the four-item
  engine-specific residue, and the review rule that a PR growing the
  surface updates the section.
- Phase 2: doctor grows engine-aware host checks — its Docker-shaped trio
  (daemon reachable, docker group, boot persistence) misreports under
  Podman/systemd, and doctor --json is the appliance commit gate.
- A testing plan mapped onto the existing four-tier model: the parity
  test's derivation mechanics and closed-set lock at tier 1, a Podman
  lane for the tier-3 mini-stack, the appliance tier-4 matrix additions,
  and the installer smoke on the release checklist.
- One-line manifest note: image ownership is per-service (the Tari node
  already pins from a foreign registry).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ort-surface

docs(dev): plan amendments — runtime port surface, engine-aware doctor, testing plan
#103)

With monero.mode or tari.mode set to remote the bundled node container never
starts, but torrc still defined its inbound hidden service — so Tor published
an onion address that accepted connections into nothing.

Each node's HiddenService block moves out of the template and into the tor
entrypoint, appended only when that node's compose profile is active. The gate
is the profile list itself, passed through to the tor container from pithead's
rendered .env, so it cannot drift from which nodes actually run. P2Pool's onion
stays unconditional — p2pool always runs.

pithead follows suit: provision_tor waits only for the onions that will exist,
doctor reports a remote node's missing address as expected rather than a
warning, and the "fully provisioned" guard keys off P2Pool's onion instead of
Monero's. A stack first set up in remote mode has no address for that node, so
provision_node_onions mints and captures it on the apply/upgrade that makes the
node local — before the node container starts against it, since monerod
templates anonymous-inbound from that value.

Covered at tier 1 (torrc gating, provisioning by mode, doctor's report), tier 2
(the profile list reaches the tor service), and tier 3 (the live torrc matches
the node mode).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…okup

Ponytail review: same behaviour, half the lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both callers take the default; speculative flexibility, cut on the ponytail pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…akhani-1b6564

fix(tor): publish a node's inbound onion only while that node is local (#103)
…_lan_access (#760)

The serving side of the remote-node modes. monero.rpc_lan_access existed
but published only the RPC — a remote P2Pool needs the ZMQ feed too, and
the Tari base node published nothing at all, so serving another stack
meant hand-run socat forwards (what the #78 bench setup did on gouda).

- monero.zmq_lan_access: publishes monerod's ZMQ (18083); a separate key
  from rpc_lan_access on purpose — that key's documented use is wallets,
  and widening it would change existing deployments' exposure.
- tari.grpc_lan_access: publishes the bundled Tari base node's gRPC
  (18142); loopback by default, matching the console-wallet publish's
  trust boundary. Ignored in remote mode (the service is profiled off).
- Both flips to 0.0.0.0 are DEST in describe_change (host-only, like
  MONERO_RPC_BIND), with the no-auth trust warning in the message.
- Docs: config rows + the remote-node sections now name the serving-side
  switches; CHANGELOG entry.
- Tier 1: describe_change direction tests + the #523 black-box render
  extended for all three binds (default localhost, true → 0.0.0.0).

Closes #760.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lan-access

feat(config): node LAN exposure switches — monero.zmq_lan_access + tari.grpc_lan_access
VERSION + dashboard package version in lockstep, uv.lock regenerated, CHANGELOG
Unreleased rolled to [1.14.0].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#760)

The e2e caught this on the bench: monerod's 18083 and the Tari node's 18142 are
published from this release, loopback unless the LAN switch is on, so anything
already holding either port stops the upgrade at 'docker compose up'. Say so in
the CHANGELOG upgrade note and beside both config keys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sh-note

docs(config): note that the node feeds publish a host port either way (#760)
@VijitSingh97
VijitSingh97 merged commit 1e09070 into main Jul 24, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant