Skip to content

Packs: secrets stay with their destination; restore keeps what this machine needs - #359

Merged
fylorn merged 1 commit into
feat/sync-backupfrom
feat/pack-fixes-2
Oct 19, 2026
Merged

fylorn merged 1 commit into
feat/sync-backupfrom
feat/pack-fixes-2

Conversation

@fylorn

@fylorn fylorn commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Review fixes for packs, import and restore on the sync-and-backup branch.

Import

  • A pack without secrets reuses the keys here only when overwriting an item whose destination is unchanged: same scheme, host and port (default ports filled in), AWS region, OAuth token endpoint, and proxy type and address. Otherwise the secret stays blank, the row is flagged missing_key, and the upstream comes in disabled. An item imported under another name never takes the keys here. Changing only the path keeps the keys.
  • A proxy with a blank password is flagged missing_key.

Restore

  • A route whose target names a group that is gone resolves to that group: kept (referenced) when the group is being removed, brought back when only the route is chosen.
  • Proxies referenced by this machine's own sections (the sync location's proxy) are kept; a whole restore copies the proxy definition over when the version lacks it.
  • Restoring a version from the sync location (sync-…) leaves sync.exclude upstreams, and the items that follow them, out of the comparison; they keep their current place in the order.
  • POST /backups/preview accepts items and runs the same plan as POST /backups/restore. The restore now answers RestoreWritten { version, rows }, where rows are the rows actually applied (dependencies included, kept set for what stayed).
  • Text that does not read as YAML is no longer recorded as a version; a whole restore takes this machine's sections from the newest readable version that differs from the current text.

Other

  • Pinned keys no longer expire. A source replaces its own set under one lock; at most 64 sources (the least recently reported goes), source up to 128 bytes, up to 1024 names of up to 256 bytes each, otherwise 400 with backup.pinned.source_too_long, backup.pinned.too_many or backup.pinned.name_too_long. The older file shapes (a plain array, or {"names": [...]}) read as the blank source.
  • Plugin files put back at startup are reloaded by the gateway. They are put back only when neither the script nor the approved copy matches the approved hash, so an unapproved edit is left alone.
  • The 64 KiB preference limit is checked for the preferences being written, and write_prefs refuses oversized ones for every writer; a large one already stored no longer blocks imports and restores.
  • A passphrase pack that needs more work than allowed reports pack.too_much_work (required, max) instead of pack.corrupt.

Tests

Regression tests cover each item: destination changes (host, port, scheme, AWS region, OAuth endpoint, proxy address) and rename, kept and chosen group routes, the sync proxy in partial and whole restores, excluded upstreams in a synced version, preview and write parity, readable versions, plugin healing and reload, pinned limits, concurrent reports and old files, stored oversized preferences, and the work-factor error.

🤖 Generated with Claude Code

…achine needs

Import
- A pack without secrets reuses the keys here only when overwriting an item
  whose destination is unchanged: same scheme, host and port, AWS region,
  OAuth token endpoint, and proxy type and address. Otherwise the secret
  stays blank, the row is flagged missing_key and the upstream comes in
  disabled. An item imported under another name never takes the keys here.
- A proxy whose password is blank is flagged missing_key too.

Restore
- A route that names a group which is gone resolves to that group: kept
  when it is being removed, brought back when only the route is chosen.
- Proxies used by this machine's own sections (the sync location's proxy)
  are kept; a whole restore copies the proxy over when the version lacks it.
- Restoring a version from the sync location leaves the upstreams this
  machine does not sync, and what follows them, out of the comparison.
- POST /backups/preview takes the chosen items and plans exactly what
  POST /backups/restore writes; the restore now answers RestoreWritten
  { version, rows } with the rows it actually applied.
- Text that does not read as YAML is no longer kept as a version, and a
  whole restore takes this machine's sections from the newest readable one.

Other
- Pinned keys no longer expire; a source replaces its own set, under one
  lock, with limits on sources, names and lengths (backup.pinned.*). The
  older file shapes read as the blank source.
- Plugin files put back at startup are reloaded by the gateway, and only
  when neither the script nor its approved copy matches the approved hash.
- The 64 KiB preference limit applies to the preferences being written,
  in every writer; a large one already stored does not block a restore.
- A passphrase-encrypted pack that asks for more work than allowed reports
  pack.too_much_work instead of pack.corrupt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn
fylorn force-pushed the feat/pack-fixes-2 branch from bcf0b57 to 7588d11 Compare October 19, 2026 11:05
@fylorn
fylorn merged commit 6867b1e into feat/sync-backup Oct 19, 2026
6 checks passed
@fylorn
fylorn deleted the feat/pack-fixes-2 branch October 19, 2026 11:26
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant