sdk+backend(P1.9): protocol-version handshake on every request
All three SDKs now send X-Attesto-Sdk (attesto-<lang>/<version>) and X-Attesto-Protocol (ATTESTO-PROOFSTREAM-001/0.1-alpha) on every request. A new backend ProtocolVersionMiddleware logs both headers (operators can see the SDK/protocol mix in traffic) and, when the protocol header is present on a /v2 request and names a different protocol identifier or major version, answers 426 Upgrade Required with a structured body (error/supported/received/hint). Absent or unparseable headers change nothing — old clients and curl stay fully compatible (test-asserted, including /v1 never being handshake-gated). SDKs surface the 426 as a typed error: Python AttestoProtocolMismatch, TypeScript AttestoProtocolMismatch, Go IsProtocolMismatch(err) over *APIError (Go-idiomatic). Tests cover the mismatch rules, the 426 mapping, and that the handshake headers are actually sent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
11
client.go
11
client.go
@@ -534,6 +534,9 @@ func (c *Client) requestRaw(ctx context.Context, method, path string, values url
|
|||||||
req.Header.Set("Authorization", "Bearer "+c.bearer)
|
req.Header.Set("Authorization", "Bearer "+c.bearer)
|
||||||
req.Header.Set("User-Agent", c.userAgent)
|
req.Header.Set("User-Agent", c.userAgent)
|
||||||
req.Header.Set("X-Attesto-SDK", c.userAgent)
|
req.Header.Set("X-Attesto-SDK", c.userAgent)
|
||||||
|
// [P1.9] protocol handshake: the backend answers 426 when it speaks a
|
||||||
|
// different protocol generation (ErrProtocolMismatch via APIError).
|
||||||
|
req.Header.Set("X-Attesto-Protocol", ProtocolHandshake)
|
||||||
if body != nil {
|
if body != nil {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
@@ -577,6 +580,14 @@ func (e *APIError) Error() string {
|
|||||||
return fmt.Sprintf("attesto api error: status=%d message=%s", e.StatusCode, e.Message)
|
return fmt.Sprintf("attesto api error: status=%d message=%s", e.StatusCode, e.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsProtocolMismatch reports whether err is a 426 protocol-handshake rejection:
|
||||||
|
// the backend speaks a different protocol generation than this SDK announced in
|
||||||
|
// X-Attesto-Protocol. Upgrade the SDK to a release that speaks it.
|
||||||
|
func IsProtocolMismatch(err error) bool {
|
||||||
|
var apiErr *APIError
|
||||||
|
return errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusUpgradeRequired
|
||||||
|
}
|
||||||
|
|
||||||
func decodeResponse(resp *http.Response, out any) error {
|
func decodeResponse(resp *http.Response, out any) error {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode == http.StatusNoContent {
|
if resp.StatusCode == http.StatusNoContent {
|
||||||
|
|||||||
@@ -5,4 +5,7 @@ const (
|
|||||||
DefaultBaseURL = "https://verify.attesto.eu"
|
DefaultBaseURL = "https://verify.attesto.eu"
|
||||||
ProofstreamProtocol = "ATTESTO-PROOFSTREAM-001"
|
ProofstreamProtocol = "ATTESTO-PROOFSTREAM-001"
|
||||||
ProtocolVersionAlpha = "0.1-alpha"
|
ProtocolVersionAlpha = "0.1-alpha"
|
||||||
|
// ProtocolHandshake is sent as X-Attesto-Protocol on every request; the
|
||||||
|
// backend answers 426 when it speaks a different protocol generation.
|
||||||
|
ProtocolHandshake = ProofstreamProtocol + "/" + ProtocolVersionAlpha
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user