Files
rustfs/protocol/agent/v1/fixtures/version/negotiation-vectors.json
T
overtrue 3b5164032a feat(connect): add device identity store and registration proof
A RustFS cluster device needs a durable identity before it can exchange a
one-time registration token for a certificate. This adds the device-side
half of that exchange, which rustfs/connect already verifies.

`connect::identity` builds the canonical registration transcript frozen by
protocol/agent/v1/registration-proof.md, signs it as low-S ES256, and emits
the PKCS#10 certificate request Connect consumes for its SubjectPublicKeyInfo.
`connect::identity_store` seals the P-256 key at mode 0600 and publishes it
through a no-clobber link, so a retry or a concurrent start returns the
original identity rather than minting a second one, and a corrupt or widened
key is refused rather than silently replaced.

The protocol fixture set is copied here byte-identically because
fixture-sets.json names this repository as the consumer copy; the tests
verify it against its own manifests and cross-verify Connect-produced ECDSA
proofs against transcripts rebuilt locally.

Nothing starts a task or touches the S3 data path: an unenrolled deployment
generates no key and holds no identity.
2026-08-19 12:54:50 +08:00

133 lines
3.2 KiB
JSON

{
"protocolVersion": "v1",
"fixtureSet": "version",
"fixture": "negotiation-vectors",
"description": "Protocol version decisions. A rejected version fails closed: nothing in the payload is processed, stored, or echoed.",
"vectors": [
{
"name": "supported major version",
"request": {
"protocolVersion": "v1",
"agentVersion": "1.4.0",
"capabilities": ["heartbeat", "inventory"]
},
"expected": {
"decision": "ACCEPT",
"negotiatedProtocolVersion": "v1",
"reason": null,
"httpStatus": null
}
},
{
"name": "supported major version reported by an agent that sends nothing else",
"request": {
"protocolVersion": "v1"
},
"expected": {
"decision": "ACCEPT",
"negotiatedProtocolVersion": "v1",
"reason": null,
"httpStatus": null
}
},
{
"name": "next major version from a future agent",
"request": {
"protocolVersion": "v2",
"agentVersion": "2.0.0",
"capabilities": ["heartbeat"]
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "far future major version",
"request": {
"protocolVersion": "v9999"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "missing protocol version",
"request": {
"agentVersion": "1.4.0"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "version without its prefix",
"request": {
"protocolVersion": "1"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "uppercase prefix",
"request": {
"protocolVersion": "V1"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "dotted version",
"request": {
"protocolVersion": "v1.2"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "zero major version",
"request": {
"protocolVersion": "v0"
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
},
{
"name": "empty protocol version",
"request": {
"protocolVersion": ""
},
"expected": {
"decision": "REJECT",
"negotiatedProtocolVersion": null,
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400
}
}
]
}