@@ -112,9 +112,16 @@ func (f *TableFormatter) Format(result *types.ScanResult, w io.Writer) error {
112112 )
113113 }
114114
115- // Display detailed remediation for confirmed/vulnerable findings
116- if f .Options .ShowRemediation {
117- f .printDetailedRemediation (w , allCrypto , result .Ecosystem )
115+ // Display detailed remediation for vulnerable findings
116+ // For reachability-analyzed projects: show CONFIRMED first, then PLANNING
117+ // For other projects: show all vulnerable/partial algorithms
118+ if hasReachability {
119+ if f .Options .ShowRemediation {
120+ f .printDetailedRemediation (w , allCrypto , result .Ecosystem )
121+ }
122+ } else {
123+ // Always show remediation for non-reachability projects (Python, npm, Java, etc.)
124+ f .printSimpleRemediation (w , allCrypto , result .Ecosystem )
118125 }
119126
120127 // Count deep-analyzed packages
@@ -221,13 +228,84 @@ func (f *TableFormatter) printReachabilityBreakdown(w io.Writer, allCrypto []cry
221228func (f * TableFormatter ) printSimpleBreakdown (w io.Writer , allCrypto []cryptoDetail ) {
222229 sortByRisk (allCrypto )
223230
224- fmt .Fprintln (w , "CRYPTO ALGORITHMS FOUND:" )
225- fmt .Fprintln (w , strings .Repeat ("─" , 90 ))
226- fmt .Fprintf (w , " %-14s %-12s %-12s %s\n " , "ALGORITHM" , "RISK" , "TIMELINE" , "DEPENDENCY" )
231+ // Group by risk level for cleaner output
232+ vulnerable := filterByRisk (allCrypto , types .RiskVulnerable )
233+ partial := filterByRisk (allCrypto , types .RiskPartial )
234+ safe := filterByRisk (allCrypto , types .RiskSafe )
235+
236+ if len (vulnerable ) > 0 {
237+ fmt .Fprintln (w , "[!] VULNERABLE - Quantum computers will break these:" )
238+ fmt .Fprintln (w , strings .Repeat ("─" , 90 ))
239+ for _ , c := range vulnerable {
240+ timeline := formatTimelineShort (getTimeline (c .algorithm ))
241+ effort := formatEffortShort (getEffort (c .algorithm ))
242+ fmt .Fprintf (w , " 🔴 %-14s %-12s %-12s %s\n " , c .algorithm , timeline , effort , c .dependency )
243+ }
244+ fmt .Fprintln (w )
245+ }
246+
247+ if len (partial ) > 0 {
248+ fmt .Fprintln (w , "[~] PARTIAL RISK - Weakened but usable:" )
249+ fmt .Fprintln (w , strings .Repeat ("─" , 90 ))
250+ for _ , c := range partial {
251+ timeline := formatTimelineShort (getTimeline (c .algorithm ))
252+ effort := formatEffortShort (getEffort (c .algorithm ))
253+ fmt .Fprintf (w , " 🟡 %-14s %-12s %-12s %s\n " , c .algorithm , timeline , effort , c .dependency )
254+ }
255+ fmt .Fprintln (w )
256+ }
257+
258+ if len (safe ) > 0 {
259+ fmt .Fprintln (w , "[OK] QUANTUM SAFE:" )
260+ fmt .Fprintln (w , strings .Repeat ("─" , 90 ))
261+ for _ , c := range safe {
262+ fmt .Fprintf (w , " 🟢 %-14s %s\n " , c .algorithm , c .dependency )
263+ }
264+ fmt .Fprintln (w )
265+ }
266+
267+ // Handle unknown risk (not in any of the above categories)
268+ unknown := filterByRisk (allCrypto , types .RiskUnknown )
269+ if len (unknown ) > 0 {
270+ fmt .Fprintln (w , "[?] UNKNOWN RISK:" )
271+ fmt .Fprintln (w , strings .Repeat ("─" , 90 ))
272+ for _ , c := range unknown {
273+ fmt .Fprintf (w , " ⚪ %-14s %s\n " , c .algorithm , c .dependency )
274+ }
275+ fmt .Fprintln (w )
276+ }
277+ }
278+
279+ // printSimpleRemediation prints remediation for non-reachability projects.
280+ func (f * TableFormatter ) printSimpleRemediation (w io.Writer , allCrypto []cryptoDetail , ecosystem types.Ecosystem ) {
281+ seen := make (map [string ]bool )
282+ var toRemediate []cryptoDetail
283+
284+ // Collect all vulnerable and partial algorithms (deduplicated)
227285 for _ , c := range allCrypto {
228- icon := riskIcon (c .risk )
229- timeline := getTimeline (c .algorithm )
230- fmt .Fprintf (w , " %s %-12s %-12s %-12s %s\n " , icon , c .algorithm , formatRisk (c .risk ), timeline , c .dependency )
286+ if seen [c .algorithm ] {
287+ continue
288+ }
289+ if c .risk == types .RiskVulnerable || c .risk == types .RiskPartial {
290+ toRemediate = append (toRemediate , c )
291+ seen [c .algorithm ] = true
292+ }
293+ }
294+
295+ if len (toRemediate ) == 0 {
296+ return
297+ }
298+
299+ // Sort by risk priority
300+ sort .Slice (toRemediate , func (i , j int ) bool {
301+ return riskPriority (toRemediate [i ].risk ) > riskPriority (toRemediate [j ].risk )
302+ })
303+
304+ fmt .Fprintln (w , "REMEDIATION GUIDANCE:" )
305+ fmt .Fprintln (w , strings .Repeat ("═" , 90 ))
306+
307+ for _ , c := range toRemediate {
308+ f .printRemediationItem (w , c , ecosystem )
231309 }
232310 fmt .Fprintln (w )
233311}
@@ -352,6 +430,16 @@ func filterByReachability(crypto []cryptoDetail, reach types.Reachability) []cry
352430 return result
353431}
354432
433+ func filterByRisk (crypto []cryptoDetail , risk types.QuantumRisk ) []cryptoDetail {
434+ var result []cryptoDetail
435+ for _ , c := range crypto {
436+ if c .risk == risk {
437+ result = append (result , c )
438+ }
439+ }
440+ return result
441+ }
442+
355443func sortByRisk (crypto []cryptoDetail ) {
356444 sort .Slice (crypto , func (i , j int ) bool {
357445 return riskPriority (crypto [i ].risk ) > riskPriority (crypto [j ].risk )
0 commit comments