Skip to content
Merged
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
13 changes: 10 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@ dependencies = [
"cloud-sql-python-connector>=1.0.0",
"google-auth>=2.0.0",
"google-cloud-secret-manager>=2.16.0",
"pg8000>=1.29.0",
"pg8000>=1.31.5", # CVE-2025-61385: SQL injection fix
"yagmail>=0.15.293",
"keyring>=25.6.0",
"pyserial>=3.5",
# Security fixes for transitive dependencies
"urllib3>=2.6.3", # CVE-2026-21441: decompression bomb fixes
"aiohttp>=3.13.3", # CVE-2025-69223: zip bomb and DoS fixes
"authlib>=1.6.4", # CVE-2025-59420: JWT crit headers fix
"starlette>=0.49.1", # CVE-2025-62727: Range header DoS fix
"fonttools>=4.60.2", # CVE-2025-66034: arbitrary file write fix
"filelock>=3.20.1", # CVE-2025-68146: TOCTOU symlink attack fix
]

[project.optional-dependencies]
Expand All @@ -61,8 +68,8 @@ visualization = [
"plotly>=5.0.0",
]
mcp = [
"mcp[cli]>=0.1.0",
"fastmcp>=0.1.0",
"mcp[cli]>=1.23.0", # CVE-2025-66416: DNS rebinding protection fix
"fastmcp>=2.14.0", # Multiple security fixes including MCP 1.23+ update
]
dev = [
"pytest>=7.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/rtgs_lab_tools/device_configuration/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ def decode_both(ctx, system_uid, sensor_uid, verbose, log_file, no_postgres_log,
@click.option("--num-co2", type=int, default=0, help="Number of CO2 sensors")
@click.option("--num-o2", type=int, default=0, help="Number of O2 sensors")
@click.option("--num-pressure", type=int, default=0, help="Number of pressure sensors")
@click.option(
"--num-analog-mux", type=int, default=0, help="Number of analog mux sensors"
)
@add_common_options
@click.pass_context
@handle_common_errors("create-config")
Expand All @@ -368,6 +371,7 @@ def create_config(
num_co2,
num_o2,
num_pressure,
num_analog_mux,
verbose,
log_file,
no_postgres_log,
Expand Down Expand Up @@ -398,6 +402,7 @@ def create_config(
"numCO2": num_co2,
"numO2": num_o2,
"numPressure": num_pressure,
"numAnalogMux": num_analog_mux,
},
}
}
Expand Down Expand Up @@ -432,6 +437,7 @@ def create_config(
"num_co2": num_co2,
"num_o2": num_o2,
"num_pressure": num_pressure,
"num_analog_mux": num_analog_mux,
"note": note,
}
results = {
Expand Down
38 changes: 19 additions & 19 deletions src/rtgs_lab_tools/device_configuration/configurations/config.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
"config": {
"system": {
"logPeriod": 300,
"backhaulCount": 1,
"powerSaveMode": 2,
"loggingMode": 2,
"numAuxTalons": 1,
"numI2CTalons": 1,
"numSDI12Talons": 1
},
"sensors": {
"numET": 0,
"numHaar": 0,
"numSoil": 2,
"numApogeeSolar": 0,
"numCO2": 0,
"numO2": 0,
"numPressure": 0
}
"system": {
"logPeriod": 300,
"backhaulCount": 4,
"powerSaveMode": 1,
"loggingMode": 0,
"numAuxTalons": 1,
"numI2CTalons": 1,
"numSDI12Talons": 1
},
"sensors": {
"numET": 0,
"numHaar": 0,
"numSoil": 1,
"numApogeeSolar": 0,
"numCO2": 0,
"numO2": 0,
"numPressure": 0
}
}
}
}
1 change: 1 addition & 0 deletions src/rtgs_lab_tools/device_configuration/particle_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ def calculate_config_uid(config: Dict[str, Any]) -> Tuple[int, int]:
| (sensors.get("numCO2", 0) << 12)
| (sensors.get("numO2", 0) << 8)
| (sensors.get("numPressure", 0) << 4)
| sensors.get("numAnalogMux", 0)
)

