Note
ruleshttp is currently a beta-quality library.
ruleshttp wraps Go HTTP clients and enforces rules on outgoing HTTP requests and incoming responses using the Expr expression language. It is intended to be used in cases where scoped credentials are not sufficiently locked down.
GitHub's Personal Access Tokens (PATs) can be granted read and write permissions for pull requests which enables both approving and requesting changes. Perhaps you have a code review setup where approved PRs are automatically merged and you want some LLM to request changes but not approve PRs. PAT permissions alone cannot express that! With ruleshttp you can solve this with the following rules:
# rules.yaml
pre_request:
- name: allow-request-changes
match: 'Method == "POST" && Host == "api.github.com" && Path contains "/pulls/" && Path endsWith "/reviews"'
authorize: 'fromJSON(Body)["event"] == "REQUEST_CHANGES"'
pre_response:
- name: all-responses
match: ALL
authorize: ALLThe ruleshttp.New functions return a Go http.RoundTripper which can be used in an http.Client like so:
// Load the rules and create a http.RoundTripper/http.Client.Transport
transport, err := ruleshttp.NewFromFile("rules.yaml")
if err != nil {
log.Fatal(err)
}
// Using github.com/google/go-github/v84 as an example
client := github.NewClient(&http.Client{Transport: transport}).WithAuthToken(token)
_, _, err = client.PullRequests.CreateReview(ctx, owner, repo, number, &github.PullRequestReviewRequest{
Body: github.Ptr("An approval attempt that will be rejected by rules.yaml"),
Event: github.Ptr("APPROVE"),
})
if errors.Is(err, ruleshttp.ErrDenied) {
// request or response was rejected by rules
}Rules are defined in YAML and compiled at startup. Each rule has a match expression and an authorize expression. For each request or response, rules are evaluated in order: the first rule whose match expression is true and whose authorize expression is true allows the traffic. If no rule allows, the call is rejected.
Rules are an allowlist-only system. A request/response must be explicitly authorized to be allowed. An empty rules list denies all traffic.
Two hook points are supported:
pre_request— evaluated before the request is sent.pre_response— evaluated after the response is received. Has access to the original request viaRequest.
Note that if a request is allowed, a response can still be rejected. This is to support cases where you want to allow read-only requests but you may want to reject certain responses. A consequence of this decision is that responses always have to be explicitly allowed.