Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
69e3418
fix(render): cap JVM heap at 50% of container memory below 8GB
warku123 Aug 18, 2026
835bb97
fix(render): de-conflict in-container HTTP ports (fullNode/solidity/P…
warku123 Aug 18, 2026
5c578b3
fix(target): probe ssh nodes through the tunnel; report real host in …
warku123 Aug 18, 2026
c60ccfd
chore(ci): pause tag-triggered releases (manual dispatch only)
warku123 Aug 19, 2026
5abf817
test(render): remove ineffectual assignment
warku123 Aug 19, 2026
6e55e30
fix(runtime): actually swap node artifact on upgrade/rollback (AUD-001)
warku123 Aug 19, 2026
4490064
fix(mcp): redact witness keys from live config resources
warku123 Aug 19, 2026
cc3b687
fix(security): enforce private permissions for JAR configs
warku123 Aug 19, 2026
78364f2
fix(apply): probe jar nodes over target tunnel in WaitForReady (AUD-004)
warku123 Aug 20, 2026
c03e75e
fix(cli): return NODE_NOT_FOUND instead of panicking on empty inspect…
warku123 Aug 20, 2026
3f4231b
fix(network): verify every node during rolling network upgrade (AUD-007)
warku123 Aug 20, 2026
a349b1b
fix(network): roll back nodes whose verify failed after upgrade (AUD-…
warku123 Aug 20, 2026
7862f5b
fix(replay): advance cursor only after a block fully replays (AUD-009)
warku123 Aug 20, 2026
efb4967
fix(snapshot): verify process identity before signaling stop
warku123 Aug 20, 2026
767787f
fix(build): fold untracked file contents into dirty cache key
warku123 Aug 20, 2026
c39f7fc
fix(render): fail loudly on unparseable memory values
warku123 Aug 20, 2026
46a990b
fix(snapshot): refuse downloads that overwrite a running node's chain…
warku123 Aug 20, 2026
6d11a77
fix(target): resilient ssh transport and jar download (AUD-019/020/021)
warku123 Aug 20, 2026
6ce2173
fix(state): make Save atomic and surface persistence errors
warku123 Aug 20, 2026
43d4482
Merge branch 'develop' into fix/p0-audit-findings
warku123 Aug 20, 2026
a0d7dce
fix(snapshot): stage downloads and publish atomically; merge build en…
warku123 Aug 20, 2026
9e32bd8
fix(network): harden multi-node lifecycle, versioned intent hash, and…
warku123 Aug 20, 2026
8bdb536
fix(mcp): align plan/apply with CLI contract and converge shared logic
warku123 Aug 20, 2026
f425d8b
fix(misc): streaming logs follow, bootstrap gate order, and audit har…
warku123 Aug 21, 2026
3603612
fix(render): wire solidity_grpc port, strict yaml fields, compose env…
warku123 Aug 21, 2026
9101fb0
docs(specs): record implementation contracts and fix drift
warku123 Aug 21, 2026
8209b5c
refactor(cmd): consolidate persistNodeState helper; fix MCP template-…
warku123 Aug 21, 2026
abd51cb
refactor(apply): centralize endpoint and port helpers
warku123 Aug 21, 2026
3030ffe
refactor(mcp,cmd): converge state load + target resolution helpers (#…
warku123 Aug 21, 2026
1406619
refactor(render,apply): converge diff algorithms and env/lookup helpe…
warku123 Aug 21, 2026
7f295d3
refactor(paths,render): converge template-dir, default-path, and cont…
warku123 Aug 21, 2026
5a77870
refactor(target): converge live-config reader into target.ReadLiveCon…
warku123 Aug 21, 2026
b16abb5
Merge remote-tracking branch 'upstream/develop' into fix/p0-audit-fin…
warku123 Aug 24, 2026
b1d1515
docs(changelog): document P0 audit fixes
warku123 Aug 24, 2026
70048f9
fix: address P0 audit findings C1-C5
warku123 Aug 24, 2026
8ad9c5a
fix(diagnose,heal): pass recorded node network into CLI check opts (A…
warku123 Aug 24, 2026
9e25486
fix: address CI lint and e2e contract failures
warku123 Aug 25, 2026
3d8943b
test: close local gate gaps and add output-schema contract test
warku123 Aug 25, 2026
82bb090
docs(makefile): note verify targets mirror CI jobs
warku123 Aug 25, 2026
fde40dd
fix(intent): skip default image for jar nodes and guard jar/docker ru…
warku123 Aug 25, 2026
6d09545
fix(runtime): remove stale systemd env drop-in when jar EnvVars becom…
warku123 Aug 25, 2026
a3b05dd
fix(schema): accept versioned intent_hash in status output schema
warku123 Aug 26, 2026
69ebd43
style(schema): gofmt embed.go version-history comment
warku123 Aug 26, 2026
99244c3
test(cmd): rename untagged e2e test files and document the convention
warku123 Aug 27, 2026
7f2fcf4
fix(network): make the PARTIAL_SUCCESS message describe actual state …
warku123 Aug 27, 2026
38fcad6
docs(contracts): realign agent guides, output schemas and MCP instruc…
warku123 Aug 27, 2026
a96f0a7
fix: address colleague review blockers
warku123 Aug 28, 2026
4e5ee89
Merge branch 'develop' into fix/p0-audit-findings
warku123 Aug 28, 2026
ef3095f
fix(network): hoist defer out of backup cleanup loop (gocritic deferI…
warku123 Aug 31, 2026
390a4e1
fix: address colleague review findings (non-blocking batch)
warku123 Aug 31, 2026
28979fe
fix(network): restore swapped-failed nodes via auto-rollback
warku123 Aug 31, 2026
80c6d4e
docs(replay): record block-failure abort as intentional (AUD-009)
warku123 Aug 31, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@ shadow-fork-intent.yaml
# one cleartext secp256k1 private key per receiver and MUST never be
# committed.
txgen-output/

# Regression campaign evidence (local-only, durable copy of /tmp/regress-*)
.regression-evidence/
44 changes: 28 additions & 16 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,21 @@ the exit status alone. One command emits a partial result today:
`network destroy` exits **1** with `error_code: "PARTIAL_SUCCESS"`, a
`removed` array and a `failed` array naming the nodes whose teardown failed.

**Do not retry it.** The message says `state cleaned up regardless`: trond has
already dropped every node from its state, so a second `network destroy`
returns `NETWORK_NOT_FOUND`. The `failed` entries are containers or units
still running on the target with nothing tracking them — surface that list to
the user for manual cleanup rather than retrying.

The other multi-node commands do not partially report: `network create` stops
at the first failed node with `DEPLOY_ERROR`, and `network upgrade` with
`UPGRADE_FAILED`, both exit 1.
**Partial state semantics.** The `removed` entries are gone from trond's
state; the `failed` entries REMAIN in state (their containers or units may
still be running on the target). A follow-up `network destroy` retries
exactly those remaining nodes — fix the underlying cause first (target
unreachable, docker error), then re-run if the user approves. Surface the
`failed` array to the user rather than looping silently.

`network create` behaves differently: it attempts every node to the end —
a failing node is recorded as an `error` entry in the result payload while
its siblings still get their turn — and only then returns exit 1 with
`DEPLOY_ERROR` summarising how many failed. Nodes that did deploy keep
running and are persisted in state, so a re-run reconciles them instead of
redeploying from scratch. `network upgrade` DOES stop at the first failure:
`UPGRADE_FAILED`, exit 1, with already-upgraded nodes left on the new
version unless `--auto-rollback` reverted them.

Every error JSON has the same shape:

Expand All @@ -110,6 +116,9 @@ Every error JSON has the same shape:
}
```

Errors may also include optional top-level `artifact_swapped: true` when a new
artifact was already activated and started but was not rolled back.

Process `suggestions[]` in order. The first entry is the most
prescriptive and usually fixes the issue automatically; later entries
are alternative fixes for less-likely causes.
Expand Down Expand Up @@ -293,6 +302,8 @@ done
trond apply --intent intent-with-snapshot.yaml --auto-approve --wait -o json
```

Snapshot download refuses destinations belonging to running or error-state managed nodes (`NODE_RUNNING`); stop the node before writing chain data.

### `plaintext_transport` — do not skip this

The six mainnet mirrors are bare IPs that publish **no HTTPS endpoint**
Expand Down Expand Up @@ -431,7 +442,8 @@ trond network upgrade pn \
--auto-rollback -o json
# Output: {"network":"pn","version":"4.8.1","upgraded_count":N,
# "upgraded_nodes":[...],"steps":[{node,phase,status,...}],
# "status":"success"|"failed","failed_at":"..."?}
# "status":"success"|"failed","failed_at":"..."?,
# "warnings":[... ]?} (cleanup failures are warnings, not UPGRADE_ERROR)

# 7. Cleanup. --confirm must match the network name (refuses typos).
trond network destroy pn --confirm pn -o json
Expand Down Expand Up @@ -637,7 +649,7 @@ managing a single user's nodes.
# Block until a probe succeeds (port listen, HTTP endpoint, exec output).
trond wait <node> --port 8090 --timeout 60s -o json
trond wait <node> --http "http://127.0.0.1:8090/wallet/getnowblock" \
--json '.block_header.raw_data.number > 100' --timeout 5m
--json-path block_header.raw_data.number --json-gt 100 --timeout 5m

# Exec arbitrary commands inside a node (docker exec / SSH exec).
trond exec <node> -- ls /java-tron/output-directory
Expand Down Expand Up @@ -987,11 +999,11 @@ the canonical workflow as runnable code.
## Versioning of this contract

Every JSON output that carries a `schema_version` field follows
semantic versioning at the field level: existing fields are stable
within a major version; additions are minor; renames or removals are
major. This file is updated alongside any contract change. If you
write an agent against trond X.Y, pin to that version and re-test on
upgrade.
semantic versioning at the field level: additive optional fields on
existing schemas are patch; new schemas are minor; renames, removals,
or meaning shifts are major. This file is updated alongside any
contract change. If you write an agent against trond X.Y, pin to that
version and re-test on upgrade.

If a JSON output's shape doesn't match what's documented here, that's
a bug — file an issue with the actual output and the trond version
Expand Down
88 changes: 88 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,94 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Breaking Changes

- Intent parsing now rejects unknown fields; invalid memory values now error
instead of falling back to 16 GB; `--monitor` no longer suppresses
`monitoring.enabled: true`. `extra_env` `$$` escaping is security
hardening, not a breaking change.

### Fixed

- Network auto-rollback now includes nodes whose upgrade artifact was activated
before a later child failure, using the `artifact_swapped` error-envelope fact;
schema contract bumped from 1.16.1 to 1.16.2. Network rollback also preserves
the pre-series `PreviousVersion` metadata so repeated rollbacks remain honest.
- Upgrade and rollback now fail when artifact SHA256 probing fails instead of
retaining a stale digest that could produce a false drift result.
- Untracked build-source directories, dangling links, and unreadable files are
represented by hash markers instead of aborting the build.
- State save treats post-rename directory fsync as best-effort for platforms
that cannot sync directories.
- Target overlays can explicitly disable inherited `auto_ports`.
- Network destroy reports every node affected by a shared target-resolution
failure.
- `intent_hash` now accepts the versioned `v2:` prefix.
- SSH bootstrap provisioning mode is restored, so package-manager, shell, and
user-creation commands are allowed only during `bootstrap`.
- Network upgrade backup cleanup now executes `rm` through the target layer;
cleanup failures are reported as warnings instead of misreporting a successful
upgrade as `UPGRADE_ERROR`.
- Agent guide no longer claims `network create` stops at the first failed
node: the command attempts every node in turn, aggregates failures into
`DEPLOY_ERROR` (exit 1), and leaves successfully deployed nodes running
and recorded in state for reconciliation on re-run.
- `network destroy` partial-failure error message now states the actual
state semantics: removed entries are gone from state, failed entries
REMAIN in state and can be retried (previously claimed the state was
"cleaned up regardless"). Part of the #225/#226 correction chain — the
earlier guide text was written on top of trond's own lying runtime
error message.
- `status` output schema now accepts versioned intent hashes (`v2:` prefix),
fixing schema-validation failures against real `status` output; contract test
coverage extended to status. (council R2 finding)
- Jar intent nodes no longer receive the default Docker image, which
previously made `apply` reject mutually-exclusive artifact sources. Jar
plus Docker runtime is now rejected up front with a clear error pointing to
`target.runtime=jar` (commit fde40dd).
- `diagnose` and `heal` now use the node's recorded network for
private-network gating checks (AUD-044; commit 8ad9c5a).
- **P0 audit remediation.** Batch B adds focused cmd-side test splits for
`cmd/build`, `cmd/state`, `cmd/network create`, and `cmd/apply` (B1–B8),
while domain 1–5 fixes harden lifecycle, state persistence, target
transport, rendering, snapshots, runtime upgrades, security, replay, and
transaction broadcasting behavior.
- Multi-node network creation, addition, destruction, and rolling upgrades
now persist node state consistently, verify every node, and roll back
already-upgraded nodes when verification fails. Automatic port allocation
is persisted for repeatable reconciliation.
- Snapshot downloads stage data before publishing atomically, refuse unsafe
overwrites, verify the process identity before stopping jobs, and merge
build environment maps correctly. Jar upgrades and rollbacks now swap the
running artifact reliably.
- Rendering now validates strict YAML fields, merges overlays correctly,
escapes Compose environment values, wires the `solidity_grpc` port, avoids
in-container HTTP-port conflicts, and caps JVM heap below 8 GB of container
memory. SSH probing and downloads are resilient and report the actual host.
- Sensitive witness data remains redacted, JAR configuration permissions are
restricted, state saves are atomic with surfaced persistence errors, and
replay cursors advance only after complete block replay.
- Replay now aborts with a clear error when any transaction broadcast in a block
fails, and retries resume from the failed block boundary (AUD-009).

### Changed

- Shared state loading, target resolution, live-config reading, template and
path discovery, diff computation, environment-variable expansion
(`internal/apply.ResolveEnvVars`), endpoint/port handling, and node-state
persistence are centralized across CLI and MCP paths.
- `trond plan` now reports `current_state: "not_deployed"` instead of
`"not deployed"`, matching the documented machine-readable contract.
- `intent_hash` in `apply` and `status` output is now versioned as
`v2:<sha256>`; the previous bare-hex digest format is replaced by the v2
digest scheme.
- With `auto_ports: true`, allocated ports are persisted. Re-running
`trond plan` after `apply` now correctly reports `changes: null` and zero
downtime instead of spurious configuration diffs requiring a restart.
- MCP lifecycle and diagnostic paths now use the same CLI contracts and
shared implementations; contract coverage and implementation specs were
expanded to document the corrected behavior.

## [0.1.0] — 2026-XX-XX

First tagged release. The project transitions from a curated set of HOCON
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ endif

GOFLAGS ?=

.PHONY: build test lint e2e build-all clean clean-all fmt vet tidy sync-templates sync-schemas sync-knowledge snapshot-schema-baseline update-render-golden docs man cover vuln bootstrap-go build-replay install-replay build-txgen install-txgen build-txgen-falcon install-txgen-falcon
.PHONY: build test lint e2e verify verify-fast build-all clean clean-all fmt vet tidy sync-templates sync-schemas sync-knowledge snapshot-schema-baseline update-render-golden docs man cover vuln bootstrap-go build-replay install-replay build-txgen install-txgen build-txgen-falcon install-txgen-falcon

## bootstrap-go: Download + verify the project-local Go toolchain
## (idempotent; safe to re-run; no-op if already current)
Expand All @@ -68,6 +68,15 @@ lint: $(GO_BOOTSTRAP)
e2e: $(GO_BOOTSTRAP)
$(GO) test ./... -tags=e2e -race -count=1 -timeout 10m

## verify: Pre-push gate — lint + unit tests + e2e (requires Docker daemon).
## Mirrors the CI jobs (golangci-lint, Test + coverage, e2e) so a green
## local run means a green CI; run this before pushing.
verify: lint test e2e

## verify-fast: Fast pre-push gate — lint + unit tests (no Docker required).
## Same lint and unit jobs as CI; skips only the Docker-dependent e2e job.
verify-fast: lint test

## build-all: Cross-compile for all supported platforms
build-all: $(GO_BOOTSTRAP)
GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o bin/$(BINARY)-linux-amd64 .
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ cache management, and MCP usage: [build pipeline quickstart](specs/002-trond-bui
| `trond logs <node>` | Stream node logs |
| `trond diagnose <node>` | Run structured health checks |
| `trond health <node>` | Quick HTTP API probe |
| `trond verify <node>` | Post-deploy health gate |
| `trond verify --intent <path> --timeout 5m` | Post-deploy health gate |
| `trond preflight` | Check target readiness |
| `trond bootstrap` | Install Docker or JDK on target |

Expand Down
62 changes: 62 additions & 0 deletions TODOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
Deferred work captured during reviews. Each item carries enough context to pick
up cold.

## Open audit follow-ups

- **AUD-009 replay block-failure threshold** — aborting replay when any
transaction broadcast in a block fails is intentional, not a bug: the cursor
must never advance past a partially-failed block, or silently dropped
transactions can make the shadow chain diverge from mainnet. Retry resumes
at the failed block boundary; already-landed transactions are re-broadcast
as expected, pinned by `tools/replay/replayer_test.go` (`want 4` assertion).
Defer a configurable `--block-fail-threshold N` flag (default `0` = current
strict abort; `N > 0` tolerates ≤N failures per block, while all failures
remain in `failLog` and are reported in the summary) to a follow-up PR if
needed.
- **AUD-020 transport-pool leak** — retire target-aware transports from the
shared pool on every lifecycle path (`internal/target/target.go:38-48,86-94`).
- **Windows support** — complete platform-specific lifecycle and filesystem
validation beyond the best-effort directory fsync (`internal/state/store.go`).

## `snapshot clone --from-node` for SSH-target / named-volume nodes

- **What:** `snapshot clone --from-node <name>` now resolves jar + docker
Expand Down Expand Up @@ -85,3 +102,48 @@ up cold.
- **Context:** flagged by the 2026-06 eng-review of the C1 private-net PR
(Issue 4 / Codex #7). Documented in AGENTS.md's safety section meanwhile.
- **Depends on:** a deliberate schema-version major bump.

## Jar remove should scrub retained witness key

- **What:** `trond remove` without purge (`--keep-data`) may leave an inline
witness key in `config.conf` under the install directory; assess default
scrubbing or document the retained secret clearly.
- **Context:** Council R2 skeptic.

## Preserve change tracking on remove read errors

- **What:** `changeTracker.remove` treats non-NotExist `ReadFile` errors
(SSH/permission transient) as absent; a successful `rm` then leaves
`changed` false, so a running JVM retains old env until restart. Distinguish
errors or conservatively set `changed`, and add read-error+rm-success
coverage.
- **Priority:** P2.
- **Context:** Council R2 skeptic.

## Reject control characters in systemd drop-in Environment values

- **What:** Reject control characters in drop-in `Environment=` values; newline
or `#` could theoretically inject extra systemd directives.
- **Priority:** P3; operator-self threat model, low risk.
- **Context:** Council R2 implementer.

## Add real systemd lifecycle E2E coverage

- **What:** Real systemd E2E for `daemon-reload`, `enable`, `is-active`, and
journal semantics is missing; add a systemd runner or formally declare the
support boundary.
- **Status:** UNVERIFIED.
- **Context:** Council R1/R2.

## Define state-save failure reconciliation

- **What:** Define recovery and consistency semantics when runtime mutation
succeeds but state save fails, including a reconcile strategy.
- **Context:** Council R1 skeptic,洞#8.

## Expand schema producer/consumer contract coverage

- **What:** Output schema↔producer bidirectional assertions currently cover
only apply/events/status; extend them to every output schema. Also declare
`intent_hash` in `inspect.schema.json`.
- **Context:** Council R2 architect; long-term debt.
17 changes: 15 additions & 2 deletions cmd/agentsmd_e2e_test.go → cmd/agentsmd_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
//go:build e2e

// Package-level tests guarding the AGENTS.md agent contract.
//
// NOTE: this file intentionally has NO //go:build e2e tag — it runs in
// the DEFAULT test suite (moved out of the e2e tag in 3d8943b "close
// local gate gaps") so AGENTS.md doc rot (renamed commands, drifted
// output fields) is caught by the ordinary CI "Test + coverage" job and
// local `go test ./...`, not only when someone runs -tags=e2e.
//
// Cost/hermeticity caveat: TestE2E_AgentsMD_OutputFieldsExist is NOT
// fully hermetic — it builds the trond binary once per package run via
// e2eEnv and executes a small set of read-only commands (version,
// doctor, snapshot sources, recipe list, network status, list). Command
// failures are Skip, not Fail, and no Docker/network is required. Keep
// any new test in this file equally cheap and skip-tolerant; tests that
// need Docker or a deployed node belong in a //go:build e2e file.
package cmd

import (
Expand Down
Loading
Loading