Skip to content

fix(drivers): close Lua host holes for command, default mode, and fingerprint - #1199

Merged
frahlg merged 6 commits into
masterfrom
fix/lua-driver-contract
Sep 12, 2026
Merged

frahlg merged 6 commits into
masterfrom
fix/lua-driver-contract

Conversation

@frahlg

@frahlg frahlg commented Sep 10, 2026

Copy link
Copy Markdown
Member

Core could report a successful command when a Lua hook was missing, accept a controllable read-only driver without a safe default, and omit PV-only control from the default-mode gate. Missing commands now fail, both Registry and Lua reject read-only commands before the hook runs, and PV control requires a default. Fingerprint probes cannot use mutating host calls; the catalog reads auth_post_path.

Move the recovery pin to device-drivers #112, including its telemetry fixes and safe-default/read-only declarations. Include the read-only Zaptec Cloud and Tesla Wall Connector drivers and regenerate the shipped inventory. Keep the exact reviewed Ferroamp source hashes: the new version changes only version and configured serial identity; its PV limit and release code is unchanged. Unknown source bytes still receive no PV control proof.

Validation: make verify passes on current master including #1170; driver and EV-cloud packages pass; the version check across the pin passes for all 40 bundled drivers. A new test loads each pinned Lua file and applies the same default-hook gate as Registry startup. Tests cover refused read-only commands, missing hooks, PV-only actuators, probe write denial, PV proof identity and revocation. This proves host contract compatibility and simulated recovery paths, not safe-default behavior on every physical device. Native bundle integrity passes; native worker execution is unavailable on this Mac. No UI changes, release or install.

…gerprint

A missing driver_command is an error instead of a silent success. A
non-read-only driver that declares controls or a battery/EV/V2X/heat-pump
command path must implement driver_default_mode before it starts.
Fingerprint probes deny mutating host verbs even for bundled drivers.
The catalog parser now reads auth_post_path.
@cursor

cursor Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_341bb692-9c52-4531-b9ce-afb4f5eee825)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T07:31:48.229651Z 79d180b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79d180bc6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread go/internal/drivers/registry.go
Comment thread go/internal/drivers/registry.go Outdated

@miravoss26 miravoss26 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tightens the Lua driver host contract after the device-drivers audit (companion PR srcfl/device-drivers#112). Three real safety gaps closed:

  • Command() silently succeeded when driver_command was undefined — now returns an error instead of pretending the write happened. This was the sharpest one: a caller had no way to know a command was dropped on the floor.
  • RunFingerprint now sets ProbeReadOnly, so a passive fingerprint probe can't call modbus_write/mqtt_pub/http_post/http_patch even on bundled drivers (where allowWrite was previously a no-op without a signed policy).
  • Legacy drivers that can be commanded + declare an actuation capability (battery/EV/V2X/heatpump) or catalog controls now require driver_default_mode at start, with read-only and telemetry-only drivers correctly exempted.

Test coverage matches the logic well — TestLegacyBatteryCommandDriverRequiresDefaultMode, TestReadOnlyBatteryMayOmitDefaultMode, TestBatteryTelemetryDriverWithoutCommandMayOmitDefaultMode, TestFingerprintProbeCannotWrite, TestLuaDriverMissingCommandIsError all cover the new branches, not just the happy path. CI green (Core Linux binaries, Windows config, go test + vet, Device Support driver contract).

Minor: this is a behavior change for any driver relying on the old "missing driver_command = silent success" shape, but that's exactly the bug being fixed, and the changeset documents it.

Safe to merge from my read.

@miravoss26 miravoss26 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good hardening pass on the Lua host contract, three real holes closed:

  1. Command() on a driver with no driver_command used to return nil (silent success) — now an explicit error. That's a real "commanded a device, nothing happened, no one noticed" bug closed.
  2. RunFingerprint now sets HostEnv.ProbeReadOnly, and allowWrite checks it before falling through to RuntimePolicy == nil → allow. Previously a bundled driver with no signed policy could modbus_write/http_post during a passive fingerprint probe — that's the actuation-during-probe hole, now closed at the host layer regardless of policy state.
  3. legacyDriverRequiresDefaultMode widens the startup gate from "declares controls" to "has driver_command AND an actuation capability (battery/EV/V2X/heatpump)" — broader and more honest given the audit found no bundled driver even declares controls.

Well tested: missing-command error, probe-cannot-write (asserts zero writes reached the mock), and all three default-mode branches (must-have / read-only-may-omit / telemetry-only-may-omit).

One question before merge, not a blocker on the code itself: the PR body says this is host-only and the companion device-drivers fix (making bundled Lua drivers comply) hasn't landed yet — bundled pin unchanged. Point 3 above is strictly stricter than today's gate (hasCommand && actuationCapability, not just controls). Is there a CI check that loads all 38 currently-bundled drivers through Registry.Add / legacyDriverRequiresDefaultMode to confirm none of them currently have a command path + battery/EV/etc capability without driver_default_mode? If not, merging this ahead of the companion PR risks a currently-shipped driver failing to start. Worth a human confirming that sequencing before merge — the code change itself looks correct and well-scoped.

Security screen: no secrets, no new deps; the interesting security surface here (fingerprint write-gating, command-contract) is the point of the PR and looks correctly tightened.

frahlg added a commit to srcfl/device-drivers that referenced this pull request Sep 12, 2026
#112)

Driver audit against the FTW host contract (companion: srcfl/ftw#1199).

- fronius_smart_meter 2.1.2, zuidwijk_p1 1.1.1: stop fabricating 0 W/0-value telemetry on a failed/missing read; declare read_only
- tesla_vehicle 0.2.2: cache replay sets soc_fresh = false
- pixii 2.1.4: serial probe no longer gated on an unset `ok`
- easee_cloud 1.3.1: config_secrets = {"password"}; driver_default_mode pauses and writes 0 A
- ferroamp 2.1.2: host.set_sn(config.serial) when set
- Telemetry-only hybrids/meters (sonnen, goodwe, growatt, sofar, kostal, sma, victron, fronius, pixii_pv, solis_string, tibber) declare read_only = true
- zaptec_cloud 0.1.0 and tesla_wall_connector 0.1.0 promoted from FTW testdata

Pre-merge review found zaptec_cloud shipped control-capable with no hardware verification and a phase-order bug in ev_set_current (computed amps from the old phase count before applying a same-call phase change). Fixed by keeping it read-only/no-op like tesla_wall_connector until a real charger verifies the control path end-to-end; DCO sign-off added to both commits.

make check: 4404 passed, 1069 skipped.
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
…ract

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
…ract

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@cursor

cursor Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_37f824ad-1a59-442f-ace4-3366f82d5d3a)

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