Skip to content

feat(provision): settle + verify managed SSH key (ed25519) and persist for #71 (#74) - #82

Merged
mobileskyfi merged 1 commit into
mainfrom
mobileskyfi/issue74
Jul 7, 2026
Merged

feat(provision): settle + verify managed SSH key (ed25519) and persist for #71 (#74)#82
mobileskyfi merged 1 commit into
mainfrom
mobileskyfi/issue74

Conversation

@mobileskyfi

@mobileskyfi mobileskyfi commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Completes #74 and delivers the data source #71 was blocked on.

Decision (settled, grounded)

Keep ed25519 as the managed key. Grounded in test/lab/ssh-keys/REPORT.md: accepted by /user/ssh-keys/add|import from RouterOS 7.12+, and batch-login-verified on the 7.20.8 floor and current stable. RSA-2048 is only a sub-7.12 fallback quickchr never provisions; ECDSA is rejected by RouterOS.

What changed

  • installSshKey() now verifies with a real batch login. Presence in /user/ssh-keys is necessary but not sufficient — it follows up with ssh -o BatchMode=yes -o PasswordAuthentication=no and returns { privateKeyPath, algorithm, batchVerified }. Best-effort: a failed probe records batchVerified: false and never aborts provisioning.
  • Persisted as MachineState.managedSshKey (to machine.json). This is exactly what API: live descriptor contract for centrs --quickchr targets #71's descriptor reads to advertise services.ssh.auth.privateKeyPath / batch key auth as usable only when batchVerified is true.
  • Integration test asserts the persisted fact (state + machine.json) and an independent BatchMode=yes login — verified live on 7.20.8 and 7.23.2.
  • Docs aligned: provisioning.instructions.md, REPORT.md §6, CHANGELOG.

Acceptance (#74) → evidence

  • Live integration verifies host-OpenSSH BatchMode=yes / PasswordAuthentication=no login → test/integration/provisioning.test.ts.
  • Covers current stable and the min provisioning version (7.20.8) → ran both.
  • REPORT.md / provisioning docs / tests no longer disagree with provision.ts (ed25519).
  • API: live descriptor contract for centrs --quickchr targets #71 can report privateKeyPath / batch auth as usable only when known-good → managedSshKey.batchVerified is the gate.

What's left for #71 (separate session)

This PR provides the fact; #71 implements the descriptor v1 shape (the services map, ssh.auth.{modes,batchModes,privateKeyPath}) that consumes MachineState.managedSshKey. No further #74 work blocks it.

Local verification: 683 unit tests pass; integration green on 7.20.8 + 7.23.2; tsc/biome/markdownlint/cspell clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • SSH provisioning now saves and reports managed key details, including the key type, file location, and whether login verification succeeded.
    • Devices that support it now use a stronger SSH key setup by default, with older devices still handled automatically.
  • Bug Fixes

    • SSH key installation now provides clearer failure feedback when the device rejects a key.
    • Provisioning now performs a real SSH login check after setup, improving confidence that access is working.

…74)

Settles the managed-key algorithm and delivers the verified-key fact #71 needs.

- Algorithm decision: keep ed25519 (grounded accepted from RouterOS 7.12+, and
  batch-login-verified on the 7.20.8 floor and current stable in
  test/lab/ssh-keys/REPORT.md). RSA-2048 is only a sub-7.12 fallback quickchr
  never provisions; ECDSA is rejected by RouterOS.
- installSshKey() now does a real host-OpenSSH batch login (BatchMode=yes,
  PasswordAuthentication=no) after install — presence in /user/ssh-keys is
  necessary but not sufficient — and returns { privateKeyPath, algorithm,
  batchVerified }. Best-effort: a failed probe records batchVerified=false and
  never aborts provisioning.
- Persist the fact as MachineState.managedSshKey (to machine.json). This is the
  data source #71's descriptor reads to advertise SSH private-key batch auth as
  usable ONLY when batchVerified is true.
- Integration test (test/integration/provisioning.test.ts) asserts the persisted
  fact + an independent BatchMode login; verified live on 7.20.8 and 7.23.2.
- Docs aligned: provisioning.instructions.md, REPORT.md §6, CHANGELOG.

Closes #74.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 7, 2026 03:29
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e41e6a5d-9cf8-42dd-ae67-45181e97bcce

📥 Commits

Reviewing files that changed from the base of the PR and between afa0c3a and fca19e8.

📒 Files selected for processing (7)
  • .github/instructions/provisioning.instructions.md
  • CHANGELOG.md
  • src/lib/provision.ts
  • src/lib/quickchr.ts
  • src/lib/types.ts
  • test/integration/provisioning.test.ts
  • test/lab/ssh-keys/REPORT.md

📝 Walkthrough

Walkthrough

Adds a ManagedSshKey type and extends MachineState/ProvisionResult with it. installSshKey now generates an ed25519 keypair, verifies REST listing, performs a best-effort host SSH batch-login check, and returns key metadata; provision() propagates this through both provisioning paths. quickchr.ts persists the result. Docs, changelog, and integration tests updated.

