nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: distribution/distribution
Pull request #2911 (2019-04-29 13:52:00)

Populate the platform information when calling the References() method of manifest list
Populate the platform information when calling the References() method of manifest list

Signed-off-by: Wenkai Yin <yinw@vmware.com>

milosgajdos: @ywk253100 can you please rebase?

Patch:
diff --git a/manifest/manifestlist/manifestlist.go b/manifest/manifestlist/manifestlist.go
index 833a6d50..55c0224e 100644
--- a/manifest/manifestlist/manifestlist.go
+++ b/manifest/manifestlist/manifestlist.go
@@ -126,6 +126,13 @@ func (m ManifestList) References() []distribution.Descriptor {
 	dependencies := make([]distribution.Descriptor, len(m.Manifests))
 	for i := range m.Manifests {
 		dependencies[i] = m.Manifests[i].Descriptor
+		dependencies[i].Platform = &v1.Platform{
+			Architecture: m.Manifests[i].Platform.Architecture,
+			OS:           m.Manifests[i].Platform.OS,
+			OSVersion:    m.Manifests[i].Platform.OSVersion,
+			OSFeatures:   m.Manifests[i].Platform.OSFeatures,
+			Variant:      m.Manifests[i].Platform.Variant,
+		}
 	}
 
 	return dependencies


Test patch:
diff --git a/manifest/manifestlist/manifestlist_test.go b/manifest/manifestlist/manifestlist_test.go
index fc77af18..860dca51 100644
--- a/manifest/manifestlist/manifestlist_test.go
+++ b/manifest/manifestlist/manifestlist_test.go
@@ -110,6 +110,18 @@ func TestManifestList(t *testing.T) {
 		t.Fatalf("unexpected number of references: %d", len(references))
 	}
 	for i := range references {
+		platform := manifestDescriptors[i].Platform
+		expectedPlatform := &v1.Platform{
+			Architecture: platform.Architecture,
+			OS:           platform.OS,
+			OSFeatures:   platform.OSFeatures,
+			OSVersion:    platform.OSVersion,
+			Variant:      platform.Variant,
+		}
+		if !reflect.DeepEqual(references[i].Platform, expectedPlatform) {
+			t.Fatalf("unexpected value %d returned by References: %v", i, references[i])
+		}
+		references[i].Platform = nil
 		if !reflect.DeepEqual(references[i], manifestDescriptors[i].Descriptor) {
 			t.Fatalf("unexpected value %d returned by References: %v", i, references[i])
 		}
@@ -247,6 +259,18 @@ func TestOCIImageIndex(t *testing.T) {
 		t.Fatalf("unexpected number of references: %d", len(references))
 	}
 	for i := range references {
+		platform := manifestDescriptors[i].Platform
+		expectedPlatform := &v1.Platform{
+			Architecture: platform.Architecture,
+			OS:           platform.OS,
+			OSFeatures:   platform.OSFeatures,
+			OSVersion:    platform.OSVersion,
+			Variant:      platform.Variant,
+		}
+		if !reflect.DeepEqual(references[i].Platform, expectedPlatform) {
+			t.Fatalf("unexpected value %d returned by References: %v", i, references[i])
+		}
+		references[i].Platform = nil
 		if !reflect.DeepEqual(references[i], manifestDescriptors[i].Descriptor) {
 			t.Fatalf("unexpected value %d returned by References: %v", i, references[i])
 		}
Repository: distribution/distribution
Pull request #3881 (2023-04-27 17:52:01)

registry/errors: Parse http forbidden as denied
This fixes error caused by requesting a push token with the "Public repo read-only" permission not being correctly parsed into a typed error.


Patch:
diff --git a/registry/client/errors.go b/registry/client/errors.go
index 68bfe19d..8394ee0c 100644
--- a/registry/client/errors.go
+++ b/registry/client/errors.go
@@ -54,6 +54,8 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
 		switch statusCode {
 		case http.StatusUnauthorized:
 			return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
+		case http.StatusForbidden:
+			return errcode.ErrorCodeDenied.WithMessage(detailsErr.Details)
 		case http.StatusTooManyRequests:
 			return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details)
 		default:


Test patch:
diff --git a/registry/client/errors_test.go b/registry/client/errors_test.go
index ca9dddd1..6be399d0 100644
--- a/registry/client/errors_test.go
+++ b/registry/client/errors_test.go
@@ -102,3 +102,18 @@ func TestHandleErrorResponseUnexpectedStatusCode501(t *testing.T) {
 		t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
 	}
 }
+
+func TestHandleErrorResponseInsufficientPrivileges403(t *testing.T) {
+	json := `{"details":"requesting higher privileges than access token allows"}`
+	response := &http.Response{
+		Status:     "403 Forbidden",
+		StatusCode: 403,
+		Body:       nopCloser{bytes.NewBufferString(json)},
+	}
+	err := HandleErrorResponse(response)
+
+	expectedMsg := "denied: requesting higher privileges than access token allows"
+	if !strings.Contains(err.Error(), expectedMsg) {
+		t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
+	}
+}
Repository: googleapis/api-linter
Pull request #77 (2019-06-13 15:36:23)

Added support for location information about the package definition


Patch:
diff --git a/lint/source.go b/lint/source.go
index 7713011..ae361aa 100644
--- a/lint/source.go
+++ b/lint/source.go
@@ -157,6 +157,16 @@ func (s DescriptorSource) SyntaxComments() (Comments, error) {
 	return s.findCommentsByPath([]int{syntaxTag})
 }
 
+// PackageLocation returns the location of the package definition.
+func (s DescriptorSource) PackageLocation() (Location, error) {
+	return s.findLocationByPath([]int{packageTag})
+}
+
+// PackageComments returns the comments of the package definition.
+func (s DescriptorSource) PackageComments() (Comments, error) {
+	return s.findCommentsByPath([]int{packageTag})
+}
+
 // DescriptorLocation returns a `Location` for the given descriptor.
 // If not found, returns (nil, ErrPathNotFound).
 func (s DescriptorSource) DescriptorLocation(d protoreflect.Descriptor) (Location, error) {
@@ -173,6 +183,7 @@ func getPath(d protoreflect.Descriptor) []int {
 }
 
 const syntaxTag = 12
+const packageTag = 2
 
 var enumTagInFile = 5
 var enumTagInMessage = 4


Test patch:
diff --git a/lint/source_test.go b/lint/source_test.go
index f557ec7..718b058 100644
--- a/lint/source_test.go
+++ b/lint/source_test.go
@@ -162,6 +162,35 @@ func TestSyntaxComments(t *testing.T) {
 	}
 }
 
+func TestPackageLocation(t *testing.T) {
+	req := readProtoFile(t, "test_source.protoset")
+	descSource := req.DescriptorSource()
+	want := Location{Position{5, 1}, Position{5, 25}}
+	got, err := descSource.PackageLocation()
+	if err != nil {
+		t.Errorf("PackageLocation() error: %s", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("PackageLocation() returns %v, but want %v", got, want)
+	}
+}
+
+func TestPackageComments(t *testing.T) {
+	req := readProtoFile(t, "test_source.protoset")
+	descSource := req.DescriptorSource()
+
+	want := Comments{
+		TrailingComments: "package comment\n",
+	}
+	got, err := descSource.PackageComments()
+	if err != nil {
+		t.Errorf("PackageComments() error: %s", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("PackageComments() returns %s, but want %s", got, want)
+	}
+}
+
 func TestIsRuleDisabled(t *testing.T) {
 	req := readProtoFile(t, "test_rule_disable.protoset")
 	fileDesc := req.ProtoFile()
diff --git a/lint/testdata/test_source.proto b/lint/testdata/test_source.proto
index 1d88335..524d021 100644
--- a/lint/testdata/test_source.proto
+++ b/lint/testdata/test_source.proto
@@ -2,7 +2,7 @@
 
 syntax = "proto2";
 
-package api.linter.lint;
+package api.linter.lint; //package comment
 
 // Outer
 message Outer {
Repository: googleapis/api-linter
Pull request #78 (2019-06-13 16:05:14)

Exposing Configs.GetRuleConfig
GetRuleConfig tells us which rules we actually want to run. By exposing this API, clients may be able to completely eliminate the need to compile protos by checking file paths against their set of rules.


Patch:
diff --git a/lint/config.go b/lint/config.go
index 9b5bdb7..cd2da3e 100644
--- a/lint/config.go
+++ b/lint/config.go
@@ -109,9 +109,9 @@ func ReadConfigsYAML(f io.Reader) (Configs, error) {
 	return c, nil
 }
 
-// getRuleConfig returns a RuleConfig that matches the given path and rule.
+// GetRuleConfig returns a RuleConfig that matches the given path and rule.
 // Returns an error if a config is not found for the path.
-func (c Configs) getRuleConfig(path string, rule RuleName) (result RuleConfig, err error) {
+func (c Configs) GetRuleConfig(path string, rule RuleName) (result RuleConfig, err error) {
 	err = fmt.Errorf("failed to find a config for path %q", path)
 	for _, cfg := range c {
 		if cfg.match(path) {
diff --git a/lint/linter.go b/lint/linter.go
index d698cf7..9dc37ec 100644
--- a/lint/linter.go
+++ b/lint/linter.go
@@ -73,7 +73,7 @@ func (l *Linter) run(req Request) (Response, error) {
 	for name, rl := range l.rules {
 		var config RuleConfig
 
-		if c, err := l.configs.getRuleConfig(req.ProtoFile().Path(), name); err == nil {
+		if c, err := l.configs.GetRuleConfig(req.ProtoFile().Path(), name); err == nil {
 			config = config.withOverride(c)
 		} else {
 			errMessages = append(errMessages, err.Error())


Test patch:
diff --git a/lint/config_test.go b/lint/config_test.go
index deb7443..a3eb1c4 100644
--- a/lint/config_test.go
+++ b/lint/config_test.go
@@ -101,9 +101,9 @@ func TestRuleConfigs_getRuleConfig(t *testing.T) {
 		},
 	}
 	for ind, test := range tests {
-		cfg, _ := test.configs.getRuleConfig(test.path, test.rule)
+		cfg, _ := test.configs.GetRuleConfig(test.path, test.rule)
 		if cfg != test.result {
-			t.Errorf("Test #%d: %+v.getRuleConfig(%q, %q)=%+v; want %+v", ind+1, test.configs, test.path, test.rule, cfg, test.result)
+			t.Errorf("Test #%d: %+v.GetRuleConfig(%q, %q)=%+v; want %+v", ind+1, test.configs, test.path, test.rule, cfg, test.result)
 		}
 	}
 }
Repository: googleapis/api-linter
Pull request #85 (2019-06-17 13:44:10)

Executing rules inside a function that recovers from panics.
This will prevent a panic inside a rule from impacting the rest of the linter rules.


Patch:
diff --git a/lint/linter.go b/lint/linter.go
index 9dc37ec..e4ce62d 100644
--- a/lint/linter.go
+++ b/lint/linter.go
@@ -18,6 +18,7 @@ package lint
 
 import (
 	"errors"
+	"fmt"
 	"strings"
 
 	"google.golang.org/protobuf/types/descriptorpb"
@@ -81,7 +82,7 @@ func (l *Linter) run(req Request) (Response, error) {
 		}
 
 		if !config.Disabled && !req.DescriptorSource().isRuleDisabledInFile(rl.Info().Name) {
-			if problems, err := rl.Lint(req); err == nil {
+			if problems, err := l.runAndRecoverFromPanics(rl, req); err == nil {
 				for _, p := range problems {
 					if !req.DescriptorSource().isRuleDisabled(rl.Info().Name, p.Descriptor) {
 						p.RuleID = rl.Info().Name
@@ -102,3 +103,17 @@ func (l *Linter) run(req Request) (Response, error) {
 
 	return resp, err
 }
+
+func (l *Linter) runAndRecoverFromPanics(rl Rule, req Request) (probs []Problem, err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			if rerr, ok := r.(error); ok {
+				err = rerr
+			} else {
+				err = fmt.Errorf("panic occurred during rule execution: %v", r)
+			}
+		}
+	}()
+
+	return rl.Lint(req)
+}


Test patch:
diff --git a/lint/linter_test.go b/lint/linter_test.go
index 5c300ec..a754787 100644
--- a/lint/linter_test.go
+++ b/lint/linter_test.go
@@ -15,7 +15,9 @@
 package lint
 
 import (
+	"fmt"
 	"reflect"
+	"strings"
 	"testing"
 
 	"google.golang.org/protobuf/types/descriptorpb"
@@ -109,3 +111,39 @@ func TestLinter_run(t *testing.T) {
 		}
 	}
 }
+
+type panickingRule struct{}
+
+func (r *panickingRule) Info() RuleInfo                    { return RuleInfo{Name: "panic"} }
+func (r *panickingRule) Lint(_ Request) ([]Problem, error) { panic("panic") }
+
+type panickingErrorRule struct{}
+
+func (r *panickingErrorRule) Info() RuleInfo                    { return RuleInfo{Name: "panic"} }
+func (r *panickingErrorRule) Lint(_ Request) ([]Problem, error) { panic(fmt.Errorf("panic")) }
+
+func TestLinter_LintProtos_RulePanics(t *testing.T) {
+	tests := []struct {
+		rule Rule
+	}{{&panickingRule{}}, {&panickingErrorRule{}}}
+
+	for _, test := range tests {
+		r, err := NewRules(test.rule)
+		if err != nil {
+			t.Fatalf("Failed to create Rules: %q", err)
+		}
+
+		fd := new(descriptorpb.FileDescriptorProto)
+		fd.SourceCodeInfo = new(descriptorpb.SourceCodeInfo)
+
+		l := New(r, []Config{{
+			IncludedPaths: []string{"**"},
+			RuleConfigs:   map[string]RuleConfig{"": {}},
+		}})
+
+		_, err = l.LintProtos([]*descriptorpb.FileDescriptorProto{fd})
+		if err == nil || !strings.Contains(err.Error(), "panic") {
+			t.Fatalf("Expected error with panic, got %q", err)
+		}
+	}
+}
Repository: googleapis/api-linter
Pull request #298 (2019-11-04 19:29:59)

Added rule doc uri to the output.
Example output:

```yaml
- file_path: dummy.proto
  problems:
  - message: Method "GetDummyRequest" has no `name` field
    location:
      start_position:
        line_number: 5
        column_number: 1
      end_position:
        line_number: 7
        column_number: 2
    rule_id: core::0131::request-name-field
    rule_doc_uri: https://googleapis.github.io/api-linter/rules/core/0131-request-name-field.html
```


Patch:
diff --git a/lint/problem.go b/lint/problem.go
index 5f123c8..9fda25b 100644
--- a/lint/problem.go
+++ b/lint/problem.go
@@ -16,6 +16,7 @@ package lint
 
 import (
 	"encoding/json"
+	"strings"
 
 	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
 	"github.com/jhump/protoreflect/desc"
@@ -87,12 +88,14 @@ func (p Problem) marshal() interface{} {
 		Suggestion string       `json:"suggestion,omitempty" yaml:"suggestion,omitempty"`
 		Location   fileLocation `json:"location" yaml:"location"`
 		RuleID     RuleName     `json:"rule_id" yaml:"rule_id"`
+		RuleDocURI string       `json:"rule_doc_uri" yaml:"rule_doc_uri"`
 		Category   string       `json:"category,omitempty" yaml:"category,omitempty"`
 	}{
 		p.Message,
 		p.Suggestion,
 		fileLocationFromPBLocation(loc),
 		p.RuleID,
+		ruleDocURI(p.RuleID),
 		p.category,
 	}
 }
@@ -151,3 +154,12 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 		},
 	}
 }
+
+// ruleDocURI returns the link to the rule doc in https://googleapis.github.io/api-linter.
+func ruleDocURI(name RuleName) string {
+	base := "https://googleapis.github.io/api-linter/rules"
+	nameParts := strings.Split(string(name), "::") // e.g., core::0122::camel-case-uri -> ["core", "0122", "camel-case-uri"]
+	ruleSet := nameParts[0]
+	path := strings.Join(nameParts[1:], "-")
+	return base + "/" + ruleSet + "/" + path + ".html"
+}


Test patch:
diff --git a/lint/problem_test.go b/lint/problem_test.go
index eb235ce..6f0a180 100644
--- a/lint/problem_test.go
+++ b/lint/problem_test.go
@@ -117,3 +117,23 @@ func TestProblemDescriptor(t *testing.T) {
 	}
 
 }
+
+func TestRuleDocURI(t *testing.T) {
+	cases := []struct {
+		name     string
+		ruleName RuleName
+		wantURI  string
+	}{{
+		name:     "CoreRule",
+		ruleName: NewRuleName("core", "0122", "camel-case-uris"),
+		wantURI:  "https://googleapis.github.io/api-linter/rules/core/0122-camel-case-uris.html",
+	}}
+
+	for _, test := range cases {
+		t.Run(test.name, func(t *testing.T) {
+			if got, want := ruleDocURI(test.ruleName), test.wantURI; got != want {
+				t.Errorf("ruleDocURI(%q): got %q, but want %q", string(test.ruleName), got, want)
+			}
+		})
+	}
+}
Repository: googleapis/api-linter
Pull request #337 (2019-11-12 20:12:13)

[fix] Make location ends inclusive.
They were exclusive and it causes an off-by-one issue.


Patch:
diff --git a/lint/problem.go b/lint/problem.go
index 5f5dede..6c92184 100644
--- a/lint/problem.go
+++ b/lint/problem.go
@@ -128,7 +128,8 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 	// If `span` has four ints; they correspond to
 	// [start line, start column, end line, end column].
 	//
-	// We add one because spans are zero-indexed.
+	// We add one because spans are zero-indexed, but not to the end column
+	// because we want the ending position to be inclusive and not exclusive.
 	if len(span) == 4 {
 		return fileLocation{
 			Start: position{
@@ -137,7 +138,7 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 			},
 			End: position{
 				Line:   int(span[2]) + 1,
-				Column: int(span[3]) + 1,
+				Column: int(span[3]),
 			},
 		}
 	}
@@ -145,7 +146,8 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 	// Okay, `span` has three ints; they correspond to
 	// [start line, start column, end column].
 	//
-	// We add one because spans are zero-indexed.
+	// We add one because spans are zero-indexed, but not to the end column
+	// because we want the ending position to be inclusive and not exclusive.
 	return fileLocation{
 		Start: position{
 			Line:   int(span[0]) + 1,
@@ -153,7 +155,7 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 		},
 		End: position{
 			Line:   int(span[0]) + 1,
-			Column: int(span[2]) + 1,
+			Column: int(span[2]),
 		},
 	}
 }


Test patch:
diff --git a/lint/problem_test.go b/lint/problem_test.go
index 4dd591a..c4c7e01 100644
--- a/lint/problem_test.go
+++ b/lint/problem_test.go
@@ -27,7 +27,7 @@ import (
 func TestProblemJSON(t *testing.T) {
 	problem := &Problem{
 		Message:  "foo bar",
-		Location: &dpb.SourceCodeInfo_Location{Span: []int32{2, 0, 41}},
+		Location: &dpb.SourceCodeInfo_Location{Span: []int32{2, 0, 42}},
 		RuleID:   "core::0131",
 	}
 	serialized, err := json.Marshal(problem)
@@ -71,7 +71,7 @@ func TestProblemYAML(t *testing.T) {
 		{"LineNumberStart", `line_number: 3`},
 		{"LintNumberEnd", `line_number: 6`},
 		{"ColumnNumberStart", `column_number: 1`},
-		{"ColumnNumberEnd", `column_number: 71`},
+		{"ColumnNumberEnd", `column_number: 70`},
 		{"RuleID", `rule_id: core::0131`},
 	}
 	for _, test := range tests {
@@ -105,7 +105,7 @@ func TestProblemDescriptor(t *testing.T) {
 		{"Message", `message: foo bar`},
 		{"LineNumber", `line_number: 43`},
 		{"ColumnNumberStart", `column_number: 1`},
-		{"ColumnNumberEnd", `column_number: 80`},
+		{"ColumnNumberEnd", `column_number: 79`},
 		{"RuleID", `rule_id: core::0131`},
 	}
 	for _, test := range tests {
Repository: googleapis/api-linter
Pull request #342 (2019-11-13 01:41:00)

[cleanup] Move domain to linter.aip.dev.


Patch:
diff --git a/README.md b/README.md
index 031134a..a9e6816 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ message GetBookRequest {
 
 When able, it also offers a suggestion for the correct fix.
 
-[Read more ≫](https://googleapis.github.io/api-linter/)
+[_Read more ≫_](https://linter.aip.dev/)
 
 ## License
 
diff --git a/docs/_config.yml b/docs/_config.yml
index c5e7bb4..7591ab5 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -2,7 +2,7 @@
 markdown: kramdown
 plugins:
   - jekyll-redirect-from
-url: https://googleapis.github.io/api-linter
+url: https://linter.aip.dev
 defaults:
   - scope:
       path: ''
diff --git a/lint/problem.go b/lint/problem.go
index 6c92184..9ef5cbd 100644
--- a/lint/problem.go
+++ b/lint/problem.go
@@ -160,9 +160,9 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 	}
 }
 
-// ruleDocURI returns the link to the rule doc in https://googleapis.github.io/api-linter.
+// ruleDocURI returns the link to the rule doc in https://linter.aip.dev/.
 func ruleDocURI(name RuleName) string {
-	base := "https://googleapis.github.io/api-linter/rules"
+	base := "https://linter.aip.dev/rules"
 	nameParts := strings.Split(string(name), "::") // e.g., core::0122::camel-case-uri -> ["core", "0122", "camel-case-uri"]
 	ruleSet := nameParts[0]
 	path := strings.Join(nameParts[1:], "-")


Test patch:
diff --git a/lint/problem_test.go b/lint/problem_test.go
index c4c7e01..a99b000 100644
--- a/lint/problem_test.go
+++ b/lint/problem_test.go
@@ -126,7 +126,7 @@ func TestRuleDocURI(t *testing.T) {
 	}{{
 		name:     "CoreRule",
 		ruleName: NewRuleName(122, "camel-case-uris"),
-		wantURI:  "https://googleapis.github.io/api-linter/rules/core/0122-camel-case-uris.html",
+		wantURI:  "https://linter.aip.dev/rules/core/0122-camel-case-uris.html",
 	}}
 
 	for _, test := range cases {
Repository: googleapis/api-linter
Pull request #350 (2019-11-15 21:04:15)

[AIP-140] Permit order_by and group_by.


Patch:
diff --git a/docs/rules/0140/prepositions.md b/docs/rules/0140/prepositions.md
index a590fe5..9adebf3 100644
--- a/docs/rules/0140/prepositions.md
+++ b/docs/rules/0140/prepositions.md
@@ -20,6 +20,8 @@ words in the method's name:
 
 {% include prepositions.md %}
 
+**Note:** The standard fields `order_by` and `group_by` are permitted.
+
 ## Examples
 
 **Incorrect** code for this rule:
diff --git a/rules/aip0140/prepositions.go b/rules/aip0140/prepositions.go
index 9aa1b57..636b3fe 100644
--- a/rules/aip0140/prepositions.go
+++ b/rules/aip0140/prepositions.go
@@ -18,6 +18,7 @@ import (
 	"fmt"
 	"strings"
 
+	"bitbucket.org/creachadair/stringset"
 	"github.com/googleapis/api-linter/lint"
 	"github.com/googleapis/api-linter/locations"
 	"github.com/googleapis/api-linter/rules/internal/data"
@@ -26,6 +27,9 @@ import (
 
 var noPrepositions = &lint.FieldRule{
 	Name: lint.NewRuleName(140, "prepositions"),
+	OnlyIf: func(f *desc.FieldDescriptor) bool {
+		return !stringset.New("order_by", "group_by").Contains(f.GetName())
+	},
 	LintField: func(f *desc.FieldDescriptor) (problems []lint.Problem) {
 		for _, word := range strings.Split(f.GetName(), "_") {
 			if data.Prepositions.Contains(word) {


Test patch:
diff --git a/rules/aip0140/prepositions_test.go b/rules/aip0140/prepositions_test.go
index f1455e6..b86a4bf 100644
--- a/rules/aip0140/prepositions_test.go
+++ b/rules/aip0140/prepositions_test.go
@@ -28,6 +28,8 @@ func TestNoPrepositions(t *testing.T) {
 		{"author", testutils.Problems{}},
 		{"written_by", testutils.Problems{{Message: "by"}}},
 		{"move_toward_shelf_at_front", testutils.Problems{{Message: "toward"}, {Message: "at"}}},
+		{"order_by", testutils.Problems{}},
+		{"group_by", testutils.Problems{}},
 	}
 	for _, test := range tests {
 		t.Run(test.Name, func(t *testing.T) {