test(config): add receive-side golden oracle and sharpen fixture

Address low-severity review findings on the X-macro config refactor:

1. The golden test only hashed config_send_wire_block(), so a
   receive-side KIND that reads a different width/order could still
   round-trip symmetrically.  Add test_config_wire_golden_receive():
   capture the same hash-pinned 633-byte frame and feed it through
   config_receive(), asserting every field (config_wire_equal) plus the
   derived use_delta/use_xattrs bits and representative bounded kinds.
   Add test_config_wire_receive_bounds() for bounds the symmetric
   round-trip cannot reach: an out-of-range BOOL (hand-built frame),
   RAW_MAXALLOC zero, a malformed STR_MODULE, an over-cap
   INT_IDMAPCOUNT, and an out-of-range INT_IDENTITY chown_uid.

2. golden_config_populate() set long runs of booleans to all-1, so an
   adjacent swap within a run produced identical bytes.  Alternate the
   boolean values and make the fixture receiver-valid (chmod grammar
   "u=rwx,go=rx" is the same 11 bytes; delta_max_file_size inside the
   bound).  Re-pin the golden: len stays 633, hash is now
   9160991280011164139 (computed, not guessed).

3. Document in config.h and client_cli.c that the CLI option tables
   remain hand-maintained and are deliberately not generated from the
   wire-field X-macro (client-only fields, flag/alias/negation
   semantics).  No CLI-table rewrite.

PROTOCOL_VERSION stays "2.20.0"; src/shared/config.c is untouched and
the wire bytes are unchanged apart from the fixture's own new values.
This commit is contained in:
2026-09-13 10:56:34 +02:00
parent 4e918a1b69
commit 6ea966781f
3 changed files with 289 additions and 52 deletions
+9 -1
View File
@@ -608,7 +608,15 @@ typedef struct {
size_t offset; /* offsetof of the boolean target field in Config */
} NegatableOption;
/* Options that map directly onto a Config field with no side effects. */
/* Options that map directly onto a Config field with no side effects.
*
* NOTE: these CLI tables are intentionally NOT generated from the wire-field
* X-macro table in config.h. The two sets only overlap partially: the CLI
* surface also carries client-only fields that never cross the wire (rsh,
* outbuf, remote-option, batch paths, trust-sender, ...) and needs flag/alias/
* negation semantics that the wire table does not model. Keeping them
* hand-maintained is deliberate; the shared contract is enforced at the wire
* boundary by config.[ch] and the golden test. */
static const OptionEntry OPTION_TABLE[] = {
{"--dry-run", "-n", OPT_FLAG, offsetof(Config, dry_run)},
{"--remove-source-files", NULL, OPT_FLAG, offsetof(Config, remove_source_files)},