mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-26 05:56:50 +00:00
feat(connect): add device identity store and registration proof (#6267)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
d1a73b0a348845bf3ed9fb68301babc5abbc6e72243a610db1cd4794b1328070 canonical-hash.json
|
||||
f1107d3e6accbaee468f1a1fdb79d7103fb2aadafd85c39020fbbca5173b03b4 field-registry.json
|
||||
b3b2e7f761198d4823c94440637a48153437183f4cacec5118570e1920f73b29 old-agent-vectors.json
|
||||
bec2f30dea2fd4839e501acd94c9d935817f4f1b67cd14d33cad59c0351a23ea reject-vectors.json
|
||||
5493ba0d1477ad3762ed87c410d5830b47fe7aedac511f97b96385a51e258c32 secret-like-vectors.json
|
||||
6e2df36bf266fcca4b2c9a856d0a9ca8ab7e2cfaf7534b9af176c6597cb38137 unknown-field-vectors.json
|
||||
46e5d3398719a31dcc912379e66b4ab06a433d125366cce5239c49956fc4ab1b valid-vectors.json
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "canonical-hash",
|
||||
"description": "The canonical content hash of an L0 inventory snapshot, defined precisely enough that an independent implementation reproduces it byte for byte. The prose form is docs/data-collection/inventory-l0.md; this file is the machine-checkable copy.",
|
||||
"algorithm": "SHA-256",
|
||||
"output": {
|
||||
"encoding": "lowercase hexadecimal",
|
||||
"length": 64,
|
||||
"pattern": "^[0-9a-f]{64}$"
|
||||
},
|
||||
"hashedBytes": "domainPrefix followed immediately by canonicalJson encoded as UTF-8, with nothing between them and nothing after",
|
||||
"domainPrefix": {
|
||||
"ascii": "rustfs-connect/agent/v1/inventory-snapshot\n",
|
||||
"hex": "7275737466732d636f6e6e6563742f6167656e742f76312f696e76656e746f72792d736e617073686f740a",
|
||||
"byteLength": 43,
|
||||
"reason": "Domain separation. An inventory hash can never equal a heartbeat, bundle, or job hash computed over the same member values."
|
||||
},
|
||||
"input": {
|
||||
"startsFrom": "the normalized document, after the version gate, after unknown members and unknown coarse flag tokens have been discarded, and after schema and cross-field validation succeeded",
|
||||
"excludedMembers": ["protocolVersion"],
|
||||
"excludedMembersReason": "protocolVersion is negotiation input, not content. Excluding it means the same cluster state hashes identically across protocol versions, and it is why an unknown member can never change the hash.",
|
||||
"materializedDefaults": {
|
||||
"osVersion": null,
|
||||
"coarseFlags": []
|
||||
},
|
||||
"materializedDefaultsReason": "Absent optional members take their documented default and the default is serialized, so the canonical object always carries exactly the same seven member names. An old agent that omits an optional member and a new agent that sends its default explicitly produce the same hash."
|
||||
},
|
||||
"serialization": {
|
||||
"form": "one line of UTF-8 with no insignificant whitespace: no space after a colon or comma, no newline, no trailing newline",
|
||||
"objects": "{ then member,member,... then }, where a member is \"name\":value; an empty object is {}",
|
||||
"arrays": "[ then value,value,... then ]; an empty array is []",
|
||||
"memberOrder": "ascending by the UTF-8 bytes of the member name, compared as unsigned bytes; no locale, no case folding, no UTF-16 code unit order",
|
||||
"arrayOrder": "the normalized order, which for coarseFlags is de-duplicated and sorted ascending by the same unsigned-byte comparison",
|
||||
"null": "the four bytes null",
|
||||
"integers": "base ten, no plus sign, no leading zero except the single digit 0, no decimal point, no exponent; every v1 value is in 0..9007199254740991 so no implementation needs arbitrary precision",
|
||||
"strings": "opened and closed by a double quote with the value's bytes between them",
|
||||
"stringEscaping": "none is ever emitted. Every string value the canonical input can hold matches ^[a-z0-9.]{1,32}$ and every member name matches ^[a-zA-Z]{1,32}$, so no character requiring a JSON escape can reach the hash. A value outside those classes is a schema violation and is rejected before hashing.",
|
||||
"canonicalValueCharacterClass": "^[a-z0-9.]{1,32}$",
|
||||
"canonicalMemberNameCharacterClass": "^[a-zA-Z]{1,32}$",
|
||||
"absentTypes": "the canonical input contains no boolean, no floating point number, and no nested array of objects. Adding a member of one of those types requires extending these rules in a reviewed protocol change."
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"name": "fully populated snapshot",
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"canonicalJsonByteLength": 225,
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f"
|
||||
},
|
||||
{
|
||||
"name": "every limit at its maximum",
|
||||
"canonicalJson": "{\"capacityTotalBytes\":9007199254740991,\"capacityUsedBytes\":9007199254740991,\"coarseFlags\":[\"capacity.critical\",\"capacity.warning\",\"clock.skew\",\"cluster.degraded\",\"cluster.healing\",\"cluster.readonly\",\"drive.offline\",\"node.offline\"],\"driveCount\":1048576,\"nodeCount\":4096,\"osVersion\":{\"family\":\"other\",\"major\":9999,\"minor\":9999},\"rustfsVersion\":\"9999.9999.9999\"}",
|
||||
"canonicalJsonByteLength": 359,
|
||||
"contentHash": "b69d51f898a53562a7057faa5bda1e21699ee6615517cd8b1455096f9171bce4"
|
||||
},
|
||||
{
|
||||
"name": "every limit at its minimum",
|
||||
"canonicalJson": "{\"capacityTotalBytes\":0,\"capacityUsedBytes\":0,\"coarseFlags\":[],\"driveCount\":0,\"nodeCount\":1,\"osVersion\":null,\"rustfsVersion\":\"0.0.0\"}",
|
||||
"canonicalJsonByteLength": 133,
|
||||
"contentHash": "08ebc03ee906c05d686ef32c0998154213f2811a2d07408a9ef7d0b205cc701b"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "field-registry",
|
||||
"description": "The frozen v1 inventory snapshot envelope. Every collected member cites its data-collection registry id from protocol/data-collection-fields.json. Any member not listed here is unknown: it is accepted, discarded before validation, never persisted, never echoed back, and its raw text is never logged.",
|
||||
"envelope": "InventorySnapshot",
|
||||
"schema": "protocol/agent/v1/inventory-snapshot.schema.json",
|
||||
"classificationRegistry": "protocol/data-collection-fields.json",
|
||||
"level": "L0",
|
||||
"source": "inventory",
|
||||
"retentionDays": 90,
|
||||
"cadence": "per-inventory",
|
||||
"supportedMajorVersions": [1],
|
||||
"protocolVersionPattern": "^v[1-9][0-9]{0,3}$",
|
||||
"unknownFieldPolicy": "accept-and-discard",
|
||||
"unknownCoarseFlagPolicy": "discard",
|
||||
"unknownMajorVersionPolicy": "reject",
|
||||
"fields": [
|
||||
{
|
||||
"name": "protocolVersion",
|
||||
"registryId": null,
|
||||
"collected": false,
|
||||
"requiredness": "required",
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "string",
|
||||
"pattern": "^v[1-9][0-9]{0,3}$"
|
||||
},
|
||||
"includedInContentHash": false,
|
||||
"note": "Negotiation input shared with the frozen v1 negotiation envelope. It gates processing, is never persisted as an inventory attribute, and therefore has no data-collection registry id."
|
||||
},
|
||||
{
|
||||
"name": "rustfsVersion",
|
||||
"registryId": "inventory.rustfsVersion",
|
||||
"collected": true,
|
||||
"requiredness": "required",
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "string",
|
||||
"pattern": "^(0|[1-9][0-9]{0,3})\\.(0|[1-9][0-9]{0,3})\\.(0|[1-9][0-9]{0,3})$"
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "Coarse release only. Pre-release and build metadata are rejected because a build identifier fingerprints a private build."
|
||||
},
|
||||
{
|
||||
"name": "osVersion",
|
||||
"registryId": "inventory.osVersion",
|
||||
"collected": true,
|
||||
"requiredness": "optional",
|
||||
"type": ["object", "null"],
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": false,
|
||||
"required": ["family", "major", "minor"]
|
||||
},
|
||||
"memberLimits": {
|
||||
"family": {
|
||||
"type": "string",
|
||||
"enum": ["linux", "darwin", "windows", "freebsd", "other"]
|
||||
},
|
||||
"major": { "type": "integer", "minimum": 0, "maximum": 9999 },
|
||||
"minor": { "type": "integer", "minimum": 0, "maximum": 9999 }
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "The family is a closed vocabulary, never free text. An unlisted operating system reports 'other'. Unknown members of this object are discarded exactly like unknown top-level members."
|
||||
},
|
||||
{
|
||||
"name": "nodeCount",
|
||||
"registryId": "inventory.nodeCount",
|
||||
"collected": true,
|
||||
"requiredness": "required",
|
||||
"type": "integer",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 4096
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "A cluster reporting inventory has at least one node."
|
||||
},
|
||||
{
|
||||
"name": "driveCount",
|
||||
"registryId": "inventory.driveCount",
|
||||
"collected": true,
|
||||
"requiredness": "required",
|
||||
"type": "integer",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1048576
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "Zero is legal while a cluster is being provisioned."
|
||||
},
|
||||
{
|
||||
"name": "capacityTotalBytes",
|
||||
"registryId": "inventory.capacityTotalBytes",
|
||||
"collected": true,
|
||||
"requiredness": "required",
|
||||
"type": "integer",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "2^53-1 is the largest integer Rust u64, PHP int, JavaScript number, and JSON all represent exactly. Above the cap is a validation error, never a silent truncation."
|
||||
},
|
||||
{
|
||||
"name": "capacityUsedBytes",
|
||||
"registryId": "inventory.capacityUsedBytes",
|
||||
"collected": true,
|
||||
"requiredness": "required",
|
||||
"type": "integer",
|
||||
"default": null,
|
||||
"limits": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "Must not exceed capacityTotalBytes. JSON Schema cannot compare two members, so the validator enforces that invariant separately."
|
||||
},
|
||||
{
|
||||
"name": "coarseFlags",
|
||||
"registryId": "inventory.coarseFlags",
|
||||
"collected": true,
|
||||
"requiredness": "optional",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"limits": {
|
||||
"type": "array",
|
||||
"maxItems": 8,
|
||||
"uniqueItems": true
|
||||
},
|
||||
"itemLimits": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"capacity.critical",
|
||||
"capacity.warning",
|
||||
"clock.skew",
|
||||
"cluster.degraded",
|
||||
"cluster.healing",
|
||||
"cluster.readonly",
|
||||
"drive.offline",
|
||||
"node.offline"
|
||||
]
|
||||
},
|
||||
"includedInContentHash": true,
|
||||
"note": "Allow-listed conditions only. Normalization discards unknown tokens, de-duplicates, and sorts ascending by UTF-8 bytes, so agent-side ordering never changes the content hash."
|
||||
}
|
||||
],
|
||||
"errorReasons": {
|
||||
"description": "Inventory-scoped ErrorInfo reasons. The negotiation reason is not redeclared here: an unsupported major version fails with UNSUPPORTED_PROTOCOL from protocol/agent/v1/fixtures/auth/error-codes.json, before any inventory member is read. INVENTORY_FIELD_INVALID is new in this issue and must not collide with a reason already frozen for authentication.",
|
||||
"versionFailure": "UNSUPPORTED_PROTOCOL",
|
||||
"payloadFailure": {
|
||||
"reason": "INVENTORY_FIELD_INVALID",
|
||||
"status": "INVALID_ARGUMENT",
|
||||
"httpStatus": 400,
|
||||
"domain": "rustfs.connect",
|
||||
"meaning": "The normalized inventory snapshot violates the frozen schema or a cross-field invariant."
|
||||
},
|
||||
"disclosureRules": [
|
||||
"A rejection names the frozen member path that failed and never the value that failed.",
|
||||
"A rejection never names, quotes, or counts an unknown member, so discarded text cannot reach an error body or a log line.",
|
||||
"A raw input bound rejection names the bound that was exceeded and never the body."
|
||||
]
|
||||
},
|
||||
"rawInputBounds": {
|
||||
"description": "Denial-of-service bounds applied to the raw body after the version gate and before normalization. They are deliberately far above what a v1 snapshot needs so that additive growth never trips them. A violation is rejected without naming or echoing the offending value.",
|
||||
"maxBodyBytes": 8192,
|
||||
"maxDepth": 8,
|
||||
"maxTopLevelMembers": 64,
|
||||
"maxRawCoarseFlagItems": 64,
|
||||
"reason": "INVENTORY_FIELD_INVALID",
|
||||
"httpStatus": 400
|
||||
},
|
||||
"crossFieldInvariants": [
|
||||
{
|
||||
"name": "usedNeverExceedsTotal",
|
||||
"expression": "capacityUsedBytes <= capacityTotalBytes",
|
||||
"reason": "INVENTORY_FIELD_INVALID"
|
||||
}
|
||||
],
|
||||
"forbiddenFieldClasses": {
|
||||
"description": "L0 inventory cannot express any of these. The frozen schema sets additionalProperties false at every level and every string member is an enum or a numeric-component pattern, so none of these sample values can be carried by any member, known or unknown, that survives normalization.",
|
||||
"classes": [
|
||||
{ "class": "bucket", "samples": ["customer-backups", "prod-media-eu"] },
|
||||
{ "class": "object", "samples": ["invoices/2026/08/inv-1.pdf", "db-dump.sql.gz"] },
|
||||
{ "class": "path", "samples": ["/var/lib/rustfs/data/disk1", "C:\\rustfs\\data"] },
|
||||
{ "class": "endpoint", "samples": ["https://rustfs.internal:9000", "10.4.2.17:9000", "node-3.storage.example.com"] },
|
||||
{ "class": "configuration", "samples": ["RUSTFS_ERASURE_SET_SIZE=12", "{\"tls\":{\"minVersion\":\"1.3\"}}"] },
|
||||
{ "class": "credential", "samples": ["AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "Bearer eyJhbGciOiJIUzI1NiJ9.e30.c2ln", "-----BEGIN PRIVATE KEY-----"] },
|
||||
{ "class": "identifier", "samples": ["node-3.storage.example.com", "aa:bb:cc:dd:ee:ff", "acme-corp"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "old-agent-vectors",
|
||||
"description": "Release skew in both directions, plus the version gate. The version rule is not restated here: it is the one frozen in protocol/agent/v1/fixtures/version/field-registry.json, and the inventory field registry repeats its pattern and supported majors so the two can be compared. An unsupported major fails closed before any inventory member is read, so nothing is normalized, validated, hashed, stored, or echoed.",
|
||||
"versionRule": {
|
||||
"inheritedFrom": "protocol/agent/v1/fixtures/version/field-registry.json",
|
||||
"protocolVersionPattern": "^v[1-9][0-9]{0,3}$",
|
||||
"supportedMajorVersions": [1],
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400
|
||||
},
|
||||
"baseContentHash": "1d6f2b1d767df63fbf72d6f7abcc98d5c47ed6783739e449f898ea5898e5e356",
|
||||
"vectors": [
|
||||
{
|
||||
"name": "old agent omits every optional member",
|
||||
"category": "old-agent",
|
||||
"direction": "old-agent-to-new-connect",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": { "osVersion": null, "coarseFlags": [] },
|
||||
"canonicalJson": "{\"capacityTotalBytes\":549755813888,\"capacityUsedBytes\":137438953472,\"coarseFlags\":[],\"driveCount\":16,\"nodeCount\":4,\"osVersion\":null,\"rustfsVersion\":\"1.0.0\"}",
|
||||
"contentHash": "1d6f2b1d767df63fbf72d6f7abcc98d5c47ed6783739e449f898ea5898e5e356",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newer agent sends the documented defaults explicitly",
|
||||
"category": "old-agent",
|
||||
"direction": "new-agent-to-old-connect",
|
||||
"sameContentHashAs": "old agent omits every optional member",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.0.0",
|
||||
"osVersion": null,
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472,
|
||||
"coarseFlags": []
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":549755813888,\"capacityUsedBytes\":137438953472,\"coarseFlags\":[],\"driveCount\":16,\"nodeCount\":4,\"osVersion\":null,\"rustfsVersion\":\"1.0.0\"}",
|
||||
"contentHash": "1d6f2b1d767df63fbf72d6f7abcc98d5c47ed6783739e449f898ea5898e5e356",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newer agent adds a member this Connect does not know",
|
||||
"category": "old-agent",
|
||||
"direction": "new-agent-to-old-connect",
|
||||
"sameContentHashAs": "old agent omits every optional member",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472,
|
||||
"poolCount": 2
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes"
|
||||
],
|
||||
"discarded": ["poolCount"],
|
||||
"defaultsApplied": { "osVersion": null, "coarseFlags": [] },
|
||||
"canonicalJson": "{\"capacityTotalBytes\":549755813888,\"capacityUsedBytes\":137438953472,\"coarseFlags\":[],\"driveCount\":16,\"nodeCount\":4,\"osVersion\":null,\"rustfsVersion\":\"1.0.0\"}",
|
||||
"contentHash": "1d6f2b1d767df63fbf72d6f7abcc98d5c47ed6783739e449f898ea5898e5e356",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "next major version from a future agent",
|
||||
"category": "old-agent",
|
||||
"direction": "new-agent-to-old-connect",
|
||||
"input": {
|
||||
"protocolVersion": "v2",
|
||||
"rustfsVersion": "2.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "REJECT",
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400,
|
||||
"retained": [],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": null,
|
||||
"contentHash": null,
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "far future major version",
|
||||
"category": "old-agent",
|
||||
"direction": "new-agent-to-old-connect",
|
||||
"input": {
|
||||
"protocolVersion": "v9999",
|
||||
"rustfsVersion": "9999.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "REJECT",
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400,
|
||||
"retained": [],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": null,
|
||||
"contentHash": null,
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a secret-like unknown member does not rescue an unsupported major version",
|
||||
"category": "old-agent",
|
||||
"direction": "new-agent-to-old-connect",
|
||||
"input": {
|
||||
"protocolVersion": "v2",
|
||||
"compatibilityShim": "v1",
|
||||
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"rustfsVersion": "2.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "REJECT",
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400,
|
||||
"retained": [],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": null,
|
||||
"contentHash": null,
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "an agent that omits the protocol version",
|
||||
"category": "old-agent",
|
||||
"direction": "old-agent-to-new-connect",
|
||||
"input": {
|
||||
"rustfsVersion": "1.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "REJECT",
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400,
|
||||
"retained": [],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": null,
|
||||
"contentHash": null,
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a dotted protocol version is not a major version",
|
||||
"category": "old-agent",
|
||||
"direction": "old-agent-to-new-connect",
|
||||
"input": {
|
||||
"protocolVersion": "v1.2",
|
||||
"rustfsVersion": "1.0.0",
|
||||
"nodeCount": 4,
|
||||
"driveCount": 16,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 137438953472
|
||||
},
|
||||
"expected": {
|
||||
"decision": "REJECT",
|
||||
"reason": "UNSUPPORTED_PROTOCOL",
|
||||
"httpStatus": 400,
|
||||
"retained": [],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": null,
|
||||
"contentHash": null,
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "reject-vectors",
|
||||
"description": "Snapshots the frozen schema and its cross-field invariant refuse. Every vector is rejected after normalization, so nothing here is stored, echoed, or hashed. violation names the member and the schema keyword that must fire; a rejection that fires on a different member is as much a regression as one that does not fire at all. The negative category covers malformed, missing, negative, and mistyped values; the overflow category covers values above a frozen maximum.",
|
||||
"reason": "INVENTORY_FIELD_INVALID",
|
||||
"status": "INVALID_ARGUMENT",
|
||||
"httpStatus": 400,
|
||||
"vectors": [
|
||||
{
|
||||
"name": "a node count of zero",
|
||||
"category": "negative",
|
||||
"violation": { "member": "nodeCount", "rule": "minimum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 0,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a negative node count",
|
||||
"category": "negative",
|
||||
"violation": { "member": "nodeCount", "rule": "minimum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": -1,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a negative drive count",
|
||||
"category": "negative",
|
||||
"violation": { "member": "driveCount", "rule": "minimum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": -1,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a negative used capacity",
|
||||
"category": "negative",
|
||||
"violation": { "member": "capacityUsedBytes", "rule": "minimum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": -1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a negative capacity on both members",
|
||||
"category": "negative",
|
||||
"violation": { "member": "capacityTotalBytes", "rule": "minimum" },
|
||||
"note": "A negative total with a non-negative used member would break the cross-field invariant as well, which would make it ambiguous which rule fired. Both members are negative so the minimum keyword is the only thing this vector can trip.",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": -1,
|
||||
"capacityUsedBytes": -1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a negative operating system major version",
|
||||
"category": "negative",
|
||||
"violation": { "member": "osVersion.major", "rule": "minimum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": -1, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a missing RustFS version",
|
||||
"category": "negative",
|
||||
"violation": { "member": "rustfsVersion", "rule": "required" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a missing used capacity",
|
||||
"category": "negative",
|
||||
"violation": { "member": "capacityUsedBytes", "rule": "required" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a two component RustFS version",
|
||||
"category": "negative",
|
||||
"violation": { "member": "rustfsVersion", "rule": "pattern" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a RustFS version carrying pre-release and build metadata",
|
||||
"category": "negative",
|
||||
"violation": { "member": "rustfsVersion", "rule": "pattern" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2-rc.1+9f2c1a",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a RustFS version component with a leading zero",
|
||||
"category": "negative",
|
||||
"violation": { "member": "rustfsVersion", "rule": "pattern" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "01.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "an operating system family outside the closed vocabulary",
|
||||
"category": "negative",
|
||||
"violation": { "member": "osVersion.family", "rule": "enum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "ubuntu", "major": 24, "minor": 4 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "an operating system version missing its minor component",
|
||||
"category": "negative",
|
||||
"violation": { "member": "osVersion.minor", "rule": "required" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "used capacity above total capacity",
|
||||
"category": "negative",
|
||||
"violation": { "member": "capacityUsedBytes", "rule": "usedNeverExceedsTotal" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 1099511627777
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a node count sent as a string",
|
||||
"category": "negative",
|
||||
"violation": { "member": "nodeCount", "rule": "type" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": "8",
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a fractional capacity",
|
||||
"category": "negative",
|
||||
"violation": { "member": "capacityTotalBytes", "rule": "type" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776.5,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coarse flags sent as a string",
|
||||
"category": "negative",
|
||||
"violation": { "member": "coarseFlags", "rule": "type" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": "cluster.degraded"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "an operating system version sent as a string",
|
||||
"category": "negative",
|
||||
"violation": { "member": "osVersion", "rule": "type" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": "linux 6.8",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a node count above the frozen maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "nodeCount", "rule": "maximum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 4097,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a drive count above the frozen maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "driveCount", "rule": "maximum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 1048577,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a total capacity one byte above the exactly representable maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "capacityTotalBytes", "rule": "maximum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 9007199254740992,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "both capacities one byte above the exactly representable maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "capacityUsedBytes", "rule": "maximum" },
|
||||
"note": "The used member carries the same cap as the total member. Used capacity can only exceed the cap when total capacity does too, so this vector raises both and asserts the used member is bounded in its own right.",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 9007199254740992,
|
||||
"capacityUsedBytes": 9007199254740992
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a RustFS version component above the frozen maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "rustfsVersion", "rule": "pattern" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "10000.0.0",
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "an operating system major version above the frozen maximum",
|
||||
"category": "overflow",
|
||||
"violation": { "member": "osVersion.major", "rule": "maximum" },
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 10000, "minor": 0 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "secret-like-vectors",
|
||||
"description": "An agent, a proxy, or an attacker attaches credential-shaped and customer-identifying members to an otherwise valid snapshot. Every one is an unknown optional member, so the frozen rule applies unchanged: accepted, discarded, never persisted, never echoed back, and never logged in raw form. Rejecting them instead would break additive compatibility and would put the secret text into an error message, so discarding is the safer and the frozen behaviour. Each vector carries the same content hash as the valid fixture's fully populated snapshot, which proves nothing here reaches storage. The literal values below are non-functional examples, not real credentials.",
|
||||
"baseVector": "fully populated snapshot",
|
||||
"baseContentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"errorMessagesNameUnknownMembers": false,
|
||||
"vectors": [
|
||||
{
|
||||
"name": "S3 access key and secret key attached to the snapshot",
|
||||
"category": "secret-like",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"secretLikeMembers": ["accessKeyId", "secretAccessKey", "sessionToken"],
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
|
||||
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"sessionToken": "FwoGZXIvYXdzEExampleSessionTokenValue"
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["accessKeyId", "secretAccessKey", "sessionToken"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bearer token and private key material attached to the snapshot",
|
||||
"category": "secret-like",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"secretLikeMembers": ["authorization", "devicePrivateKeyPem", "kmsMasterKey"],
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.e30.c2lnbmF0dXJl",
|
||||
"devicePrivateKeyPem": "-----BEGIN PRIVATE KEY-----\nMEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCBleGFtcGxl\n-----END PRIVATE KEY-----",
|
||||
"kmsMasterKey": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["authorization", "devicePrivateKeyPem", "kmsMasterKey"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bucket object path and endpoint members attached to the snapshot",
|
||||
"category": "secret-like",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"secretLikeMembers": ["buckets", "largestObjectKey", "dataPaths", "endpoint"],
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"buckets": ["customer-backups", "prod-media-eu"],
|
||||
"largestObjectKey": "invoices/2026/08/inv-1.pdf",
|
||||
"dataPaths": ["/var/lib/rustfs/data/disk1", "C:\\rustfs\\data"],
|
||||
"endpoint": "https://rustfs.internal:9000"
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["buckets", "dataPaths", "endpoint", "largestObjectKey"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "redacted configuration and customer identifiers attached to the snapshot",
|
||||
"category": "secret-like",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"secretLikeMembers": ["configuration", "customerName", "nodeHostnames"],
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"configuration": { "tls": { "minVersion": "1.3" }, "erasure": "RUSTFS_ERASURE_SET_SIZE=12" },
|
||||
"customerName": "acme-corp",
|
||||
"nodeHostnames": ["node-3.storage.example.com", "10.4.2.17"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["configuration", "customerName", "nodeHostnames"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "secret material hidden inside osVersion and inside a coarse flag token",
|
||||
"category": "secret-like",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"secretLikeMembers": ["osVersion.licenseKey", "coarseFlags[akiaiosfodnn7example]"],
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": {
|
||||
"family": "linux",
|
||||
"major": 6,
|
||||
"minor": 8,
|
||||
"licenseKey": "RUSTFS-PROD-4821-9930-ACME"
|
||||
},
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline", "akiaiosfodnn7example"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["coarseFlags[akiaiosfodnn7example]", "osVersion.licenseKey"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "unknown-field-vectors",
|
||||
"description": "Unknown optional members and unknown coarse flag tokens. Every one is accepted, discarded before validation, never persisted, never echoed back, and never logged in raw form. Every vector here carries the same content hash as the valid fixture's fully populated snapshot, which is the executable statement that an unknown member cannot influence stored inventory. The discarded list is bookkeeping: its membership is the contract, not its order.",
|
||||
"baseVector": "fully populated snapshot",
|
||||
"baseContentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"vectors": [
|
||||
{
|
||||
"name": "one unknown optional member from a newer agent",
|
||||
"category": "unknown-field",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"telemetryProfile": "extended"
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["telemetryProfile"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unknown optional members of every JSON type at once",
|
||||
"category": "unknown-field",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"erasureSetSize": 12,
|
||||
"experimentalFlags": { "fastInventory": true },
|
||||
"regionHints": ["eu-west", "us-east"],
|
||||
"supersededBy": null,
|
||||
"telemetryProfile": "extended"
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [
|
||||
"erasureSetSize",
|
||||
"experimentalFlags",
|
||||
"regionHints",
|
||||
"supersededBy",
|
||||
"telemetryProfile"
|
||||
],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unknown member nested inside osVersion",
|
||||
"category": "unknown-field",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": {
|
||||
"family": "linux",
|
||||
"major": 6,
|
||||
"minor": 8,
|
||||
"distribution": "debian",
|
||||
"kernelRelease": "6.8.0-41-generic"
|
||||
},
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["osVersion.distribution", "osVersion.kernelRelease"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coarse flag tokens this Connect does not know",
|
||||
"category": "unknown-field",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": [
|
||||
"cluster.degraded",
|
||||
"drive.offline",
|
||||
"rebalance.pending",
|
||||
"tier.transition.stalled"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [
|
||||
"coarseFlags[rebalance.pending]",
|
||||
"coarseFlags[tier.transition.stalled]"
|
||||
],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "near-miss member names are unknown because matching is exact and case sensitive",
|
||||
"category": "unknown-field",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"],
|
||||
"RustfsVersion": "1.4.2",
|
||||
"capacityFreeBytes": 687194767360,
|
||||
"capacity_used_bytes": 412316860416,
|
||||
"nodeCounts": 8
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [
|
||||
"RustfsVersion",
|
||||
"capacityFreeBytes",
|
||||
"capacity_used_bytes",
|
||||
"nodeCounts"
|
||||
],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
{
|
||||
"protocolVersion": "v1",
|
||||
"fixtureSet": "inventory",
|
||||
"fixture": "valid-vectors",
|
||||
"description": "Accepted L0 inventory snapshots with their normalized form, canonical hash input, and content hash. canonicalJson is the exact byte string that is hashed after the domain prefix, so an independent implementation can diff its serialization before it ever compares a digest.",
|
||||
"vectors": [
|
||||
{
|
||||
"name": "fully populated snapshot",
|
||||
"category": "valid",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["cluster.degraded", "drive.offline"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unsorted duplicated and unknown coarse flags normalize to the same snapshot",
|
||||
"category": "valid",
|
||||
"sameContentHashAs": "fully populated snapshot",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "linux", "major": 6, "minor": 8 },
|
||||
"nodeCount": 8,
|
||||
"driveCount": 96,
|
||||
"capacityTotalBytes": 1099511627776,
|
||||
"capacityUsedBytes": 412316860416,
|
||||
"coarseFlags": ["drive.offline", "cluster.degraded", "drive.offline", "cluster.on.fire"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": ["coarseFlags[cluster.on.fire]"],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":1099511627776,\"capacityUsedBytes\":412316860416,\"coarseFlags\":[\"cluster.degraded\",\"drive.offline\"],\"driveCount\":96,\"nodeCount\":8,\"osVersion\":{\"family\":\"linux\",\"major\":6,\"minor\":8},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "e1cba9f30a26b94bb289a8a4b630a704dafaeb4960bffd38cef98e3d2581518f",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "every limit at its maximum",
|
||||
"category": "valid",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "9999.9999.9999",
|
||||
"osVersion": { "family": "other", "major": 9999, "minor": 9999 },
|
||||
"nodeCount": 4096,
|
||||
"driveCount": 1048576,
|
||||
"capacityTotalBytes": 9007199254740991,
|
||||
"capacityUsedBytes": 9007199254740991,
|
||||
"coarseFlags": [
|
||||
"capacity.critical",
|
||||
"capacity.warning",
|
||||
"clock.skew",
|
||||
"cluster.degraded",
|
||||
"cluster.healing",
|
||||
"cluster.readonly",
|
||||
"drive.offline",
|
||||
"node.offline"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":9007199254740991,\"capacityUsedBytes\":9007199254740991,\"coarseFlags\":[\"capacity.critical\",\"capacity.warning\",\"clock.skew\",\"cluster.degraded\",\"cluster.healing\",\"cluster.readonly\",\"drive.offline\",\"node.offline\"],\"driveCount\":1048576,\"nodeCount\":4096,\"osVersion\":{\"family\":\"other\",\"major\":9999,\"minor\":9999},\"rustfsVersion\":\"9999.9999.9999\"}",
|
||||
"contentHash": "b69d51f898a53562a7057faa5bda1e21699ee6615517cd8b1455096f9171bce4",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "every limit at its minimum",
|
||||
"category": "valid",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "0.0.0",
|
||||
"osVersion": null,
|
||||
"nodeCount": 1,
|
||||
"driveCount": 0,
|
||||
"capacityTotalBytes": 0,
|
||||
"capacityUsedBytes": 0,
|
||||
"coarseFlags": []
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":0,\"capacityUsedBytes\":0,\"coarseFlags\":[],\"driveCount\":0,\"nodeCount\":1,\"osVersion\":null,\"rustfsVersion\":\"0.0.0\"}",
|
||||
"contentHash": "08ebc03ee906c05d686ef32c0998154213f2811a2d07408a9ef7d0b205cc701b",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a full cluster reports used equal to total",
|
||||
"category": "valid",
|
||||
"input": {
|
||||
"protocolVersion": "v1",
|
||||
"rustfsVersion": "1.4.2",
|
||||
"osVersion": { "family": "freebsd", "major": 14, "minor": 1 },
|
||||
"nodeCount": 4,
|
||||
"driveCount": 32,
|
||||
"capacityTotalBytes": 549755813888,
|
||||
"capacityUsedBytes": 549755813888,
|
||||
"coarseFlags": ["capacity.critical", "cluster.readonly"]
|
||||
},
|
||||
"expected": {
|
||||
"decision": "ACCEPT",
|
||||
"reason": null,
|
||||
"httpStatus": null,
|
||||
"retained": [
|
||||
"protocolVersion",
|
||||
"rustfsVersion",
|
||||
"osVersion",
|
||||
"nodeCount",
|
||||
"driveCount",
|
||||
"capacityTotalBytes",
|
||||
"capacityUsedBytes",
|
||||
"coarseFlags"
|
||||
],
|
||||
"discarded": [],
|
||||
"defaultsApplied": {},
|
||||
"canonicalJson": "{\"capacityTotalBytes\":549755813888,\"capacityUsedBytes\":549755813888,\"coarseFlags\":[\"capacity.critical\",\"cluster.readonly\"],\"driveCount\":32,\"nodeCount\":4,\"osVersion\":{\"family\":\"freebsd\",\"major\":14,\"minor\":1},\"rustfsVersion\":\"1.4.2\"}",
|
||||
"contentHash": "0ab2308e84d2a9660650526edcd07795fe08a0fea047f16718846ce883a150b3",
|
||||
"echoedBack": [],
|
||||
"stored": [],
|
||||
"logged": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user