-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.json
More file actions
506 lines (506 loc) · 29.4 KB
/
Copy pathindex.json
File metadata and controls
506 lines (506 loc) · 29.4 KB
1
2
3
4
5
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
[
{
"anchor": "agent-cmd/agent-frontmatter",
"applies_when": "any `agents/*.md` file is created.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/agent-frontmatter",
"level": "MUST",
"owner": "agent-auditor"
},
{
"anchor": "agent-cmd/command-frontmatter",
"applies_when": "any `commands/*.md` file is created.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/command-frontmatter",
"level": "MUST",
"owner": "slash-command-auditor"
},
{
"anchor": "agent-cmd/command-thin",
"applies_when": "any new `commands/*.md` file is added or substantially changed.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/command-thin",
"level": "MUST",
"owner": "slash-command-auditor"
},
{
"anchor": "agent-cmd/gap-driven-feedback",
"applies_when": "an agent depends on documented information that may be incomplete.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/gap-driven-feedback",
"level": "SHOULD",
"owner": "agent-auditor"
},
{
"anchor": "agent-cmd/no-user-prompts",
"applies_when": "any agent or command performs work that could prompt the user (writing to `/tmp/`, requesting permissions, asking confirmation) during normal execution.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/no-user-prompts",
"level": "MUST",
"owner": "agent-auditor"
},
{
"anchor": "agent-cmd/scripts-in-claude-dir",
"applies_when": "an agent depends on executable scripts (Python, shell) to do real work.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/scripts-in-claude-dir",
"level": "MUST",
"owner": "agent-auditor"
},
{
"anchor": "agent-cmd/single-source-of-truth",
"applies_when": "an agent's domain has multiple potential data sources (config files, APIs, generated artifacts, documentation) and one of them is the authoritative, human-maintained source.",
"doc_path": "docs/agent-command-development-guide.md",
"enforcement": "judgment",
"id": "agent-cmd/single-source-of-truth",
"level": "SHOULD",
"owner": "agent-auditor"
},
{
"anchor": "go-architecture/business-logic-not-in-main",
"applies_when": "`main.go` (production code only — `main_test.go` is exempt) or `application.Run` contains domain operations (validation, business rules, data transformation, decision logic) instead of delegating to a service in `pkg/`.",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (semantic check — what counts as \"business logic\" requires reading the code). Coarse ast-grep filter is possible: `main.go` containing imports of `bborbe/errors` or `bborbe/validation` is a strong signal that domain logic leaked out of `pkg/`; production-file-scoped, `_test.go` excluded.",
"id": "go-architecture/business-logic-not-in-main",
"level": "MUST",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-architecture/constructor-returns-interface",
"applies_when": "a Go `New*` constructor returns the concrete struct type (`*userService`) instead of the interface it implements (`UserService`).",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (ast-grep follow-up: `function_declaration` with name `^New` and result containing the concrete struct, paired with the corresponding interface declaration in the same package)",
"id": "go-architecture/constructor-returns-interface",
"level": "MUST",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-architecture/counterfeiter-directive-on-interface",
"applies_when": "an exported `interface` declaration in a non-`main` Go service package (i.e. likely substituted via mocks in tests) has no preceding `//counterfeiter:generate` line. Concrete trigger: any package with `*_test.go` files that import a `mocks` package, plus every exported interface in that package.",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (ast-grep partial: pattern over `interface_declaration` with surrounding-comment context per the PR #11 struct-literal recipe — negative-precedes relations are awkward in ast-grep 0.43.0, so the agent does the absence check)",
"id": "go-architecture/counterfeiter-directive-on-interface",
"level": "MUST",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-architecture/new-prefix-constructor-naming",
"applies_when": "a Go function outside `pkg/factory/**` returns an exported interface or struct type and is intended to be the canonical construction site, but the function name does not start with `New`.",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (ast-grep follow-up: `function_declaration` returning a service-interface type with `name` not matching `^New`. `Create*` factories under `pkg/factory/**` are covered by `go-factory/no-impl-in-factory-pkg` instead and MUST be excluded from this rule's scope).",
"id": "go-architecture/new-prefix-constructor-naming",
"level": "MUST",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-architecture/no-globals-or-singletons",
"applies_when": "a Go service package introduces a service dependency (logger, DB, HTTP client, time getter, etc.) via any of: (a) a package-level `var` declaration, (b) initialisation inside `func init()`, or (c) lazy initialisation via `sync.Once` keyed to a package-level pointer. All three patterns share the same test-ordering and parallelism problems.",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (ast-grep follow-up: `kind: var_spec` at file scope + `kind: function_declaration` named `init` + `sync.Once` patterns with package-level state; full enforcement needs package-scope reasoning to distinguish service deps from constants and config values).",
"id": "go-architecture/no-globals-or-singletons",
"level": "MUST",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-architecture/private-struct-matches-interface",
"applies_when": "a Go package exposes an exported interface (e.g. `UserService`) and the package contains exactly one struct implementing every method of that interface, but the struct's name is not the interface name with the first letter lowercased (`userService`).",
"doc_path": "docs/go-architecture-patterns.md",
"enforcement": "judgment (paired-declaration scan: for each exported interface, find structs with matching method sets in the same package and check name correspondence — single-implementation packages only)",
"id": "go-architecture/private-struct-matches-interface",
"level": "SHOULD",
"owner": "go-architecture-assistant"
},
{
"anchor": "go-context/cancel-check-in-loop",
"applies_when": "Go `for` loop body lacks a non-blocking `select { case <-ctx.Done(): ...; default: }` check, outside `*_test.go` and `vendor/`.",
"doc_path": "docs/go-context-cancellation-in-loops.md",
"enforcement": "`rules/go/cancel-check-in-loop.yml` (mechanical flag) + judgment-tier LLM adjudication for \"long-running enough to matter\".",
"id": "go-context/cancel-check-in-loop",
"level": "SHOULD",
"owner": "go-context-assistant"
},
{
"anchor": "go-doc/comment-starts-with-name",
"applies_when": "an exported identifier has a doc comment whose first word does not match the identifier's name exactly (case-sensitive).",
"doc_path": "docs/go-doc-best-practices.md",
"enforcement": "judgment (mechanical follow-up: no standard linter catches this — `revive`'s `exported` rule only flags *missing* doc comments, not first-word mismatch. Best path is an ast-grep pattern over `func_declaration` / `type_declaration` + adjacent comment text, comparing the first whitespace-delimited word against the identifier name — see PR #11 recipe for the surrounding-comment pattern shape)",
"id": "go-doc/comment-starts-with-name",
"level": "MUST",
"owner": "godoc-assistant"
},
{
"anchor": "go-doc/exported-item-must-have-comment",
"applies_when": "a Go file defines an exported (capitalized) function, method, type, interface, struct, struct field, constant, or variable without a preceding `//` doc comment.",
"doc_path": "docs/go-doc-best-practices.md",
"enforcement": "judgment (mechanical follow-up: enable `revive`'s `exported` rule or `golangci-lint`'s `revive` linter with `exported` enabled — these flag every exported identifier without a doc comment)",
"id": "go-doc/exported-item-must-have-comment",
"level": "MUST",
"owner": "godoc-assistant"
},
{
"anchor": "go-doc/package-comment-in-doc-go",
"applies_when": "a Go package's package-level comment lives in a regular source file (`<feature>.go`) rather than in a dedicated `doc.go`.",
"doc_path": "docs/go-doc-best-practices.md",
"enforcement": "judgment (filename presence + first-comment-block check)",
"id": "go-doc/package-comment-in-doc-go",
"level": "SHOULD",
"owner": "godoc-assistant"
},
{
"anchor": "go-doc/third-person-no-signature-repeat",
"applies_when": "a doc comment uses first-person (\"I\", \"we\", \"our\") OR repeats the function signature verbatim in the prose (\"takes an `int` and returns a `string`\" when the signature already says `func F(int) string`).",
"doc_path": "docs/go-doc-best-practices.md",
"enforcement": "judgment (prose linters can flag first-person; signature-repeat is semantic and needs review)",
"id": "go-doc/third-person-no-signature-repeat",
"level": "SHOULD",
"owner": "godoc-assistant"
},
{
"anchor": "go-errors/inner-closure-no-double-wrap",
"applies_when": "an inner closure (passed to `db.Update`, `filepath.WalkDir`, or similar callback APIs) calls `errors.Wrap`/`errors.Wrapf` while the surrounding function ALSO wraps the closure's return value.",
"doc_path": "docs/go-error-wrapping-guide.md",
"enforcement": "judgment",
"id": "go-errors/inner-closure-no-double-wrap",
"level": "SHOULD",
"owner": "go-error-assistant"
},
{
"anchor": "go-errors/no-bare-return-err",
"applies_when": "a Go `return err` statement appears inside an `if err != nil { ... }` block, outside `*_test.go` and `vendor/`. Inner closures where the outer scope already wraps are an exception — see RULE `go-errors/inner-closure-no-double-wrap`.",
"doc_path": "docs/go-error-wrapping-guide.md",
"enforcement": "`rules/go/no-bare-return-err.yml`",
"id": "go-errors/no-bare-return-err",
"level": "MUST",
"owner": "go-error-assistant"
},
{
"anchor": "go-errors/no-context-background-in-business-logic",
"applies_when": "a Go `context.Background()` call appears outside `main.go`, `cmd/**`, `*_test.go`, `vendor/`. Top-level goroutine spawners in `main` are exempt by path filter.",
"doc_path": "docs/go-error-wrapping-guide.md",
"enforcement": "`rules/go/no-context-background-in-business-logic.yml`",
"id": "go-errors/no-context-background-in-business-logic",
"level": "MUST",
"owner": "go-error-assistant"
},
{
"anchor": "go-errors/no-fmt-errorf",
"applies_when": "any `*.go` file outside `main.go`, `*_test.go`, `vendor/` calls `fmt.Errorf(...)`.",
"doc_path": "docs/go-error-wrapping-guide.md",
"enforcement": "`rules/go/no-fmt-errorf.yml`",
"id": "go-errors/no-fmt-errorf",
"level": "MUST",
"owner": "go-error-assistant"
},
{
"anchor": "go-errors/sentinel-err-prefix-naming",
"applies_when": "a package-level sentinel error variable uses the legacy `XxxError`/`XxxErr` naming convention (e.g. `BucketNotFoundErr`, `ConnectionError`) instead of the stdlib-style `ErrXxx` prefix (`ErrBucketNotFound`, `ErrConnection`).",
"doc_path": "docs/go-error-wrapping-guide.md",
"enforcement": "judgment",
"id": "go-errors/sentinel-err-prefix-naming",
"level": "SHOULD",
"owner": "go-error-assistant"
},
{
"anchor": "go-factory/no-cleanup-return",
"applies_when": "a Go function whose name starts with `Create` declared in a `*.go` file outside `*_test.go` and `vendor/` has a return type list that includes `func()` (a cleanup closure). Common shapes: `(T, func())`, `(T, func(), error)`, `(func(), error)`.",
"doc_path": "docs/go-factory-pattern.md",
"enforcement": "`rules/go/factory-no-cleanup-return.yml` (mechanical flag) + judgment-tier LLM adjudication for any legitimate edge case.",
"id": "go-factory/no-cleanup-return",
"level": "MUST",
"owner": "go-factory-pattern-assistant"
},
{
"anchor": "go-factory/no-conditional-in-body",
"applies_when": "a Go function whose name starts with `Create` declared in a `*.go` file outside `*_test.go` and `vendor/` contains an `if`, `switch`, or `for` statement anywhere in its body. Anonymous functions inside the body that are pure pass-throughs (single method call, no logic — see section 4.3 `Run Function Wrapper`) are an acceptable exception adjudicated by the judgment tier.",
"doc_path": "docs/go-factory-pattern.md",
"enforcement": "`rules/go/factory-no-conditional-in-body.yml` (mechanical flag) + judgment-tier LLM adjudication for the anonymous-function exception.",
"id": "go-factory/no-conditional-in-body",
"level": "MUST",
"owner": "go-factory-pattern-assistant"
},
{
"anchor": "go-factory/no-error-return",
"applies_when": "a Go function whose name starts with `Create` declared in a `*.go` file outside `*_test.go` and `vendor/` has a return type list that includes `error`. The single permitted exception is a pass-through wrapper per section 7 — a one-statement factory that immediately returns an error-returning constructor call without adding wiring, logging, or validation.",
"doc_path": "docs/go-factory-pattern.md",
"enforcement": "`rules/go/factory-no-error-return.yml` (mechanical flag) + judgment-tier LLM adjudication for the pass-through wrapper exception.",
"id": "go-factory/no-error-return",
"level": "MUST",
"owner": "go-factory-pattern-assistant"
},
{
"anchor": "go-factory/no-impl-in-factory-pkg",
"applies_when": "a `*.go` file inside `pkg/factory/` (any path matching `**/pkg/factory/*.go`) contains a struct type declaration with non-trivial methods (methods with logic beyond a trivial accessor), an interface declaration with multiple methods, or any function declaration that is NOT a `Create*` factory function. Detecting \"non-trivial\" requires reading the method body — pure ast-grep can match `type X struct` and method declarations but cannot reliably decide which methods are \"trivial\".",
"doc_path": "docs/go-factory-pattern.md",
"enforcement": "judgment — implementation-vs-trivial-helper distinction needs whole-method reasoning. Mechanical flag can catch structural violations (non-`Create*` function declarations, multi-method interfaces, impl structs) inside `pkg/factory/`, but the \"trivial accessor\" exception requires LLM adjudication.",
"id": "go-factory/no-impl-in-factory-pkg",
"level": "MUST",
"owner": "go-factory-pattern-assistant"
},
{
"anchor": "go-http-handler/kebab-case-handler-files",
"applies_when": "a `*.go` file under `**/pkg/handler/**` is named with non-kebab-case style (e.g. `exists_handler.go`, `existshandler.go`, or `handler.go`) instead of the documented `<action>-<noun>.go` kebab-case (e.g. `exists.go`, `forward-invoice.go`). Pure ast-grep operates on file contents, not filenames — this is a filesystem convention check.",
"doc_path": "docs/go-http-handler-refactoring-guide.md",
"enforcement": "judgment",
"id": "go-http-handler/kebab-case-handler-files",
"level": "SHOULD",
"owner": "go-http-handler-assistant"
},
{
"anchor": "go-http-handler/new-prefix-naming",
"applies_when": "a function declared in a `*.go` file inside `**/pkg/handler/**` returning `libhttp.WithError`, `run.Func`, or `http.Handler` does not follow the `New[Purpose]Handler` naming pattern. Pure ast-grep can match the function's return type but cannot reliably check whether the chosen name is descriptive enough — that semantic check needs a reviewer.",
"doc_path": "docs/go-http-handler-refactoring-guide.md",
"enforcement": "judgment",
"id": "go-http-handler/new-prefix-naming",
"level": "MUST",
"owner": "go-http-handler-assistant"
},
{
"anchor": "go-http-handler/no-inline-background-handler",
"applies_when": "`libhttp.NewBackgroundRunHandler(ctx, func ...)` is called with an inline anonymous function as its second argument in a `*.go` file outside `**/pkg/handler/**`, `*_test.go`, and `vendor/`. The legitimate place is inside `pkg/handler/New*Handler` factories (returning `run.Func`).",
"doc_path": "docs/go-http-handler-refactoring-guide.md",
"enforcement": "`rules/go/handler-no-inline-background-handler.yml`",
"id": "go-http-handler/no-inline-background-handler",
"level": "MUST",
"owner": "go-http-handler-assistant"
},
{
"anchor": "go-http-handler/no-inline-error-handler",
"applies_when": "`libhttp.WithErrorFunc(func ...)` is called with an inline anonymous function as its argument in a `*.go` file outside `**/pkg/handler/**`, `*_test.go`, and `vendor/`. The legitimate place for inline error handler closures is inside `pkg/handler/New*Handler` factory functions; anywhere else (typically `main.go`) the closure should be extracted into the handler package.",
"doc_path": "docs/go-http-handler-refactoring-guide.md",
"enforcement": "`rules/go/handler-no-inline-error-handler.yml`",
"id": "go-http-handler/no-inline-error-handler",
"level": "MUST",
"owner": "go-http-handler-assistant"
},
{
"anchor": "go-licensing/copyright-year-discipline",
"applies_when": "a PR diff modifies copyright years in `*.go` source-file headers — either bulk-updating across many files or setting future / non-numeric years (`2099`, `present`, etc.).",
"doc_path": "docs/go-licensing-guide.md",
"enforcement": "judgment (diff inspection — ast-grep can detect `Copyright (c) 2099` shapes but the \"bulk-update for trivial changes\" trigger needs PR-scope reasoning)",
"id": "go-licensing/copyright-year-discipline",
"level": "MUST",
"owner": "license-assistant"
},
{
"anchor": "go-licensing/license-file-required",
"applies_when": "a Go project published to `github.com/*` (public) does not have a `LICENSE` file in its repo root.",
"doc_path": "docs/go-licensing-guide.md",
"enforcement": "judgment (file-existence check; ast-grep cannot detect file absence)",
"id": "go-licensing/license-file-required",
"level": "MUST",
"owner": "license-assistant"
},
{
"anchor": "go-licensing/readme-license-section-required",
"applies_when": "a public Go project's `README.md` has no `## License` (H2) section pointing at the root `LICENSE` file.",
"doc_path": "docs/go-licensing-guide.md",
"enforcement": "judgment (markdown section presence; ast-grep doesn't parse markdown structure)",
"id": "go-licensing/readme-license-section-required",
"level": "MUST",
"owner": "license-assistant"
},
{
"anchor": "go-licensing/source-file-header-required",
"applies_when": "a public Go project has `*.go` files outside `vendor/` without the 3-line BSD-2-Clause header block at the top.",
"doc_path": "docs/go-licensing-guide.md",
"enforcement": "`addlicense -check` invocation via `make precommit` (the canonical tool; ast-grep can detect missing headers via first-line regex, but `addlicense` is already wired through the toolchain).",
"id": "go-licensing/source-file-header-required",
"level": "MUST",
"owner": "license-assistant"
},
{
"anchor": "go-prometheus/composed-metrics-interface",
"applies_when": "a single `Metrics` interface aggregates methods spanning two or more distinct functional domains (handlers + senders + schedulers + …), forcing consumers to depend on methods they don't use.",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "judgment",
"id": "go-prometheus/composed-metrics-interface",
"level": "SHOULD",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-prometheus/counter-pre-initialization",
"applies_when": "a CounterVec is registered for a label set whose value domain is small, bounded, and known at compile time (typically < 20 combinations — enum, fixed slice of strings, etc.). For large or unbounded domains, prefer `absent()` checks in alerting rules instead.",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "judgment",
"id": "go-prometheus/counter-pre-initialization",
"level": "MUST",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-prometheus/counter-total-suffix",
"applies_when": "a `prometheus.CounterOpts` struct literal sets a `Name:` field whose string value does not end with `_total`.",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "`rules/go/counter-total-suffix.yml`",
"id": "go-prometheus/counter-total-suffix",
"level": "MUST",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-prometheus/help-string-quality",
"applies_when": "any `prometheus.{Counter,Gauge,Histogram,Summary}Opts` struct literal sets a `Help:` field that (a) is empty, (b) duplicates another metric's Help verbatim, or (c) describes a different metric (copy-paste residue).",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "judgment",
"id": "go-prometheus/help-string-quality",
"level": "MUST",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-prometheus/label-naming-consistency",
"applies_when": "two or more metrics in the same project reference the same conceptual entity using different label names (e.g. `product` vs `item` for product ID; `tenant` vs `customer` vs `org`).",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "judgment",
"id": "go-prometheus/label-naming-consistency",
"level": "MUST",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-prometheus/no-gauge-for-monotonic",
"applies_when": "a `prometheus.NewGaugeVec` / `prometheus.NewGauge` registers a metric the code only ever increments (only `.Inc()` / `.Add(positive)` call sites, never `.Set()` / `.Dec()` / `.Sub()`).",
"doc_path": "docs/go-prometheus-metrics-guide.md",
"enforcement": "judgment",
"id": "go-prometheus/no-gauge-for-monotonic",
"level": "MUST",
"owner": "go-metrics-assistant"
},
{
"anchor": "go-security/chmod-return-checked",
"applies_when": "an `os.Chmod($PATH, $PERM)` call in a `*.go` file outside `*_test.go` and `vendor/` whose return value is discarded (no `if err := os.Chmod(...); err != nil` wrapper, no `_ = os.Chmod(...)` with an explanatory comment). Detecting \"return value used in error check\" requires reading the surrounding statement — pure ast-grep cannot reliably distinguish a checked `os.Chmod(...)` from an unchecked one without false positives.",
"doc_path": "docs/go-security-linting.md",
"enforcement": "judgment",
"id": "go-security/chmod-return-checked",
"level": "MUST",
"owner": "go-security-specialist"
},
{
"anchor": "go-security/dir-perms-too-permissive",
"applies_when": "`os.MkdirAll($PATH, $PERM)` or `os.Mkdir($PATH, $PERM)` calls in a `*.go` file outside `*_test.go` and `vendor/`, where `$PERM` is a literal octal that is NOT `0750` / `0o750`.",
"doc_path": "docs/go-security-linting.md",
"enforcement": "`rules/go/dir-perms-too-permissive.yml`",
"id": "go-security/dir-perms-too-permissive",
"level": "MUST",
"owner": "go-security-specialist"
},
{
"anchor": "go-security/file-perms-too-permissive",
"applies_when": "`os.WriteFile($PATH, $DATA, $PERM)` or `os.OpenFile($PATH, $FLAGS, $PERM)` calls in a `*.go` file outside `*_test.go` and `vendor/`, where `$PERM` is a literal octal that is NOT `0600` / `0o600`.",
"doc_path": "docs/go-security-linting.md",
"enforcement": "`rules/go/file-perms-too-permissive.yml`",
"id": "go-security/file-perms-too-permissive",
"level": "MUST",
"owner": "go-security-specialist"
},
{
"anchor": "go-security/nosec-requires-reason",
"applies_when": "a `// #nosec <CODE>` comment in a `*.go` file outside `*_test.go` and `vendor/` appears WITHOUT a `-- <reason>` text component on the same line.",
"doc_path": "docs/go-security-linting.md",
"enforcement": "`rules/go/nosec-requires-reason.yml`",
"id": "go-security/nosec-requires-reason",
"level": "MUST",
"owner": "go-security-specialist"
},
{
"anchor": "go-testing/counterfeiter-mocks-required",
"applies_when": "a test file declares a hand-written struct that satisfies a production interface and is used in place of a real implementation under test, instead of importing a `mocks/<Name>` fake produced by Counterfeiter.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (presence of `//counterfeiter:generate` directive + hand-written fake detection; ast-grep follow-up)",
"id": "go-testing/counterfeiter-mocks-required",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/libtime-injection-required",
"applies_when": "a Go business-logic file (outside `main.go`, `cmd/**`, `*_test.go`, `vendor/`) reads the current time. Tests cannot control `time.Now()` directly, so dependent code is unverifiable.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "cross-rule — overlaps with `go-time/no-time-now-direct` (already in `rules/index.json`). This rule scopes the same constraint to test-coverage assessments: a service that doesn't inject time has no testable time-dependent paths.",
"id": "go-testing/libtime-injection-required",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/main-test-with-compiles",
"applies_when": "a Go binary project (package `main` with `main.go`) does not have a `main_test.go` containing a `Compiles` It-block backed by `gexec.Build`.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (file-existence + body check; ast-grep follow-up)",
"id": "go-testing/main-test-with-compiles",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/no-bare-error-call",
"applies_when": "a Go test file inside an `It` / `BeforeEach` / `JustBeforeEach` / `AfterEach` block calls an error-returning function whose return value is discarded.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (ast-grep follow-up — errcheck-equivalent scoped to Ginkgo blocks)",
"id": "go-testing/no-bare-error-call",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/no-stdlib-table-tests",
"applies_when": "a Go test file in a package that has a Ginkgo `*_suite_test.go` uses `t.Run` inside a `for _, tt := range tests` loop instead of `DescribeTable`/`Entry`.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (ast-grep follow-up)",
"id": "go-testing/no-stdlib-table-tests",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/no-testing-t-direct",
"applies_when": "a Go file in a package that has a Ginkgo `TestSuite` entry-point uses `*testing.T` directly inside test functions other than the suite entry-point itself.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (ast-grep follow-up)",
"id": "go-testing/no-testing-t-direct",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/suite-test-file-required",
"applies_when": "a Go package contains test files (`*_test.go`) but no `*_suite_test.go` file with a `TestSuite` entry-point and `RunSpecs`.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (file-existence check; ast-grep follow-up)",
"id": "go-testing/suite-test-file-required",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-testing/suite-timeout-required",
"applies_when": "a `*_suite_test.go` file calls `GinkgoConfiguration()` without setting `suiteConfig.Timeout` before `RunSpecs`.",
"doc_path": "docs/go-testing-guide.md",
"enforcement": "judgment (ast-grep follow-up — pattern over suite body)",
"id": "go-testing/suite-timeout-required",
"level": "MUST",
"owner": "go-test-quality-assistant"
},
{
"anchor": "go-time/inject-getter-not-create",
"applies_when": "a factory or constructor file outside `main.go` calls `libtime.NewCurrentDateTime()`.",
"doc_path": "docs/go-time-injection.md",
"enforcement": "judgment",
"id": "go-time/inject-getter-not-create",
"level": "MUST",
"owner": "go-time-assistant"
},
{
"anchor": "go-time/no-time-now-direct",
"applies_when": "any `*.go` file outside `main.go`, `*_test.go`, `vendor/` calls `time.Now()` directly.",
"doc_path": "docs/go-time-injection.md",
"enforcement": "`rules/go/no-time-now-direct.yml`",
"id": "go-time/no-time-now-direct",
"level": "MUST",
"owner": "go-time-assistant"
},
{
"anchor": "go-time/no-time-time-in-fields",
"applies_when": "any Go struct field is declared with stdlib type `time.Time` or `time.Duration`.",
"doc_path": "docs/go-time-injection.md",
"enforcement": "`rules/go/no-time-time-in-fields.yml`",
"id": "go-time/no-time-time-in-fields",
"level": "MUST",
"owner": "go-time-assistant"
}
]