carson 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/RELEASE.md +17 -0
- data/VERSION +1 -1
- data/lib/carson/cli.rb +13 -2
- data/lib/carson/runtime/audit.rb +47 -10
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 514509a6422a4c2237a48feac1bff1c10e4705afe62fb574d400b8364cf131ba
|
|
4
|
+
data.tar.gz: 1f7bbf53a01ee92d8a97d62d0a7957bb823c0aabd70e31a7e27e37de8ab3b8c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a536b8a85ba6b2a737ce913485e3d58b5672b6b13af40261b181dd234bf1052ffa93a5f9b51307d9ce7e433e588b92ce294e88118b758747d4bb5cbad898c6c5
|
|
7
|
+
data.tar.gz: d476ba9ed57c7c97967c0cb2fab8b8390debfa196d657ae6d2e6c51e143248f8160bc543eb0d9b4e5c3c434ba4a25aa16b8af9aa6ec3b9cfcf5b7c974cd8fa9e
|
data/RELEASE.md
CHANGED
|
@@ -5,6 +5,23 @@ Release-note scope rule:
|
|
|
5
5
|
- `RELEASE.md` records only version deltas, breaking changes, and migration actions.
|
|
6
6
|
- Operational usage guides live in `MANUAL.md` and `API.md`.
|
|
7
7
|
|
|
8
|
+
## 3.4.0 — Audit JSON
|
|
9
|
+
|
|
10
|
+
### What changed
|
|
11
|
+
|
|
12
|
+
- **`carson audit --json`** — machine-readable JSON output for the audit command. The JSON envelope includes `command`, `status`, `branch`, `hooks`, `main_sync`, `pr`, `checks`, `baseline`, `problems`, and `exit_code`. Agents can parse audit results programmatically instead of regex-matching human-readable text.
|
|
13
|
+
|
|
14
|
+
### UX
|
|
15
|
+
|
|
16
|
+
- JSON output is only produced when `--json` is passed; default human-readable output is unchanged.
|
|
17
|
+
- The `problems` array contains the same concise problem strings shown in non-verbose human output, making it easy for agents to surface actionable issues.
|
|
18
|
+
- `hooks.status` is `"ok"` or `"mismatch"`, `main_sync.status` is `"ok"`, `"ahead"`, `"behind"`, or `"unknown"`.
|
|
19
|
+
|
|
20
|
+
### Migration
|
|
21
|
+
|
|
22
|
+
- No breaking changes. `carson audit` without `--json` behaves identically to 3.3.0.
|
|
23
|
+
- The `audit!` method now accepts `json_output:` keyword argument (default `false`).
|
|
24
|
+
|
|
8
25
|
## 3.3.0 — Deliver Refinements
|
|
9
26
|
|
|
10
27
|
### What changed
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.4.0
|
data/lib/carson/cli.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Carson
|
|
|
53
53
|
|
|
54
54
|
def self.build_parser
|
|
55
55
|
OptionParser.new do |opts|
|
|
56
|
-
opts.banner = "Usage: carson [status [--json]|setup|audit|sync|deliver [--merge] [--json] [--title T] [--body-file F]|prune [--all]|worktree create|done|remove <name>|onboard|refresh [--all]|offboard|template check|apply|review gate|sweep|govern [--dry-run] [--json] [--loop SECONDS]|version]"
|
|
56
|
+
opts.banner = "Usage: carson [status [--json]|setup|audit [--json]|sync|deliver [--merge] [--json] [--title T] [--body-file F]|prune [--all]|worktree create|done|remove <name>|onboard|refresh [--all]|offboard|template check|apply|review gate|sweep|govern [--dry-run] [--json] [--loop SECONDS]|version]"
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -88,6 +88,8 @@ module Carson
|
|
|
88
88
|
parse_worktree_subcommand( argv: argv, parser: parser, err: err )
|
|
89
89
|
when "review"
|
|
90
90
|
parse_named_subcommand( command: command, usage: "gate|sweep", argv: argv, parser: parser, err: err )
|
|
91
|
+
when "audit"
|
|
92
|
+
parse_audit_command( argv: argv, err: err )
|
|
91
93
|
when "status"
|
|
92
94
|
parse_status_command( argv: argv, err: err )
|
|
93
95
|
when "deliver"
|
|
@@ -242,6 +244,15 @@ module Carson
|
|
|
242
244
|
{ command: :invalid }
|
|
243
245
|
end
|
|
244
246
|
|
|
247
|
+
def self.parse_audit_command( argv:, err: )
|
|
248
|
+
json_flag = argv.delete( "--json" ) ? true : false
|
|
249
|
+
unless argv.empty?
|
|
250
|
+
err.puts "#{BADGE} Unexpected arguments for audit: #{argv.join( ' ' )}"
|
|
251
|
+
return { command: :invalid }
|
|
252
|
+
end
|
|
253
|
+
{ command: "audit", json: json_flag }
|
|
254
|
+
end
|
|
255
|
+
|
|
245
256
|
def self.parse_status_command( argv:, err: )
|
|
246
257
|
json_flag = argv.delete( "--json" ) ? true : false
|
|
247
258
|
unless argv.empty?
|
|
@@ -321,7 +332,7 @@ module Carson
|
|
|
321
332
|
when "setup"
|
|
322
333
|
runtime.setup!( cli_choices: parsed.fetch( :cli_choices, {} ) )
|
|
323
334
|
when "audit"
|
|
324
|
-
runtime.audit!
|
|
335
|
+
runtime.audit!( json_output: parsed.fetch( :json, false ) )
|
|
325
336
|
when "sync"
|
|
326
337
|
runtime.sync!
|
|
327
338
|
when "prune"
|
data/lib/carson/runtime/audit.rb
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
# Pre-commit audit — checks hooks, main sync, PR checks, and CI baseline.
|
|
2
|
+
# Exits with EXIT_BLOCK when policy violations are found.
|
|
3
|
+
# Supports --json for machine-readable structured output.
|
|
1
4
|
require "cgi"
|
|
2
5
|
|
|
3
6
|
module Carson
|
|
4
7
|
class Runtime
|
|
5
8
|
module Audit
|
|
6
|
-
def audit!
|
|
9
|
+
def audit!( json_output: false )
|
|
7
10
|
fingerprint_status = block_if_outsider_fingerprints!
|
|
8
11
|
return fingerprint_status unless fingerprint_status.nil?
|
|
9
12
|
unless head_exists?
|
|
10
|
-
|
|
13
|
+
if json_output
|
|
14
|
+
out.puts JSON.pretty_generate( { command: "audit", status: "skipped", reason: "no commits yet", exit_code: EXIT_OK } )
|
|
15
|
+
else
|
|
16
|
+
puts_line "No commits yet — audit skipped for initial commit."
|
|
17
|
+
end
|
|
11
18
|
return EXIT_OK
|
|
12
19
|
end
|
|
13
20
|
audit_state = "ok"
|
|
@@ -22,6 +29,7 @@ module Carson
|
|
|
22
29
|
puts_verbose ""
|
|
23
30
|
puts_verbose "[Hooks]"
|
|
24
31
|
hooks_ok = hooks_health_report
|
|
32
|
+
hooks_status = hooks_ok ? "ok" : "mismatch"
|
|
25
33
|
unless hooks_ok
|
|
26
34
|
audit_state = "block"
|
|
27
35
|
audit_concise_problems << "Hooks: mismatch — run carson refresh."
|
|
@@ -29,23 +37,27 @@ module Carson
|
|
|
29
37
|
puts_verbose ""
|
|
30
38
|
puts_verbose "[Main Sync Status]"
|
|
31
39
|
ahead_count, behind_count, main_error = main_sync_counts
|
|
40
|
+
main_sync = { ahead: 0, behind: 0, status: "ok" }
|
|
32
41
|
if main_error
|
|
33
42
|
puts_verbose "main_vs_remote_main: unknown"
|
|
34
43
|
puts_verbose "WARN: unable to calculate main sync status (#{main_error})."
|
|
35
44
|
audit_state = "attention" if audit_state == "ok"
|
|
36
45
|
audit_concise_problems << "Main sync: unable to determine — check remote connectivity."
|
|
46
|
+
main_sync = { ahead: 0, behind: 0, status: "unknown", error: main_error }
|
|
37
47
|
elsif ahead_count.positive?
|
|
38
48
|
puts_verbose "main_vs_remote_main_ahead: #{ahead_count}"
|
|
39
49
|
puts_verbose "main_vs_remote_main_behind: #{behind_count}"
|
|
40
50
|
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."
|
|
41
51
|
audit_state = "block"
|
|
42
52
|
audit_concise_problems << "Main sync (#{config.git_remote}): ahead by #{ahead_count} — git fetch #{config.git_remote}, or carson setup to switch remote."
|
|
53
|
+
main_sync = { ahead: ahead_count, behind: behind_count, status: "ahead" }
|
|
43
54
|
elsif behind_count.positive?
|
|
44
55
|
puts_verbose "main_vs_remote_main_ahead: #{ahead_count}"
|
|
45
56
|
puts_verbose "main_vs_remote_main_behind: #{behind_count}"
|
|
46
57
|
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."
|
|
47
58
|
audit_state = "attention" if audit_state == "ok"
|
|
48
59
|
audit_concise_problems << "Main sync (#{config.git_remote}): behind by #{behind_count} — run carson sync."
|
|
60
|
+
main_sync = { ahead: ahead_count, behind: behind_count, status: "behind" }
|
|
49
61
|
else
|
|
50
62
|
puts_verbose "main_vs_remote_main_ahead: 0"
|
|
51
63
|
puts_verbose "main_vs_remote_main_behind: 0"
|
|
@@ -109,15 +121,40 @@ module Carson
|
|
|
109
121
|
audit_status: audit_state
|
|
110
122
|
)
|
|
111
123
|
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
exit_code = audit_state == "block" ? EXIT_BLOCK : EXIT_OK
|
|
125
|
+
|
|
126
|
+
if json_output
|
|
127
|
+
result = {
|
|
128
|
+
command: "audit",
|
|
129
|
+
status: audit_state,
|
|
130
|
+
branch: current_branch,
|
|
131
|
+
hooks: { status: hooks_status },
|
|
132
|
+
main_sync: main_sync,
|
|
133
|
+
pr: monitor_report[ :pr ],
|
|
134
|
+
checks: monitor_report.fetch( :checks ),
|
|
135
|
+
baseline: {
|
|
136
|
+
status: default_branch_baseline.fetch( :status ),
|
|
137
|
+
repository: default_branch_baseline[ :repository ],
|
|
138
|
+
failing_count: default_branch_baseline.fetch( :failing_count ),
|
|
139
|
+
pending_count: default_branch_baseline.fetch( :pending_count ),
|
|
140
|
+
advisory_failing_count: default_branch_baseline.fetch( :advisory_failing_count ),
|
|
141
|
+
advisory_pending_count: default_branch_baseline.fetch( :advisory_pending_count )
|
|
142
|
+
},
|
|
143
|
+
problems: audit_concise_problems,
|
|
144
|
+
exit_code: exit_code
|
|
145
|
+
}
|
|
146
|
+
out.puts JSON.pretty_generate( result )
|
|
147
|
+
else
|
|
148
|
+
puts_verbose ""
|
|
149
|
+
puts_verbose "[Audit Result]"
|
|
150
|
+
puts_verbose "status: #{audit_state}"
|
|
151
|
+
puts_verbose( audit_state == "block" ? "ACTION: local policy block must be resolved before commit/push." : "ACTION: no local hard block detected." )
|
|
152
|
+
unless verbose?
|
|
153
|
+
audit_concise_problems.each { |problem| puts_line problem }
|
|
154
|
+
puts_line "Audit: #{audit_state}"
|
|
155
|
+
end
|
|
119
156
|
end
|
|
120
|
-
|
|
157
|
+
exit_code
|
|
121
158
|
end
|
|
122
159
|
|
|
123
160
|
private
|