return system_uid, sensor_uid
Expand Down
2 changes: 2 additions & 0 deletions src/rtgs_lab_tools/device_configuration/uid_decoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def decode_sensor_configuration_uid(uid: int) -> Dict[str, int]:
config["num_co2"] = (uid >> 12) & 0xF # 4 bits at position 12-15
config["num_o2"] = (uid >> 8) & 0xF # 4 bits at position 8-11
config["num_pressure"] = (uid >> 4) & 0xF # 4 bits at position 4-7
config["num_analog_mux"] = uid & 0xF # 4 bits at position 0-3

return config

Expand Down Expand Up @@ -98,6 +99,7 @@ def format_sensor_config(uid: int) -> str:
f"Num CO2 Sensors: {config['num_co2']}",
f"Num O2 Sensors: {config['num_o2']}",
f"Num Pressure Sensors: {config['num_pressure']}",
f"Num Analog Mux: {config['num_analog_mux']}",
]
return "\n".join(lines)

Expand Down
5 changes: 5 additions & 0 deletions src/rtgs_lab_tools/mcp_server/rtgs_lab_tools_mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@ async def device_configuration_create_config(
num_co2: int = 0,
num_o2: int = 0,
num_pressure: int = 0,
num_analog_mux: int = 0,
note: Optional[str] = None,
) -> Dict[str, Any]:
"""
Expand All @@ -810,6 +811,7 @@ async def device_configuration_create_config(
num_co2: Number of CO2 sensors (default: 0)
num_o2: Number of O2 sensors (default: 0)
num_pressure: Number of pressure sensors (default: 0)
num_analog_mux: Number of analog mux sensors (default: 0)
note: Description for this operation (optional)

Returns:
Expand Down Expand Up @@ -861,6 +863,8 @@ async def device_configuration_create_config(
str(num_o2),
"--num-pressure",
str(num_pressure),
"--num-analog-mux",
str(num_analog_mux),
]

if note:
Expand Down Expand Up @@ -890,6 +894,7 @@ async def device_configuration_create_config(
"numCO2": num_co2,
"numO2": num_o2,
"numPressure": num_pressure,
"numAnalogMux": num_analog_mux,
},
}
}
Expand Down
6 changes: 5 additions & 1 deletion tests/device_configuration/test_uid_decoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_decode_basic_sensor_config(self):
"""Test decoding a basic sensor configuration UID."""
# Create a test UID with known values
# num_et=0, num_haar=0, num_soil=1, num_apogee_solar=0,
# num_co2=0, num_o2=0, num_pressure=0
# num_co2=0, num_o2=0, num_pressure=0, num_analog_mux=0
# 0x00100000 = 1048576
uid = 0x00100000

Expand All @@ -91,6 +91,7 @@ def test_decode_basic_sensor_config(self):
assert config["num_co2"] == 0
assert config["num_o2"] == 0
assert config["num_pressure"] == 0
assert config["num_analog_mux"] == 0

def test_decode_zero_sensor_uid(self):
"""Test decoding a zero sensor UID."""
Expand All @@ -113,6 +114,7 @@ def test_decode_max_sensor_values(self):
assert config["num_co2"] == 0xF # 4 bits
assert config["num_o2"] == 0xF # 4 bits
assert config["num_pressure"] == 0xF # 4 bits
assert config["num_analog_mux"] == 0xF # 4 bits

def test_decode_sensor_config_bit_masks(self):
"""Test specific bit mask operations for sensor config."""
Expand All @@ -128,6 +130,7 @@ def test_decode_sensor_config_bit_masks(self):
assert config["num_co2"] == (0x12345678 >> 12) & 0xF
assert config["num_o2"] == (0x12345678 >> 8) & 0xF
assert config["num_pressure"] == (0x12345678 >> 4) & 0xF
assert config["num_analog_mux"] == 0x12345678 & 0xF


class TestFormatSystemConfig:
Expand Down Expand Up @@ -182,6 +185,7 @@ def test_format_sensor_config_basic(self):
assert "Num CO2 Sensors: 0" in formatted
assert "Num O2 Sensors: 0" in formatted
assert "Num Pressure Sensors: 0" in formatted
assert "Num Analog Mux: 0" in formatted

def test_format_sensor_config_zero(self):
"""Test formatting a zero sensor configuration."""
Expand Down
Loading