Expose membership assurance in member channel event payloads

This commit is contained in:
Joshua 2026-02-18 19:55:38 -08:00
parent 04f2de2ccf
commit 311104fbb8
5 changed files with 47 additions and 14 deletions

View File

@ -1115,6 +1115,8 @@ func (a *app) handleMemberChannelEvents(w http.ResponseWriter, r *http.Request)
DeviceID: binding.DeviceID,
OrgRootID: binding.OrgRootID,
PrincipalID: binding.PrincipalID,
MembershipStatus: strings.ToLower(strings.TrimSpace(rec.MembershipStatus)),
IdentityAssurance: normalizeAssuranceLevel(rec.IdentityAssurance),
Events: out,
NextCursor: nextCursor,
ServerTime: time.Now().UTC().Format(time.RFC3339Nano),

View File

@ -709,6 +709,12 @@ func TestMemberChannelRegisterPollAckAndUnregister(t *testing.T) {
if len(events.Events) == 0 {
t.Fatalf("expected seeded events, got none")
}
if events.MembershipStatus != "active" {
t.Fatalf("expected active membership status in events payload, got %+v", events)
}
if events.IdentityAssurance != assuranceOnrampAttested {
t.Fatalf("expected onramp assurance in events payload, got %+v", events)
}
first := events.Events[0]
ackTime := time.Now().UTC()
ack := postJSONExpect[memberChannelEventAckResponse](t, a, "/member/channel/events/"+first.EventID+"/ack", memberChannelEventAckRequest{
@ -764,6 +770,9 @@ func TestMemberChannelEventsAllowUnattestedMembership(t *testing.T) {
if len(events.Events) == 0 {
t.Fatalf("expected seeded events for unattested member, got none")
}
if events.IdentityAssurance != assuranceCryptoDirect {
t.Fatalf("expected crypto_direct_unattested assurance for unattested member events, got %+v", events)
}
}
func TestMemberChannelSupportTicketOwnerOnly(t *testing.T) {

View File

@ -262,6 +262,8 @@ type memberChannelEventsResponse struct {
DeviceID string `json:"device_id"`
OrgRootID string `json:"org_root_id"`
PrincipalID string `json:"principal_id"`
MembershipStatus string `json:"membership_status"`
IdentityAssurance string `json:"identity_assurance_level"`
Events []memberChannelEvent `json:"events"`
NextCursor string `json:"next_cursor"`
ServerTime string `json:"server_time"`

View File

@ -50,6 +50,8 @@ Authorization: Bearer <wallet-session>
"device_id": "desktop-7f6f3a9b",
"org_root_id": "org.acme.root",
"principal_id": "human.joshua",
"membership_status": "active",
"identity_assurance_level": "onramp_attested",
"events": [
{
"event_id": "evt_1031",
@ -145,3 +147,13 @@ Content-Type: application/json
"correlation_id": "req_01J9A6ZC0SYF5A0M8AP8BNX7B2"
}
```
## Owner Action Assurance Error
```json
{
"error": "owner support actions require onramp_attested identity assurance",
"code": "identity_assurance_insufficient",
"correlation_id": "req_01J9A72Q2Q0VQ8MCR7D2N95D3R"
}
```

View File

@ -249,6 +249,8 @@ components:
- device_id
- org_root_id
- principal_id
- membership_status
- identity_assurance_level
- events
- next_cursor
- server_time
@ -261,6 +263,12 @@ components:
type: string
principal_id:
type: string
membership_status:
type: string
enum: [active, none, suspended, revoked, unknown]
identity_assurance_level:
type: string
enum: [none, crypto_direct_unattested, sponsored_unattested, onramp_attested]
events:
type: array
items: