Fix attributes() calling /userinfo instead of /attributes.json#13
Conversation
The attributes() method was incorrectly calling APIEndpoint.userInfo(), which maps to /api/public/v3/userinfo. That endpoint returns OIDC standard claims with no status block, so callers (e.g. CVS) received empty verification statuses and could not filter on subgroup. Fix: add APIEndpoint.attributes() → /api/public/v3/attributes.json and wire attributes() in IDmeAuth to use it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verifies that IDmeAuth.attributes() calls /api/public/v3/attributes.json (not /userinfo), returns a populated status block, and deserializes the attributes list correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ganaidme
left a comment
There was a problem hiding this comment.
I verified that calling IDmeAuth.attributes() calls api/public/v3/attributes.json
matt-james-idme
left a comment
There was a problem hiding this comment.
Clean, targeted fix. The bug is exactly what the description says: attributes() was reaching for APIEndpoint.userInfo(...) and getting back OIDC claims with no status block, so any caller trying to filter on verification subgroup silently got nothing. The change is a one-line swap plus the missing endpoint function it should have been calling all along.
A few things worth calling out:
- The root cause framing in the description is accurate and helpful. This is a copy-paste bug, not a design issue, and the fix reflects that.
- The test coverage is right-sized for the change.
attributes calls attributes endpoint not userinfolocks in the bug so it can't regress, and the two response-shape tests confirm thestatusandattributesdeserialization path that was never actually exercised against the real endpoint before. - Using
endsWith("api/public/v3/attributes.json")in the URL assertion is the right call - it stays robust across environments without overfitting to a specific base URL. APIEndpoint.attributes()slots in cleanly next touserInfo()andpolicies()with consistent formatting and a docstring. Nothing else to touch.
One thing to confirm before cutting 1.0.1: worth a quick manual smoke against staging to make sure the real attributes.json response deserializes into AttributeResponse without surprises - the tests use a hand-crafted JSON fixture, so any field-name drift between the fixture and the live response wouldn't be caught here. The test plan already has this covered.
Good to merge once that's verified.
Summary
attributes()inIDmeAuthwas hardcoded to callAPIEndpoint.userInfo()→/api/public/v3/userinfostatusblock — so callers received empty verification statuses and could not filter on subgroupAPIEndpoint.attributes()→/api/public/v3/attributes.jsonand wiredIDmeAuth.attributes()to use itRoot cause
APIEndpoint.kthad noattributesfunction. Theattributes()method was reusinguserInfo()by mistake, resulting in the wrong endpoint being called at runtime.Test plan
APIEndpoint.attributes()returns{baseURL}api/public/v3/attributes.jsonfor each environmentattributes()end-to-end and confirm the response contains a populatedstatuslist withgroup,subgroups, andverifiedfieldsuserInfo()andrawPayload()are unaffected (still call/userinfo)1.0.1release and have CVS bump their dependency🤖 Generated with Claude Code