test(protocols): native-api value escaping round-trip + ssh no-PTY guard (JG-09/JG-15)#48
Conversation
…Y (JG-09/JG-15) Promote the protocol-compliance facts the fan-out flagged as untested into GitHub-visible assertions, independent of any command/feature: - JG-15: native-api attribute *value* round-trip — the API protocol is length-prefix framed, not delimiter-escaped, so `=`, spaces, CR/LF, NUL, and multibyte UTF-8 survive verbatim, and parseReply splits `=name=value` on the second `=` so a value containing `=` is read back whole. Pins the full attributeWord → encodeSentence → SentenceReader → parseReply path; the codec was tested for framing but never for special-char values end-to-end. - execute/ssh no-PTY guard: SshExecClient.argv must never request a tty (`-t`, `-tt`, `-T`, RequestTTY) — RouterOS grants no PTY and `-tt` hangs it. The terminal relay already guards this (terminal.test.ts); execute did not. - attributeWord doc comment records the no-escaping contract the test pins. Test-only + doc comment; native-api codec unchanged; cells stay CHR-passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe PR expands the Changesnative-api attributeWord Documentation and Round-Trip Tests
SSH No-PTY Assertion
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds regression coverage for two protocol-compliance behaviors: native RouterOS API attribute value round-trip (including tricky characters) and ensuring SSH execute never forces a PTY (which can hang RouterOS).
Changes:
- Added a unit test asserting
SshExecClient.argvdoes not request a PTY. - Added an end-to-end unit test covering native-api attribute value round-trips across encode/decode/parse.
- Expanded
attributeWorddocumentation to describe the “no escaping” contract.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
test/unit/ssh.test.ts |
Adds a regression test around SSH execute argv PTY behavior. |
test/unit/native-api.test.ts |
Adds end-to-end round-trip tests for native-api attribute values with special characters. |
src/protocols/native-api.ts |
Documents the attribute value no-escaping behavior and ties it to the regression test. |
| const argv = client({ exitCode: 0, stdout: "", stderr: "" }).argv("/x"); | ||
| expect(argv).not.toContain("-t"); | ||
| expect(argv).not.toContain("-tt"); | ||
| expect(argv).not.toContain("-T"); | ||
| expect(argv.join(" ")).not.toContain("RequestTTY"); |
| function roundTrip(name: string, value: string): string | undefined { | ||
| const words = ["!re", attributeWord(name, value)]; | ||
| const reader = new SentenceReader(); | ||
| const sentences = reader.push(encodeSentence(words)); | ||
| expect(sentences).toHaveLength(1); | ||
| return readAttribute(parseReply(sentences[0] as string[]), name); | ||
| } |
| * The value needs **no escaping**: words are length-prefix framed on the wire | ||
| * ({@link encodeWord}), so any bytes — `=`, spaces, CR/LF, NUL, multibyte UTF-8 — | ||
| * pass through verbatim, and {@link parseReply} splits on the *second* `=` so a | ||
| * value that contains `=` is read back whole. Round-trip pinned in |
…casts, UTF-8 wording - ssh no-PTY guard: only forbid *forcing* a PTY (`-t`/`-tt`/`RequestTTY=force|yes`); `-T` and `RequestTTY=no` *disable* a PTY and are valid hardening, so allow them. - native-api round-trip: destructure + guard instead of `as string[]` casts, so a decode regression to `undefined` fails loudly rather than being masked. - attributeWord doc + JG-15 test comment: "any UTF-8 content" (encodeWord UTF-8 encodes a JS string by byte length), not "any bytes" — avoids over-promising raw-binary safety while still covering `=`, spaces, CR/LF, NUL, multibyte. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Stage-1 protocol-compliance work (JG-09), absorbing the JG-15 escaping
round-trip the fan-out flagged as the one genuinely untested transport behavior.
Turns local protocol-memory facts into GitHub-visible, reviewable assertions.
JG-15 — native-api attribute value round-trip
The RouterOS API protocol is length-prefix framed, not delimiter-escaped: a
value is a count of raw bytes, so
=, spaces, CR/LF, NUL, and multibyte UTF-8all survive verbatim with no escaping, and
parseReplysplits=name=valueonthe second
=so a value that itself contains=is read back whole. Thecodec had framing tests but no end-to-end test for special-char values. New
describe("… (JG-15)")pins the full pathattributeWord → encodeSentence → SentenceReader → parseReplyacross 11 trickyvalues + the value-less (
=name=/=name) case.execute/ssh no-PTY guard
SshExecClient.argvmust never request a tty (-t,-tt,-T,RequestTTY)— RouterOS grants no PTY and
-tthangs the session (CHR 7.23.1 grounded).The terminal relay already guards this (
terminal.test.ts); the per-commandexecute client did not.
Docs
attributeWorddoc comment now records the no-escaping contract the test pins.Why no CHR
Test-only + one doc comment. The native-api codec is unchanged and the asserted
cells are already
CHR-passed; this is additive regression coverage, so theMATRIX is untouched.
Verification
bun run lint+bun run lint:ci+bun run test(701 pass / 0 fail / 26 skip)bun run buildall green.🤖 Generated with Claude Code
Summary by CodeRabbit
Tests
Documentation