fix(transport): curate BundleLockedException on the management surface (register row 51)

ManagementService references Commons but not Transport, so MapFault could not
see BundleLockedException and the per-bundle 3-strike lockout reached the CLI
as "An internal error occurred (CorrelationId=...)" — the operator got a
correlation id instead of the reason, and no hint that further attempts on
that bundle would be refused.

Applies the pattern register row 44 established for BundleUnlockThrottledException:

- Relocate BundleLockedException from Transport/Import/ to
  Commons/Types/Transport/, beside BundleUnlockThrottledException. Both
  consumers (BundleImporter, CentralUI TransportImport) already carried the
  Commons.Types.Transport using, so no call-site edits were needed.
- Add curated catch arms in ManagementActor.HandlePreviewBundle and
  HandleImportBundle that rethrow as ManagementCommandException, so the
  message survives MapFault's disclosure filter.
- Mirror the row-44 throttle fault-mapping test for both handlers.
- Document the relocation in docs/components/Transport.md and
  docs/requirements/Component-Transport.md.

Tests: ManagementService 499 passed (+2 new), Transport 167 passed.
This commit is contained in:
Joseph Doherty
2026-08-15 11:37:36 -04:00
parent c6769ee95e
commit b449fe201a
6 changed files with 114 additions and 34 deletions
@@ -3567,6 +3567,17 @@ public class ManagementActor : ReceiveActor
{
throw new ManagementCommandException(ex.Message);
}
catch (BundleLockedException ex)
{
// Register row 51: the per-bundle 3-strike lockout. LoadAsync raises
// it from inside its own CryptographicException handler, so without
// this arm the operator saw MapFault's generic internal-error message
// plus a correlation id, never the reason. Listed ahead of the
// CryptographicException arm to keep the read order matching the
// importer's throw order (the two types are unrelated, so the
// ordering is documentation, not dispatch).
throw new ManagementCommandException(ex.Message);
}
catch (System.Security.Cryptography.CryptographicException)
{
throw new ManagementCommandException("Wrong passphrase or bundle was tampered.");
@@ -3632,6 +3643,17 @@ public class ManagementActor : ReceiveActor
{
throw new ManagementCommandException(ex.Message);
}
catch (BundleLockedException ex)
{
// Register row 51: the per-bundle 3-strike lockout. LoadAsync raises
// it from inside its own CryptographicException handler, so without
// this arm the operator saw MapFault's generic internal-error message
// plus a correlation id, never the reason. Listed ahead of the
// CryptographicException arm to keep the read order matching the
// importer's throw order (the two types are unrelated, so the
// ordering is documentation, not dispatch).
throw new ManagementCommandException(ex.Message);
}
catch (System.Security.Cryptography.CryptographicException)
{
throw new ManagementCommandException("Wrong passphrase or bundle was tampered.");