Found while deriving SLM frontend types from the generated OpenAPI contract (#13138). The name-collision scan flagged NodeUpdate, NodeCreate and ConnectionTestRequest as declaring fields that do not exist in the contract; all three were confirmed against backend source.
Pydantic's default is extra="ignore", and none of these three models sets model_config to change it, so the surplus fields are dropped without an error. The request returns 200, and the UI reports success.
1. Edit Node silently discards every SSH/enrollment field (highest impact)
PATCH /api/nodes/{node_id} binds NodeUpdate (autobot-slm-backend/api/nodes.py:571-574), which declares exactly five fields (autobot-slm-backend/models/schemas.py:172-179):
hostname, ansible_name, ip_address, status, roles
The handler then does node_data.model_dump(exclude_unset=True) (autobot-slm-backend/api/nodes.py:588), so only those five can ever reach the DB.
The Edit-Node modal sends nine more (autobot-slm-frontend/src/components/AddNodeModal.vue:1123-1141):
ssh_user, ssh_port, auth_method, ssh_password, ssh_key,
auto_enroll, deploy_pki, import_existing, run_enrollment
All nine are discarded. What the user sees:
autobot-slm-frontend/src/components/AddNodeModal.vue:476-488 — "Deploy PKI certificates after saving" checkbox: no-op.
autobot-slm-frontend/src/components/AddNodeModal.vue:490-502 — "Re-run enrollment tasks" checkbox: no-op.
autobot-slm-frontend/src/components/AddNodeModal.vue:861 — validation forces the user to supply an SSH password whenever either checkbox is ticked (sshOpsRequested), i.e. a credential is demanded to enable an action that never happens.
autobot-slm-frontend/src/components/AddNodeModal.vue:203-227 and :272 — changing SSH user / port / auth method / password on an existing node: no-op, reported as addNodeModal.nodeUpdatedSuccessfully (autobot-slm-frontend/src/components/AddNodeModal.vue:1142).
2. Register Node silently discards ssh_key and deploy_pki
NodeCreate (autobot-slm-backend/models/schemas.py:156-169) has no ssh_key and no deploy_pki. ssh_key does not exist anywhere in autobot-slm-backend/api/nodes.py or autobot-slm-backend/models/schemas.py; the only key the backend uses is the fleet-wide one at autobot-slm-backend/api/nodes.py:2761 (_DEFAULT_SSH_KEY = config.path.ssh_key_path).
So a key pasted into the Add-Node form (autobot-slm-frontend/src/components/AddNodeModal.vue:1130, getSshKey()) is never used — enrollment silently falls back to the canonical inter-node key, which is a different trust decision from the one the operator made in the UI.
3. Connection test silently discards ssh_key
ConnectionTestRequest (autobot-slm-backend/models/schemas.py:471-478) accepts password but has no ssh_key, while the frontend type declares one (autobot-slm-frontend/src/types/slm.ts:270-277). A key-auth connection test therefore never tests the supplied key.
Which side is wrong
Deliberately not decided here, because it is a product question and #13138 is a frontend type-derivation task that must not change server contracts:
- Server is wrong -> add the fields to
NodeUpdate / NodeCreate / ConnectionTestRequest and implement the SSH/PKI/enrollment side effects. Note ssh_password and ssh_key on an update path need the same handling as the register path (never persisted in plain text, never echoed back — NodeResponse at autobot-slm-backend/models/schemas.py:182 correctly omits both today).
- Frontend is wrong -> remove the controls, and drop the validation rule that demands a password for them.
Either way the current state is worse than both: the UI collects an SSH password to perform an operation that cannot happen.
A third, cheap mitigation that is independent of the decision: set model_config = {"extra": "forbid"} on request models so an unknown field 422s instead of vanishing. Same root cause as #13051.
Until the decision is made, NodeCreate, NodeUpdate and ConnectionTestRequest cannot be derived from components['schemas'][...] in #13138 — deriving them turns the surplus fields into compile errors whose only silent fix is deleting UI controls. They are explicitly deferred there and blocked on this issue.
Verification path (no code execution required)
autobot-slm-backend/models/schemas.py:172-179 — NodeUpdate field list.
autobot-slm-backend/api/nodes.py:588 — model_dump(exclude_unset=True).
autobot-slm-frontend/src/components/AddNodeModal.vue:1123-1141 — the payload actually sent.
Related: #13051 (same silent-drop class, secrets API), #13138 (the derivation work that surfaced this), #13139 (endpoints with no response_model).
Found while deriving SLM frontend types from the generated OpenAPI contract (#13138). The name-collision scan flagged
NodeUpdate,NodeCreateandConnectionTestRequestas declaring fields that do not exist in the contract; all three were confirmed against backend source.Pydantic's default is
extra="ignore", and none of these three models setsmodel_configto change it, so the surplus fields are dropped without an error. The request returns200, and the UI reports success.1. Edit Node silently discards every SSH/enrollment field (highest impact)
PATCH /api/nodes/{node_id}bindsNodeUpdate(autobot-slm-backend/api/nodes.py:571-574), which declares exactly five fields (autobot-slm-backend/models/schemas.py:172-179):The handler then does
node_data.model_dump(exclude_unset=True)(autobot-slm-backend/api/nodes.py:588), so only those five can ever reach the DB.The Edit-Node modal sends nine more (
autobot-slm-frontend/src/components/AddNodeModal.vue:1123-1141):All nine are discarded. What the user sees:
autobot-slm-frontend/src/components/AddNodeModal.vue:476-488— "Deploy PKI certificates after saving" checkbox: no-op.autobot-slm-frontend/src/components/AddNodeModal.vue:490-502— "Re-run enrollment tasks" checkbox: no-op.autobot-slm-frontend/src/components/AddNodeModal.vue:861— validation forces the user to supply an SSH password whenever either checkbox is ticked (sshOpsRequested), i.e. a credential is demanded to enable an action that never happens.autobot-slm-frontend/src/components/AddNodeModal.vue:203-227and:272— changing SSH user / port / auth method / password on an existing node: no-op, reported asaddNodeModal.nodeUpdatedSuccessfully(autobot-slm-frontend/src/components/AddNodeModal.vue:1142).2. Register Node silently discards
ssh_keyanddeploy_pkiNodeCreate(autobot-slm-backend/models/schemas.py:156-169) has nossh_keyand nodeploy_pki.ssh_keydoes not exist anywhere inautobot-slm-backend/api/nodes.pyorautobot-slm-backend/models/schemas.py; the only key the backend uses is the fleet-wide one atautobot-slm-backend/api/nodes.py:2761(_DEFAULT_SSH_KEY = config.path.ssh_key_path).So a key pasted into the Add-Node form (
autobot-slm-frontend/src/components/AddNodeModal.vue:1130,getSshKey()) is never used — enrollment silently falls back to the canonical inter-node key, which is a different trust decision from the one the operator made in the UI.3. Connection test silently discards
ssh_keyConnectionTestRequest(autobot-slm-backend/models/schemas.py:471-478) acceptspasswordbut has nossh_key, while the frontend type declares one (autobot-slm-frontend/src/types/slm.ts:270-277). A key-auth connection test therefore never tests the supplied key.Which side is wrong
Deliberately not decided here, because it is a product question and #13138 is a frontend type-derivation task that must not change server contracts:
NodeUpdate/NodeCreate/ConnectionTestRequestand implement the SSH/PKI/enrollment side effects. Notessh_passwordandssh_keyon an update path need the same handling as the register path (never persisted in plain text, never echoed back —NodeResponseatautobot-slm-backend/models/schemas.py:182correctly omits both today).Either way the current state is worse than both: the UI collects an SSH password to perform an operation that cannot happen.
A third, cheap mitigation that is independent of the decision: set
model_config = {"extra": "forbid"}on request models so an unknown field 422s instead of vanishing. Same root cause as #13051.Until the decision is made,
NodeCreate,NodeUpdateandConnectionTestRequestcannot be derived fromcomponents['schemas'][...]in #13138 — deriving them turns the surplus fields into compile errors whose only silent fix is deleting UI controls. They are explicitly deferred there and blocked on this issue.Verification path (no code execution required)
autobot-slm-backend/models/schemas.py:172-179—NodeUpdatefield list.autobot-slm-backend/api/nodes.py:588—model_dump(exclude_unset=True).autobot-slm-frontend/src/components/AddNodeModal.vue:1123-1141— the payload actually sent.Related: #13051 (same silent-drop class, secrets API), #13138 (the derivation work that surfaced this), #13139 (endpoints with no
response_model).