Changes

Managed SSH key verification and persistence

Layer / File(s) Summary
ManagedSshKey type and MachineState extension
src/lib/types.ts
New ManagedSshKey interface (privateKeyPath, algorithm, batchVerified, verifiedAt?) and optional managedSshKey field on MachineState.
installSshKey batch verification and provision wiring
src/lib/provision.ts
installSshKey generates ed25519 keys, verifies REST listing, performs host batch-login check, and returns ManagedSshKey; provision() gains sshPort param and propagates managedSshKey through console-fallback and REST paths into ProvisionResult.
Persist managedSshKey into machine state
src/lib/quickchr.ts
_provisionInstance persists managedSshKey into machine.json and in-memory state, warns when batchVerified is false.
Docs, changelog, and integration test coverage
.github/instructions/provisioning.instructions.md, CHANGELOG.md, test/lab/ssh-keys/REPORT.md, test/integration/provisioning.test.ts
Provisioning instructions, changelog, lab report, and integration test updated to document/validate ed25519 keys, managedSshKey persistence, and batch-login verification.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

  • tikoci/quickchr#17: Both PRs modify test/integration/provisioning.test.ts; this PR adds managedSshKey assertions while #17 changes target selection affecting how those assertions run.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mobileskyfi/issue74

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mobileskyfi
mobileskyfi merged commit 4b30f56 into main Jul 7, 2026
13 checks passed
@mobileskyfi
mobileskyfi deleted the mobileskyfi/issue74 branch July 7, 2026 03:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens quickchr’s provisioning pipeline by turning the managed SSH key into a persisted, machine-level “fact” that downstream consumers (notably the upcoming #71 descriptor) can trust for batch-mode SSH handoff.

Changes:

  • Add a ManagedSshKey fact (path/algorithm/batchVerified/verifiedAt) and persist it on MachineState/machine.json.
  • Update provisioning to verify managed-key usability via a real host OpenSSH BatchMode=yes login (best-effort; does not fail provisioning).
  • Add an integration assertion that both persistence and independent batch login work; align lab report, provisioning instructions, and changelog.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/lib/provision.ts Adds managed-key batch verification and returns/passes the persisted managedSshKey fact.
src/lib/quickchr.ts Persists managedSshKey into state and warns when verification fails.
src/lib/types.ts Introduces ManagedSshKey and attaches it to MachineState.
test/integration/provisioning.test.ts Verifies managedSshKey persistence and validates batch SSH login works.
test/lab/ssh-keys/REPORT.md Updates lab narrative to reflect the new persisted/verified data source.
.github/instructions/provisioning.instructions.md Documents the settled algorithm and the persisted verification fact.
CHANGELOG.md Records the new behavior and persistence in Unreleased notes.

Comment thread src/lib/provision.ts
Comment on lines 381 to +383
lastListBody = listBody;
const keys = JSON.parse(listBody) as Array<{ user?: string }>;
if (Array.isArray(keys) && keys.some((k) => k.user === username)) return;
if (Array.isArray(keys) && keys.some((k) => k.user === username)) { listed = true; break; }
Comment thread src/lib/provision.ts
Comment on lines +290 to +294
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-o", "PasswordAuthentication=no",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=10",
Comment on lines +488 to +492
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-o", "PasswordAuthentication=no",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=10",
@mobileskyfi

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

mobileskyfi added a commit that referenced this pull request Jul 7, 2026
Follow-up to the unresolved review threads on the now-merged PR #82.

## What changed

- Match the generated RouterOS SSH key row by user, generated key
comment (`info ?? key-owner`), key type, and fingerprint when RouterOS
exposes one.
- Normalize trailing SHA256 fingerprint padding because RouterOS 7.20.8
includes base64 padding while OpenSSH-style fingerprints omit it.
- Run production and integration OpenSSH probes with
`IdentitiesOnly=yes` and `-F` to the platform null device so
agent/config identities cannot produce false-positive batch verification
on Unix or Windows.
- Reuse the production SSH-key matcher from the integration test so
key-type and optional fingerprint behavior stay aligned.
- Fail provisioning if quickchr cannot fingerprint its own generated
managed SSH public key.
- Update the scoped provisioning instructions, SSH key lab report, and
changelog to reflect the stricter verification contract.

## Why

The PR #82 review was correct: the previous check could accept any key
for the same user, and `ssh -i` without isolating OpenSSH
identity/config behavior could still authenticate through other
configured identities. That could make
`MachineState.managedSshKey.batchVerified` look stronger than it really
was, which matters for the upcoming #71 descriptor.

## Validation

- `bun run check`
- `bun test test/unit/` — 686 pass, 18 skip, 0 fail
- `QUICKCHR_INTEGRATION=1 bun test
test/integration/provisioning.test.ts` — 11 pass, 0 fail
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.

2 participants