@@ -57,6 +57,10 @@ func runGitT(t *testing.T, root string, args ...string) {
5757// Test_Analyze_HappyPath: a test-pair + a config change form two groups,
5858// both high confidence, messages non-generic.
5959func Test_Analyze_HappyPath (t * testing.T ) {
60+ t .Parallel ()
61+ if testing .Short () {
62+ t .Skip ("skipping integration test in short mode" )
63+ }
6064 root := initTestRepo (t ,
6165 map [string ]string {
6266 "go.mod" : "module fixture\n go 1.22\n " ,
@@ -100,6 +104,10 @@ func Test_Analyze_HappyPath(t *testing.T) {
100104
101105// Test_Analyze_CleanRepo: no dirty files => early_exit.
102106func Test_Analyze_CleanRepo (t * testing.T ) {
107+ t .Parallel ()
108+ if testing .Short () {
109+ t .Skip ("skipping integration test in short mode" )
110+ }
103111 root := initTestRepo (t ,
104112 map [string ]string {"README.md" : "# clean\n " },
105113 nil ,
@@ -115,6 +123,10 @@ func Test_Analyze_CleanRepo(t *testing.T) {
115123
116124// Test_Analyze_Secrets: a live AWS access key in a config file must FLAG.
117125func Test_Analyze_Secrets (t * testing.T ) {
126+ t .Parallel ()
127+ if testing .Short () {
128+ t .Skip ("skipping integration test in short mode" )
129+ }
118130 root := initTestRepo (t ,
119131 map [string ]string {"config.yaml" : "key: value\n " },
120132 map [string ]string {"config.yaml" : "key: value\n aws_access_key: AKIAIOSFODNN7EXAMPLE\n " },
@@ -133,6 +145,10 @@ func Test_Analyze_Secrets(t *testing.T) {
133145
134146// Test_Analyze_PlaceholderPaths: /Users/you/ should NOT flag as PII.
135147func Test_Analyze_PlaceholderPaths (t * testing.T ) {
148+ t .Parallel ()
149+ if testing .Short () {
150+ t .Skip ("skipping integration test in short mode" )
151+ }
136152 root := initTestRepo (t ,
137153 map [string ]string {"docs.md" : "# Docs\n " },
138154 map [string ]string {"docs.md" : "# Docs\n \n Install at /Users/you/bin/tool.\n " },
@@ -150,6 +166,10 @@ func Test_Analyze_PlaceholderPaths(t *testing.T) {
150166
151167// Test_Analyze_DepBump: go.mod version bump is detected.
152168func Test_Analyze_DepBump (t * testing.T ) {
169+ t .Parallel ()
170+ if testing .Short () {
171+ t .Skip ("skipping integration test in short mode" )
172+ }
153173 root := initTestRepo (t ,
154174 map [string ]string {
155175 "go.mod" : "module fixture\n \n go 1.22\n \n require github.com/pkg/errors v0.9.0\n " ,
@@ -170,6 +190,125 @@ func Test_Analyze_DepBump(t *testing.T) {
170190 }
171191}
172192
193+ // Test_Analyze_TagAndSubjects: latest_tag + recent_subjects are emitted so the
194+ // agent never re-runs `git log` / `git tag` for style or version lookup.
195+ func Test_Analyze_TagAndSubjects (t * testing.T ) {
196+ t .Parallel ()
197+ if testing .Short () {
198+ t .Skip ("skipping integration test in short mode" )
199+ }
200+ root := initTestRepo (t ,
201+ map [string ]string {"README.md" : "# Fixture\n " },
202+ nil ,
203+ )
204+ // Two more commits with conventional-style subjects; tag the last one.
205+ writeFixture (t , root , "a.txt" , "a\n " )
206+ runGitT (t , root , "add" , "-A" )
207+ runGitT (t , root , "commit" , "-q" , "-m" , "feat(core): add a" )
208+ writeFixture (t , root , "b.txt" , "b\n " )
209+ runGitT (t , root , "add" , "-A" )
210+ runGitT (t , root , "commit" , "-q" , "-m" , "fix(core): patch b" )
211+ runGitT (t , root , "tag" , "v0.2.0" )
212+ // Dirty the tree so analyze doesn't early-exit.
213+ writeFixture (t , root , "README.md" , "# Fixture\n \n changed\n " )
214+
215+ got , err := AnalyzeCommit (context .Background (), AnalyzeOptions {Root : root })
216+ if err != nil {
217+ t .Fatalf ("AnalyzeCommit: %v" , err )
218+ }
219+ if got .LatestTag != "v0.2.0" {
220+ t .Errorf ("LatestTag = %q, want %q" , got .LatestTag , "v0.2.0" )
221+ }
222+ if len (got .RecentSubjects ) == 0 {
223+ t .Fatalf ("RecentSubjects empty; expected recent commit subjects" )
224+ }
225+ if len (got .RecentSubjects ) > 5 {
226+ t .Errorf ("RecentSubjects = %d entries, want ≤5" , len (got .RecentSubjects ))
227+ }
228+ if ! strings .HasPrefix (got .RecentSubjects [0 ], "fix(core)" ) {
229+ t .Errorf ("RecentSubjects[0] = %q, want newest-first conventional subject" , got .RecentSubjects [0 ])
230+ }
231+ }
232+
233+ // Test_Analyze_NoTag_NoHistory: fresh repo with one commit, no tags — LatestTag
234+ // must be empty (agent signal: propose initial v0.1.0).
235+ func Test_Analyze_NoTag_NoHistory (t * testing.T ) {
236+ t .Parallel ()
237+ if testing .Short () {
238+ t .Skip ("skipping integration test in short mode" )
239+ }
240+ root := initTestRepo (t ,
241+ map [string ]string {"README.md" : "# fresh\n " },
242+ map [string ]string {"README.md" : "# fresh\n \n modified\n " },
243+ )
244+ got , err := AnalyzeCommit (context .Background (), AnalyzeOptions {Root : root })
245+ if err != nil {
246+ t .Fatalf ("AnalyzeCommit: %v" , err )
247+ }
248+ if got .LatestTag != "" {
249+ t .Errorf ("LatestTag = %q, want empty on untagged repo" , got .LatestTag )
250+ }
251+ }
252+
253+ // Test_Analyze_Visibility_None_PIISafe: a personal repo with no origin should
254+ // get "safe" default_action on PII REVIEW findings (emails/localhost), so the
255+ // agent can skip per-finding adjudication.
256+ func Test_Analyze_Visibility_None_PIISafe (t * testing.T ) {
257+ t .Parallel ()
258+ if testing .Short () {
259+ t .Skip ("skipping integration test in short mode" )
260+ }
261+ root := initTestRepo (t ,
262+ map [string ]string {"README.md" : "# readme\n " },
263+ map [string ]string {"README.md" : "# readme\n \n ping me at dev@example.com on localhost:8080\n " },
264+ )
265+ got , err := AnalyzeCommit (context .Background (), AnalyzeOptions {Root : root })
266+ if err != nil {
267+ t .Fatalf ("AnalyzeCommit: %v" , err )
268+ }
269+ if got .Remote .Visibility != "none" {
270+ t .Fatalf ("Remote.Visibility = %q, want %q (no origin remote)" , got .Remote .Visibility , "none" )
271+ }
272+ if got .Secrets .AmbiguousCount != 0 {
273+ t .Errorf ("AmbiguousCount = %d, want 0 (personal repo: PII REVIEWs should be safe)" , got .Secrets .AmbiguousCount )
274+ }
275+ findings := readFindings (t , got .Refs .Findings )
276+ if len (findings ) == 0 {
277+ t .Fatalf ("expected PII REVIEW findings for email/localhost" )
278+ }
279+ for _ , f := range findings {
280+ if f .Kind == "pii" && f .Class == "REVIEW" && f .DefaultAction != "safe" {
281+ t .Errorf ("PII REVIEW finding %q default_action = %q, want %q" , f .Snippet , f .DefaultAction , "safe" )
282+ }
283+ }
284+ }
285+
286+ // Test_Analyze_Visibility_FlagAlwaysFix: FLAG findings always get default_action=fix
287+ // regardless of visibility — live secrets are never "safe".
288+ func Test_Analyze_Visibility_FlagAlwaysFix (t * testing.T ) {
289+ t .Parallel ()
290+ if testing .Short () {
291+ t .Skip ("skipping integration test in short mode" )
292+ }
293+ root := initTestRepo (t ,
294+ map [string ]string {"config.yaml" : "key: value\n " },
295+ map [string ]string {"config.yaml" : "key: value\n aws_access_key: AKIAIOSFODNN7EXAMPLE\n " },
296+ )
297+ got , err := AnalyzeCommit (context .Background (), AnalyzeOptions {Root : root })
298+ if err != nil {
299+ t .Fatalf ("AnalyzeCommit: %v" , err )
300+ }
301+ if got .Secrets .FixCount < 1 {
302+ t .Errorf ("FixCount = %d, want >=1 (AKIA key must be fix)" , got .Secrets .FixCount )
303+ }
304+ findings := readFindings (t , got .Refs .Findings )
305+ for _ , f := range findings {
306+ if f .Class == "FLAG" && f .DefaultAction != "fix" {
307+ t .Errorf ("FLAG finding %q default_action = %q, want %q" , f .Snippet , f .DefaultAction , "fix" )
308+ }
309+ }
310+ }
311+
173312func containsAll (haystack []string , needles ... string ) bool {
174313 set := make (map [string ]bool , len (haystack ))
175314 for _ , h := range haystack {
0 commit comments