@@ -13,7 +13,6 @@ import (
1313 "github.com/usetero/cli/internal/domain"
1414 "github.com/usetero/cli/internal/sqlite"
1515 "github.com/usetero/cli/internal/styles"
16- "github.com/usetero/cli/internal/tea/components/status"
1716 "github.com/usetero/cli/internal/tea/components/table"
1817)
1918
@@ -93,8 +92,11 @@ func (m *Model) stateKey(policies []domain.PIIPolicy) string {
9392 var b strings.Builder
9493 fmt .Fprintf (& b , "%d" , len (policies ))
9594 for _ , p := range policies {
96- fmt .Fprintf (& b , "|%s:%s:%s:%s:%d" ,
97- p .ServiceName , p .LogEventName , p .RiskLevel , p .Status , len (p .Fields ))
95+ fmt .Fprintf (& b , "|%s:%s:%s:%d" ,
96+ p .ServiceName , p .LogEventName , p .Status , len (p .Fields ))
97+ for _ , f := range p .Fields {
98+ fmt .Fprintf (& b , ":%s" , f .PIIType )
99+ }
98100 }
99101 return b .String ()
100102}
@@ -172,53 +174,58 @@ func (m *Model) renderTable(width int) string {
172174 }
173175
174176 tbl := table .New (m .theme , table .WithMaxValueWidth (40 ))
175- tbl .Headers ("Log Event" , "Service" , "Risk" , " Leaking" )
177+ tbl .Headers ("Log Event" , "Service" , "Leaking" )
176178 tbl .SetWidth (width )
177179
178180 for _ , p := range m .policies {
179181 tbl .Row (
180182 p .LogEventName ,
181183 p .ServiceName ,
182- status .Risk (m .theme , p .RiskLevel , true ),
183- formatFields (p .Fields ),
184+ formatPIITypes (p .Fields , 3 ),
184185 )
185186 }
186187
187188 return tbl .View ()
188189}
189190
190- // formatFields joins PII field paths into a readable string.
191- // [["attributes","user","email"]] → "user.email"
192- // Strips the leading "attributes"/"resource_attributes" namespace for readability.
193- func formatFields (fields [][]string ) string {
191+ // formatPIITypes returns deduplicated PII type labels, showing at most maxShow
192+ // before truncating with "+N". For example: "email, phone, +2".
193+ func formatPIITypes (fields []domain.PIIField , maxShow int ) string {
194194 if len (fields ) == 0 {
195195 return "—"
196196 }
197197
198- names := make ([]string , 0 , len (fields ))
199- for _ , path := range fields {
200- names = append (names , formatFieldPath (path ))
198+ // Deduplicate and preserve first-seen order.
199+ seen := make (map [string ]bool )
200+ var types []string
201+ for _ , f := range fields {
202+ label := displayPIIType (f .PIIType )
203+ if ! seen [label ] {
204+ seen [label ] = true
205+ types = append (types , label )
206+ }
201207 }
202- return strings .Join (names , ", " )
203- }
204208
205- // formatFieldPath converts a field path to a dot-separated string,
206- // stripping common OTel namespace prefixes.
207- func formatFieldPath (path []string ) string {
208- if len (path ) == 0 {
209- return ""
209+ if len (types ) <= maxShow {
210+ return strings .Join (types , ", " )
210211 }
212+ return strings .Join (types [:maxShow ], ", " ) + fmt .Sprintf (", +%d" , len (types )- maxShow )
213+ }
211214
212- // Strip common OTel namespace prefixes for readability.
213- start := 0
214- if len (path ) > 1 {
215- switch path [0 ] {
216- case "attributes" , "resource_attributes" , "scope_attributes" :
217- start = 1
218- }
215+ // displayPIIType returns a human-readable label for a pii_type value.
216+ func displayPIIType (t string ) string {
217+ switch t {
218+ case domain .PIITypeCreditCard :
219+ return "credit card"
220+ case domain .PIITypeIPAddress :
221+ return "IP address"
222+ case domain .PIITypeSSN :
223+ return "SSN"
224+ case domain .PIITypeDateOfBirth :
225+ return "date of birth"
226+ default :
227+ return t
219228 }
220-
221- return strings .Join (path [start :], "." )
222229}
223230
224231func (m * Model ) pendingCount () int {
0 commit comments