6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/carson/runtime/audit.rb', line 6
def audit!
fingerprint_status = block_if_outsider_fingerprints!
return fingerprint_status unless fingerprint_status.nil?
unless head_exists?
puts_line "No commits yet — audit skipped for initial commit."
return EXIT_OK
end
audit_state = "ok"
audit_concise_problems = []
puts_verbose ""
puts_verbose "[Repository]"
puts_verbose "root: #{repo_root}"
puts_verbose "current_branch: #{current_branch}"
puts_verbose ""
puts_verbose "[Working Tree]"
puts_verbose git_capture!( "status", "--short", "--branch" ).strip
puts_verbose ""
puts_verbose "[Hooks]"
hooks_ok = hooks_health_report
unless hooks_ok
audit_state = "block"
audit_concise_problems << "Hooks: mismatch — run carson refresh."
end
puts_verbose ""
puts_verbose "[Main Sync Status]"
ahead_count, behind_count, main_error = main_sync_counts
if main_error
puts_verbose "main_vs_remote_main: unknown"
puts_verbose "WARN: unable to calculate main sync status (#{main_error})."
audit_state = "attention" if audit_state == "ok"
audit_concise_problems << "Main sync: unable to determine — check remote connectivity."
elsif ahead_count.positive?
puts_verbose "main_vs_remote_main_ahead: #{ahead_count}"
puts_verbose "main_vs_remote_main_behind: #{behind_count}"
puts_verbose "ACTION: local #{config.main_branch} is ahead of #{config.git_remote}/#{config.main_branch} by #{ahead_count} commit#{plural_suffix( count: ahead_count )}; reset local drift before commit/push workflows."
audit_state = "block"
audit_concise_problems << "Main sync (#{config.git_remote}): ahead by #{ahead_count} — git fetch #{config.git_remote}, or carson setup to switch remote."
elsif behind_count.positive?
puts_verbose "main_vs_remote_main_ahead: #{ahead_count}"
puts_verbose "main_vs_remote_main_behind: #{behind_count}"
puts_verbose "ACTION: local #{config.main_branch} is behind #{config.git_remote}/#{config.main_branch} by #{behind_count} commit#{plural_suffix( count: behind_count )}; run carson sync."
audit_state = "attention" if audit_state == "ok"
audit_concise_problems << "Main sync (#{config.git_remote}): behind by #{behind_count} — run carson sync."
else
puts_verbose "main_vs_remote_main_ahead: 0"
puts_verbose "main_vs_remote_main_behind: 0"
puts_verbose "ACTION: local #{config.main_branch} is in sync with #{config.git_remote}/#{config.main_branch}."
end
puts_verbose ""
puts_verbose "[PR and Required Checks (gh)]"
monitor_report = pr_and_check_report
audit_state = "attention" if audit_state == "ok" && !%w[ok skipped].include?( monitor_report.fetch( :status ) )
if monitor_report.fetch( :status ) == "attention"
checks = monitor_report.fetch( :checks )
fail_n = checks.fetch( :failing_count )
pend_n = checks.fetch( :pending_count )
total = checks.fetch( :required_total )
fail_names = checks.fetch( :failing ).map { |e| e.fetch( :name ) }.join( ", " )
if fail_n.positive? && pend_n.positive?
audit_concise_problems << "Checks: #{fail_n} failing (#{fail_names}), #{pend_n} pending of #{total} required."
elsif fail_n.positive?
audit_concise_problems << "Checks: #{fail_n} of #{total} failing (#{fail_names})."
elsif pend_n.positive?
audit_concise_problems << "Checks: pending (#{total - pend_n} of #{total} complete)."
end
end
puts_verbose ""
puts_verbose "[Default Branch CI Baseline (gh)]"
default_branch_baseline = default_branch_ci_baseline_report
audit_state = "attention" if audit_state == "ok" && !%w[ok skipped].include?( default_branch_baseline.fetch( :status ) )
baseline_st = default_branch_baseline.fetch( :status )
if baseline_st == "block"
parts = []
if default_branch_baseline.fetch( :failing_count ).positive?
names = default_branch_baseline.fetch( :failing ).map { |e| e.fetch( :name ) }.join( ", " )
parts << "#{default_branch_baseline.fetch( :failing_count )} failing (#{names})"
end
if default_branch_baseline.fetch( :pending_count ).positive?
names = default_branch_baseline.fetch( :pending ).map { |e| e.fetch( :name ) }.join( ", " )
parts << "#{default_branch_baseline.fetch( :pending_count )} pending (#{names})"
end
parts << "no check-runs for active workflows" if default_branch_baseline.fetch( :no_check_evidence )
audit_concise_problems << "Baseline (#{default_branch_baseline.fetch( :default_branch, config.main_branch )}): #{parts.join( ', ' )} — fix before merge."
elsif baseline_st == "attention"
parts = []
if default_branch_baseline.fetch( :advisory_failing_count ).positive?
names = default_branch_baseline.fetch( :advisory_failing ).map { |e| e.fetch( :name ) }.join( ", " )
parts << "#{default_branch_baseline.fetch( :advisory_failing_count )} advisory failing (#{names})"
end
if default_branch_baseline.fetch( :advisory_pending_count ).positive?
names = default_branch_baseline.fetch( :advisory_pending ).map { |e| e.fetch( :name ) }.join( ", " )
parts << "#{default_branch_baseline.fetch( :advisory_pending_count )} advisory pending (#{names})"
end
audit_concise_problems << "Baseline (#{default_branch_baseline.fetch( :default_branch, config.main_branch )}): #{parts.join( ', ' )}."
end
if config.template_canonical.nil? || config.template_canonical.to_s.empty?
puts_verbose ""
puts_verbose "[Canonical Templates]"
puts_verbose "HINT: canonical templates not configured — run carson setup to enable."
end
write_and_print_pr_monitor_report(
report: monitor_report.merge(
default_branch_baseline: default_branch_baseline,
audit_status: audit_state
)
)
puts_verbose ""
puts_verbose "[Audit Result]"
puts_verbose "status: #{audit_state}"
puts_verbose( audit_state == "block" ? "ACTION: local policy block must be resolved before commit/push." : "ACTION: no local hard block detected." )
unless verbose?
audit_concise_problems.each { |problem| puts_line problem }
puts_line "Audit: #{audit_state}"
end
audit_state == "block" ? EXIT_BLOCK : EXIT_OK
end
|