Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Driver versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html

## [Unreleased]

### Fixed

- **The channel build now carries `config_secrets` into the generated header, so a box no longer masks nothing.** `tools/ftw_repository.py` prepends a generated `DRIVER = { … }` block ahead of the source's own, and FTW core parses only the first block it finds (`extractDriverBlock`). The generated block never copied `config_secrets`, so any driver declaring it — `myuplink`, `nibe_local`, `sonnen`, `tibber` — published a catalog entry with nothing to mask: `GET /api/config` on a box running the channel build returned `myuplink`'s `client_secret` and `refresh_token` in clear text, confirmed on a live installation. The source block further down still declared the field correctly, which is exactly why nothing caught this in a source-level review. `test_config_secrets_reach_the_generated_header` holds the generated header to it. Fixes #106.
- **myuplink** 1.2.2, **nibe_local** 1.1.4, **sonnen** 2.0.2, **tibber** 1.1.1 — patch bump only. The `config_secrets` fix above changes these four drivers' published artifact bytes (the signed channel now emits their `config_secrets` list in the generated header), so the signed channel's own version rule requires a new version to publish it under. No Lua source changed.

### Changed

- **easee_cloud** 1.2.0 — emit `request_active`: false only when the vehicle
Expand Down
16 changes: 8 additions & 8 deletions SUPPORT_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ Catalog source is not proof that a target can install or run a driver.
| kstar | 1.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| mennekes | 1.0.3 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| mennekes | 1.0.3 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| myuplink | 1.2.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| myuplink | 1.2.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| nibe_local | 1.1.3 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| nibe_local | 1.1.3 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| myuplink | 1.2.2 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| myuplink | 1.2.2 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| nibe_local | 1.1.4 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| nibe_local | 1.1.4 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| opendtu | 1.0.2 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| opendtu | 1.0.2 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| opendtu_mqtt | 1.0.3 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
Expand Down Expand Up @@ -154,14 +154,14 @@ Catalog source is not proof that a target can install or run a driver.
| solis | 2.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| solis_string | 1.1.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| solis_string | 1.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| sonnen | 2.0.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| sonnen | 2.0.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| sonnen | 2.0.2 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| sonnen | 2.0.2 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| sungrow | 1.5.8 | ftw-core | observe_only_profile_blocked | 1.3.3 | 1.3.0 | exact_model_firmware_required | — | not_assessed | no |
| sungrow | 1.5.8 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tesla_vehicle | 0.2.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tesla_vehicle | 0.2.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tibber | 1.1.0 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tibber | 1.1.0 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tibber | 1.1.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| tibber | 1.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| varta | 1.1.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
| varta | 1.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no |
| victron | 2.1.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no |
Expand Down
8 changes: 4 additions & 4 deletions devices.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ manufacturers:
protocols:
- protocol: http
driver: "myuplink"
version: "1.2.1"
version: "1.2.2"
ders: [heatpump]
control: false
firmware_versions: ""
Expand All @@ -993,7 +993,7 @@ manufacturers:
protocols:
- protocol: http
driver: "nibe_local"
version: "1.1.3"
version: "1.1.4"
ders: [heatpump]
control: false
firmware_versions: ""
Expand Down Expand Up @@ -1817,7 +1817,7 @@ manufacturers:
protocols:
- protocol: http
driver: "tibber"
version: "1.1.0"
version: "1.1.1"
ders: [meter]
control: false
firmware_versions: ""
Expand Down Expand Up @@ -2092,7 +2092,7 @@ manufacturers:
protocols:
- protocol: http
driver: "sonnen"
version: "2.0.1"
version: "2.0.2"
ders: [battery, meter]
control: false
firmware_versions: ""
Expand Down
2 changes: 1 addition & 1 deletion drivers/lua/myuplink.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ DRIVER = {
id = "myuplink",
name = "MyUplink Heat Pump (telemetry)",
manufacturer = "MyUplink (NIBE, Bosch, Atlantic, Daikin, ...)",
version = "1.2.1",
version = "1.2.2",
protocols = { "http" },
capabilities = { "apicreds" },
-- Says what the header, the description and driver_command have always
Expand Down
2 changes: 1 addition & 1 deletion drivers/lua/nibe_local.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ DRIVER = {
id = "nibe-local",
name = "NIBE REST API S-series",
manufacturer = "NIBE",
version = "1.1.3",
version = "1.1.4",
protocols = { "http" },
capabilities = { "apicreds" },
-- Without this the channel infers control from driver_command and
Expand Down
12 changes: 6 additions & 6 deletions index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -423,25 +423,25 @@ drivers:
size_bytes: 3766
sha256: "5f985b8917aea7b08fba13c02506b45e40232a763393dc6af7c6eeb6ab5853af"
- name: "myuplink"
version: "1.2.1"
version: "1.2.2"
tier: core
protocol: http
connectivity: cloud
setup: [vendor_portal]
ders: [heatpump]
control: false
size_bytes: 17549
sha256: "6ac47f27388ba8c89e5aafc1b764f598a0fe8cb89e12bcabdae855419f8d5e42"
sha256: "0af1e129899c4c014b2e825d3efe13887dbc7f041cde6dbcb5496cc712e67bf9"
- name: "nibe_local"
version: "1.1.3"
version: "1.1.4"
tier: core
protocol: http
connectivity: local
setup: [device_screen]
ders: [heatpump]
control: false
size_bytes: 19446
sha256: "7f020f70eb4109c58f1af1097e37597280447fcbc95246b30e9638413592039e"
sha256: "2886420e43a42e225b02ff07bbf9166787727e89758b48ec6f4c356990a3bcd7"
- name: "opendtu"
version: "1.0.2"
tier: community
Expand Down Expand Up @@ -689,7 +689,7 @@ drivers:
size_bytes: 5784
sha256: "3cfcf53653680dede7caf6173cee251efa3cf2c9ec46fdc16a89b9b526dceb7e"
- name: "sonnen"
version: "2.0.1"
version: "2.0.2"
tier: community
protocol: http
connectivity: local
Expand Down Expand Up @@ -718,7 +718,7 @@ drivers:
size_bytes: 23154
sha256: "a708681364facbd09fb94a813050f6889d952a0178b392e51a64eddcc43fbf0d"
- name: "tibber"
version: "1.1.0"
version: "1.1.1"
tier: core
protocol: http
connectivity: cloud
Expand Down
4 changes: 2 additions & 2 deletions manifests/myuplink.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "myuplink"
version: "1.2.1"
version: "1.2.2"
tier: core
author: "Sourceful Labs AB"
protocol: http
Expand All @@ -23,7 +23,7 @@ upstream_docs:
min_host_version: "2.0.0"
size_bytes: 17549
dkb_id: "myuplink"
sha256: "6ac47f27388ba8c89e5aafc1b764f598a0fe8cb89e12bcabdae855419f8d5e42"
sha256: "0af1e129899c4c014b2e825d3efe13887dbc7f041cde6dbcb5496cc712e67bf9"
signature: ""

bytecode_sha256: ""
4 changes: 2 additions & 2 deletions manifests/nibe_local.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "nibe_local"
version: "1.1.3"
version: "1.1.4"
tier: core
author: "HuggeK with the help of Claude Code"
protocol: http
Expand All @@ -23,7 +23,7 @@ upstream_docs:
min_host_version: "2.0.0"
size_bytes: 19446
dkb_id: "nibe_local"
sha256: "7f020f70eb4109c58f1af1097e37597280447fcbc95246b30e9638413592039e"
sha256: "2886420e43a42e225b02ff07bbf9166787727e89758b48ec6f4c356990a3bcd7"
signature: ""

bytecode_sha256: ""
2 changes: 1 addition & 1 deletion manifests/sonnen.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "sonnen"
version: "2.0.1"
version: "2.0.2"
tier: community
author: "Sourceful Labs AB"
protocol: http
Expand Down
2 changes: 1 addition & 1 deletion manifests/tibber.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "tibber"
version: "1.1.0"
version: "1.1.1"
tier: core
author: "Sourceful Labs AB"
protocol: http
Expand Down
8 changes: 4 additions & 4 deletions support-status.json
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@
},
{
"catalog_source": true,
"catalog_version": "1.2.1",
"catalog_version": "1.2.2",
"driver_id": "myuplink",
"package_id": null,
"targets": {
Expand Down Expand Up @@ -1318,7 +1318,7 @@
},
{
"catalog_source": true,
"catalog_version": "1.1.3",
"catalog_version": "1.1.4",
"driver_id": "nibe_local",
"package_id": null,
"targets": {
Expand Down Expand Up @@ -2102,7 +2102,7 @@
},
{
"catalog_source": true,
"catalog_version": "2.0.1",
"catalog_version": "2.0.2",
"driver_id": "sonnen",
"package_id": null,
"targets": {
Expand Down Expand Up @@ -2186,7 +2186,7 @@
},
{
"catalog_source": true,
"catalog_version": "1.1.0",
"catalog_version": "1.1.1",
"driver_id": "tibber",
"package_id": null,
"targets": {
Expand Down
15 changes: 15 additions & 0 deletions tests/test_ftw_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,21 @@ def test_nested_or_commented_controls_do_not_change_a_control_artifact(
assert "__sourceful_ftw_controls" not in entry["raw"].decode("utf-8")


def test_config_secrets_reach_the_generated_header(tmp_path: Path) -> None:
# FTW core parses only the generated header this tool prepends, never the
# source's own DRIVER block further down (srcfl/device-drivers#106) -- a
# secret name missing from the header is a name nothing on the host ever
# masks, and myuplink's client_secret/refresh_token shipped in the clear
# because of exactly that gap.
repo, config_path = single_driver_repo(tmp_path, "myuplink")

entry = _load_channel(config_path, repo)[0]

assert entry["metadata"]["config_secrets"] == ["client_secret", "refresh_token"]
header = entry["raw"].decode("utf-8").split("DRIVER = __sourceful_ftw_metadata", 1)[0]
assert 'config_secrets = { "client_secret", "refresh_token" },' in header


def test_driver_locator_skips_non_module_decoys() -> None:
source = '''-- DRIVER = { id = "commented" }
--[=[ DRIVER = { id = "long-commented" } ]=]
Expand Down
10 changes: 10 additions & 0 deletions tools/ftw_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ def _ftw_artifact(
protocols = metadata.get("protocols", [])
capabilities = metadata.get("capabilities", [])
tested_models = metadata.get("tested_models", [])
config_secrets = metadata.get("config_secrets", [])
fields = [
f" id = {_lua_string(metadata['id'])},",
f" name = {_lua_string(metadata['name'])},",
Expand All @@ -437,6 +438,8 @@ def _ftw_artifact(
fields.append(f" {name} = {_lua_string(value)},")
if tested_models:
fields.append(f" tested_models = {_lua_string_list(tested_models)},")
if config_secrets:
fields.append(f" config_secrets = {_lua_string_list(config_secrets)},")
# A driver that declares itself read-only keeps the guards: those are
# meters and telemetry gateways stating what they are. A driver the catalog
# marks control: true keeps the control path it was ported with.
Expand Down Expand Up @@ -714,6 +717,13 @@ def _load_channel(config_path: Path, repo_root: Path) -> list[dict[str, Any]]:
value = _string_field(body, output_name)
if value:
metadata[output_name] = value
# config_secrets names which config keys a host must mask (API
# responses, logs). FTW core parses only the generated header
# below, never the source's own DRIVER block, so a name missing
# here is a name nothing on the host ever masks.
config_secrets = _string_list_field(body, "config_secrets")
if config_secrets:
metadata["config_secrets"] = config_secrets

if auth_post_path and not controls:
metadata["auth_post_path"] = auth_post_path
Expand Down