fix(transport): remove the never-read Transport:SchemaVersionMajor option (review 2026-10-21 04/U1, 08/O3)
This commit is contained in:
@@ -27,7 +27,7 @@ bundle.scadabundle
|
||||
|
||||
`manifest.json` is always plaintext so the import wizard can display source provenance and artifact counts before the operator supplies a passphrase. `BundleManifest` carries: `BundleFormatVersion`, `SchemaVersion`, `CreatedAtUtc`, `SourceEnvironment`, `ExportedBy`, `ScadaBridgeVersion`, `ContentHash` (`sha256:<hex>` of the raw content bytes), optional `Encryption` metadata, a `Summary` (artifact counts by type), and a `Contents` list (one `ManifestContentEntry` per artifact with its `dependsOn` edges).
|
||||
|
||||
`BundleFormatVersion` is an integer gate: the importer requires `BundleFormatVersion` to equal `ManifestBuilder.CurrentBundleFormatVersion` (currently `1`) and rejects any other value — higher or lower — with `ManifestValidationResult.UnsupportedFormatVersion`. `TransportOptions.SchemaVersionMajor` is not read during import. Unknown entity types in `Contents` produce a preview-row classification of "unsupported" rather than aborting the whole import.
|
||||
`BundleFormatVersion` is an integer gate: the importer requires `BundleFormatVersion` to equal `ManifestBuilder.CurrentBundleFormatVersion` (currently `1`) and rejects any other value — higher or lower — with `ManifestValidationResult.UnsupportedFormatVersion`. There is no configurable schema-version option; both versions are code constants. Unknown entity types in `Contents` produce a preview-row classification of "unsupported" rather than aborting the whole import.
|
||||
|
||||
### Encrypted vs plaintext bundles
|
||||
|
||||
@@ -229,7 +229,6 @@ After import, template changes propagate to deployed instances through revision-
|
||||
| Key | Default | Description |
|
||||
|-----|---------|-------------|
|
||||
| `SourceEnvironment` | `"scadabridge"` | Environment label stamped in `manifest.json` and used in export filenames. |
|
||||
| `SchemaVersionMajor` | `1` | Major schema version stamped in exported manifests. Not read by the importer; import version-gating uses `ManifestBuilder.CurrentBundleFormatVersion` directly. |
|
||||
| `BundleSessionTtlMinutes` | `30` | TTL for an in-progress import session. |
|
||||
| `MaxBundleSizeMb` | `100` | Upload size cap; enforced before any decompression. |
|
||||
| `MaxBundleEntryCount` | `4` | Maximum ZIP entries (a valid bundle has exactly 2). |
|
||||
|
||||
@@ -498,7 +498,7 @@ The `manifest.json` file is always present in the ZIP root and is never encrypte
|
||||
|
||||
| Field | Description |
|
||||
|---|---|
|
||||
| `bundleFormatVersion` | Integer. Importer hard-refuses any value higher than what its `TransportOptions.SchemaVersionMajor` supports. Stays `1` through T18. |
|
||||
| `bundleFormatVersion` | Integer. Importer hard-refuses any value other than the code constant `ManifestBuilder.CurrentBundleFormatVersion`. Stays `1` through T18. The schema and format versions are code constants by design — there is no `Transport:SchemaVersionMajor` option (removed 2026-10-22; it was validated but never read). |
|
||||
| `schemaVersion` | Semver string. Minor increments are additive-only and accepted by older importers. T18 bumped this `1.0 → 1.1` (adding the `sites`/`dataConnections`/`instances` content arrays); a pre-T18 importer lists those new entries as "skipped — unsupported in this version" since `ManifestValidator` gates only on `bundleFormatVersion`. |
|
||||
| `createdAtUtc` | ISO-8601 UTC timestamp of when the export was created. |
|
||||
| `sourceEnvironment` | The `SourceEnvironment` name of the exporting cluster (from `TransportOptions`). Displayed in the import wizard and required to be retyped at the confirm step. |
|
||||
|
||||
@@ -84,8 +84,7 @@
|
||||
"MaxBundleSizeMb": 100,
|
||||
"MaxUnlockAttemptsPerSession": 3,
|
||||
"MaxUnlockAttemptsPerIpPerHour": 10,
|
||||
"Pbkdf2Iterations": 600000,
|
||||
"SchemaVersionMajor": 1
|
||||
"Pbkdf2Iterations": 600000
|
||||
},
|
||||
"Logging": {
|
||||
"MinimumLevel": "Information"
|
||||
|
||||
@@ -41,8 +41,6 @@ public sealed class TransportOptions
|
||||
public int MaxUnlockAttemptsPerIpPerHour { get; set; } = 10;
|
||||
/// <summary>Gets or sets the PBKDF2 iteration count used for passphrase key derivation.</summary>
|
||||
public int Pbkdf2Iterations { get; set; } = 600_000;
|
||||
/// <summary>Gets or sets the major version of the bundle schema this instance produces and accepts.</summary>
|
||||
public int SchemaVersionMajor { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name of the cluster/environment producing bundles. Stamped
|
||||
|
||||
@@ -60,10 +60,6 @@ public sealed class TransportOptionsValidator : OptionsValidatorBase<TransportOp
|
||||
$"ScadaBridge:Transport:Pbkdf2Iterations must be at least {MinPbkdf2Iterations:N0} " +
|
||||
$"(was {options.Pbkdf2Iterations}); a lower value silently weakens bundle key derivation.");
|
||||
|
||||
builder.RequireThat(options.SchemaVersionMajor > 0,
|
||||
$"ScadaBridge:Transport:SchemaVersionMajor must be positive " +
|
||||
$"(was {options.SchemaVersionMajor}); it is the major bundle-schema version this instance emits and accepts.");
|
||||
|
||||
builder.RequireThat(!string.IsNullOrWhiteSpace(options.SourceEnvironment),
|
||||
"ScadaBridge:Transport:SourceEnvironment must be a non-empty name; it is stamped into " +
|
||||
"BundleManifest.SourceEnvironment and the export filename.");
|
||||
|
||||
@@ -132,13 +132,15 @@ public class TransportOptionsValidatorTests
|
||||
Assert.Contains("MaxUnlockAttemptsPerIpPerHour", result.FailureMessage);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a zero major schema version is rejected.</summary>
|
||||
/// <summary>
|
||||
/// Verifies that there is no configurable schema-version option: the bundle schema
|
||||
/// version is the code constant <c>ManifestBuilder.CurrentSchemaVersion</c>, so an
|
||||
/// option would be a validated no-op (review 2026-10-21 04/U1, 08/O3).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ZeroSchemaVersionMajor_IsRejected()
|
||||
public void SchemaVersion_IsNotAConfigurableOption()
|
||||
{
|
||||
var result = Validate(new TransportOptions { SchemaVersionMajor = 0 });
|
||||
Assert.True(result.Failed);
|
||||
Assert.Contains("SchemaVersionMajor", result.FailureMessage);
|
||||
Assert.Null(typeof(TransportOptions).GetProperty("SchemaVersionMajor"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a blank source environment is rejected.</summary>
|
||||
|
||||
Reference in New Issue
Block a user