feat: migrate_secret RPC — allow users to change their secret without losing VM access #17

Closed
opened 2026-03-12 17:56:01 +00:00 by mahmoud · 1 comment
Owner

Problem

VMs are protected by a secret stored in plain text in OSIS. If a user changes their secret (via the UI cog
menu), all previously deployed VMs become permanently
inaccessible — start, stop, delete all return NotFound.
There is currently no recovery path.

Solution

Add a migrate_secret(old_secret, new_secret) RPC method
to ComputeService that atomically updates the secret on
all VMs the user owns.

RPC Method

migrate_secret(
    old_secret: str,
    new_secret: str,
) -> MigrateSecretResult

MigrateSecretResult = {
    migrated_count: u32   # VMs successfully updated
}

Behavior

  1. Scan all VMs in OSIS
  2. Collect every VM where secret matches old_secret
  3. If none found — return NotFound
    (proves the old secret is wrong, leaks nothing)
  4. Atomically update secret to new_secret on all
    matched VMs
  5. Return count of migrated VMs

Security Rules

  • Same security model as all other VM methods:
    wrong old_secret → NotFound (not "wrong secret")
  • new_secret must be non-empty — return InvalidInput
    if empty
  • old_secret == new_secret → return InvalidInput
    (no-op migration is a user error)
  • Empty string secret bypass still applies:
    if old_secret is empty, match all VMs with
    empty secret only (existing bypass behavior)

UI Integration

The "Change Secret" flow in the UI becomes:

  1. User clicks "Change Secret" in cog menu
  2. Dialog opens with two fields:
    • Current secret (password input)
    • New secret (password input + confirm)
    • [Generate] button for new secret
  3. On submit:
    a. Call migrate_secret(old, new)
    b. On success: update localStorage with new secret,
    show toast "✓ Secret updated — X VMs migrated"
    c. On NotFound: show "Current secret is incorrect"
    d. On error: show error message
  4. Old dialog (set secret for first time) stays
    unchanged — only shown when no secret exists

Schema Changes

  • cloud.oschema: add MigrateSecretResult type
  • cloud.oschema: add migrate_secret to ComputeService

Implementation Notes

  • Use a single OSIS transaction to update all VMs
    atomically if possible — avoid partial migration
  • If OSIS does not support transactions, update VMs
    one by one and report partial success in the result:
    MigrateSecretResult = {
    migrated_count: u32
    failed_count: u32
    }
  • The Explorer does NOT need changes — migration
    happens directly on the node server

Definition of Done

  • migrate_secret() implemented in rpc.rs
  • Returns NotFound on wrong old_secret
  • Returns InvalidInput on empty new_secret
  • Returns InvalidInput if old == new
  • All VMs with old_secret updated atomically
  • MigrateSecretResult returns correct count
  • UI: Change Secret dialog calls migrate_secret
  • UI: localStorage updated on success
  • UI: correct error messages shown per error type
  • docs/testing.md updated with migrate_secret example
### Problem VMs are protected by a secret stored in plain text in OSIS. If a user changes their secret (via the UI cog menu), all previously deployed VMs become permanently inaccessible — start, stop, delete all return NotFound. There is currently no recovery path. ### Solution Add a migrate_secret(old_secret, new_secret) RPC method to ComputeService that atomically updates the secret on all VMs the user owns. ### RPC Method migrate_secret( old_secret: str, new_secret: str, ) -> MigrateSecretResult MigrateSecretResult = { migrated_count: u32 # VMs successfully updated } ### Behavior 1. Scan all VMs in OSIS 2. Collect every VM where secret matches old_secret 3. If none found — return NotFound (proves the old secret is wrong, leaks nothing) 4. Atomically update secret to new_secret on all matched VMs 5. Return count of migrated VMs ### Security Rules - Same security model as all other VM methods: wrong old_secret → NotFound (not "wrong secret") - new_secret must be non-empty — return InvalidInput if empty - old_secret == new_secret → return InvalidInput (no-op migration is a user error) - Empty string secret bypass still applies: if old_secret is empty, match all VMs with empty secret only (existing bypass behavior) ### UI Integration The "Change Secret" flow in the UI becomes: 1. User clicks "Change Secret" in cog menu 2. Dialog opens with two fields: - Current secret (password input) - New secret (password input + confirm) - [Generate] button for new secret 3. On submit: a. Call migrate_secret(old, new) b. On success: update localStorage with new secret, show toast "✓ Secret updated — X VMs migrated" c. On NotFound: show "Current secret is incorrect" d. On error: show error message 4. Old dialog (set secret for first time) stays unchanged — only shown when no secret exists ### Schema Changes - cloud.oschema: add MigrateSecretResult type - cloud.oschema: add migrate_secret to ComputeService ### Implementation Notes - Use a single OSIS transaction to update all VMs atomically if possible — avoid partial migration - If OSIS does not support transactions, update VMs one by one and report partial success in the result: MigrateSecretResult = { migrated_count: u32 failed_count: u32 } - The Explorer does NOT need changes — migration happens directly on the node server ### Definition of Done - [x] migrate_secret() implemented in rpc.rs - [x] Returns NotFound on wrong old_secret - [x] Returns InvalidInput on empty new_secret - [x] Returns InvalidInput if old == new - [x] All VMs with old_secret updated atomically - [x] MigrateSecretResult returns correct count - [x] UI: Change Secret dialog calls migrate_secret - [x] UI: localStorage updated on success - [x] UI: correct error messages shown per error type - [x] docs/testing.md updated with migrate_secret example
mahmoud self-assigned this 2026-03-16 11:56:16 +00:00
mahmoud added this to the ACTIVE project 2026-03-16 11:56:18 +00:00
mahmoud added this to the now milestone 2026-03-16 11:56:23 +00:00
Author
Owner

Should be done now

Should be done now
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_compute#17
No description provided.