1+ // Licensed to the .NET Foundation under one or more agreements.
2+ // The .NET Foundation licenses this file to you under the MIT license.
3+ // See the LICENSE file in the project root for more information.
4+
5+ using DevProxy . Abstractions . Plugins ;
6+ using DevProxy . Plugins . Models ;
7+ using System . Globalization ;
8+ using System . Text ;
9+
10+ namespace DevProxy . Plugins . Reporting ;
11+
12+ public sealed class MinimalPermissionsGuidancePluginReportApiResult
13+ {
14+ public required string ApiName { get ; init ; }
15+ public required IEnumerable < string > ExcessivePermissions { get ; init ; }
16+ public required IEnumerable < string > MinimalPermissions { get ; init ; }
17+ public required IEnumerable < string > Requests { get ; init ; }
18+ public required IEnumerable < string > TokenPermissions { get ; init ; }
19+ public required bool UsesMinimalPermissions { get ; init ; }
20+ }
21+
22+ public sealed class MinimalPermissionsGuidancePluginReport : IMarkdownReport , IPlainTextReport
23+ {
24+ public required IEnumerable < ApiPermissionError > Errors { get ; init ; }
25+ public required IEnumerable < MinimalPermissionsGuidancePluginReportApiResult > Results { get ; init ; }
26+ public required IEnumerable < string > UnmatchedRequests { get ; init ; }
27+ public IEnumerable < string > ? ExcludedPermissions { get ; set ; }
28+
29+ public string ? ToMarkdown ( )
30+ {
31+ if ( ! Results . Any ( ) && ! UnmatchedRequests . Any ( ) && ! Errors . Any ( ) && ExcludedPermissions ? . Any ( ) != true )
32+ {
33+ return "No permissions information to report." ;
34+ }
35+
36+ var sb = new StringBuilder ( ) ;
37+ _ = sb . AppendLine ( "# Minimal Permissions Report" )
38+ . AppendLine ( ) ;
39+
40+ foreach ( var result in Results )
41+ {
42+ _ = sb . AppendLine ( CultureInfo . InvariantCulture , $ "## API: { result . ApiName } ")
43+ . AppendLine ( )
44+ . AppendLine ( "### Requests" )
45+ . AppendLine ( )
46+ . AppendJoin ( Environment . NewLine , result . Requests . Select ( r => $ "- { r } ") )
47+ . AppendLine ( )
48+ . AppendLine ( )
49+ . AppendLine ( "### Minimal permissions" )
50+ . AppendLine ( )
51+ . AppendJoin ( Environment . NewLine , result . MinimalPermissions . Select ( p => $ "- `{ p } `") )
52+ . AppendLine ( )
53+ . AppendLine ( )
54+ . AppendLine ( "### Permissions on the token" )
55+ . AppendLine ( )
56+ . AppendJoin ( Environment . NewLine , result . TokenPermissions . Select ( p => $ "- `{ p } `") )
57+ . AppendLine ( )
58+ . AppendLine ( )
59+ . AppendLine ( "### Excessive permissions" ) ;
60+
61+ _ = result . UsesMinimalPermissions
62+ ? sb . AppendLine ( )
63+ . AppendLine ( "The token has the minimal permissions required." )
64+ : sb . AppendLine ( )
65+ . AppendLine ( "The following permissions included in the token are unnecessary:" )
66+ . AppendLine ( )
67+ . AppendJoin ( Environment . NewLine , result . ExcessivePermissions . Select ( p => $ "- `{ p } `") )
68+ . AppendLine ( ) ;
69+
70+ _ = sb . AppendLine ( ) ;
71+ }
72+
73+ if ( UnmatchedRequests . Any ( ) )
74+ {
75+ _ = sb . AppendLine ( "## Unmatched Requests" )
76+ . AppendLine ( )
77+ . AppendLine ( "The following requests could not be matched:" )
78+ . AppendLine ( )
79+ . AppendJoin ( Environment . NewLine , UnmatchedRequests . Select ( r => $ "- { r } ") )
80+ . AppendLine ( )
81+ . AppendLine ( ) ;
82+ }
83+
84+ if ( Errors . Any ( ) )
85+ {
86+ _ = sb . AppendLine ( "## Errors" )
87+ . AppendLine ( )
88+ . AppendLine ( "| Request | Error |" )
89+ . AppendLine ( "| --------| ----- |" )
90+ . AppendJoin ( Environment . NewLine , Errors . Select ( error => $ "| { error . Request } | { error . Error } |") )
91+ . AppendLine ( )
92+ . AppendLine ( ) ;
93+ }
94+
95+ if ( ExcludedPermissions ? . Any ( ) == true )
96+ {
97+ _ = sb . AppendLine ( "## Excluded Permissions" )
98+ . AppendLine ( )
99+ . AppendLine ( "The following permissions were excluded from the analysis:" )
100+ . AppendLine ( )
101+ . AppendJoin ( Environment . NewLine , ExcludedPermissions . Select ( p => $ "- `{ p } `") )
102+ . AppendLine ( ) ;
103+ }
104+
105+ return sb . ToString ( ) ;
106+ }
107+
108+ public string ? ToPlainText ( )
109+ {
110+ if ( ! Results . Any ( ) && ! UnmatchedRequests . Any ( ) && ! Errors . Any ( ) && ExcludedPermissions ? . Any ( ) != true )
111+ {
112+ return "No permissions information to report." ;
113+ }
114+
115+ var sb = new StringBuilder ( ) ;
116+ _ = sb . AppendLine ( "Minimal Permissions Report" )
117+ . AppendLine ( "==========================" )
118+ . AppendLine ( ) ;
119+
120+ foreach ( var result in Results )
121+ {
122+ var apiTitle = $ "API: { result . ApiName } ";
123+ _ = sb . AppendLine ( )
124+ . AppendLine ( apiTitle )
125+ . AppendLine ( new string ( '-' , apiTitle . Length ) )
126+ . AppendLine ( ) ;
127+
128+ _ = sb . AppendLine ( "Requests:" )
129+ . AppendJoin ( Environment . NewLine , result . Requests . Select ( r => $ "- { r } ") ) . AppendLine ( )
130+ . AppendLine ( ) ;
131+
132+ _ = sb . AppendLine ( "Minimal permissions:" )
133+ . AppendJoin ( ", " , result . MinimalPermissions ) . AppendLine ( )
134+ . AppendLine ( ) ;
135+
136+ _ = sb . AppendLine ( "Permissions on the token:" )
137+ . AppendJoin ( ", " , result . TokenPermissions ) . AppendLine ( )
138+ . AppendLine ( ) ;
139+
140+ _ = sb . AppendLine ( "Excessive permissions" )
141+ . AppendLine ( "---------------------" )
142+ . AppendLine ( ) ;
143+
144+ _ = result . UsesMinimalPermissions
145+ ? sb . AppendLine ( "The token has the minimal permissions required." )
146+ : sb . AppendLine ( "The following permissions included in the token are unnecessary:" )
147+ . AppendJoin ( ", " , result . ExcessivePermissions ) . AppendLine ( ) ;
148+ _ = sb . AppendLine ( ) ;
149+ }
150+
151+ if ( UnmatchedRequests . Any ( ) )
152+ {
153+ _ = sb . AppendLine ( )
154+ . AppendLine ( "Unmatched Requests" )
155+ . AppendLine ( "------------------" )
156+ . AppendLine ( )
157+ . AppendLine ( "The following requests could not be matched:" )
158+ . AppendJoin ( Environment . NewLine , UnmatchedRequests . Select ( r => $ "- { r } ") ) . AppendLine ( )
159+ . AppendLine ( ) ;
160+ }
161+
162+ if ( Errors . Any ( ) )
163+ {
164+ _ = sb . AppendLine ( )
165+ . AppendLine ( "Errors" )
166+ . AppendLine ( "------" )
167+ . AppendLine ( )
168+ . AppendLine ( "The following errors occurred while finding permissions for requests:" )
169+ . AppendJoin ( Environment . NewLine , Errors . Select ( error => $ "- For request '{ error . Request } ': { error . Error } ") )
170+ . AppendLine ( )
171+ . AppendLine ( ) ;
172+ }
173+
174+ if ( ExcludedPermissions ? . Any ( ) == true )
175+ {
176+ _ = sb . AppendLine ( )
177+ . AppendLine ( "Excluded Permissions" )
178+ . AppendLine ( "--------------------" )
179+ . AppendLine ( )
180+ . AppendLine ( "The following permissions were excluded from the analysis:" )
181+ . AppendJoin ( ", " , ExcludedPermissions ) . AppendLine ( ) ;
182+ }
183+
184+ return sb . ToString ( ) ;
185+ }
186+ }
0 commit comments