Skip to content

argemma-oss/ruleshttp

Repository files navigation

ruleshttp

CI Go Reference

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.

Example integration

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: ALL

The 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
}

How it works

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 via Request.

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.

Additional Docs

About

Go library for allowlisting specific shapes HTTP requests

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages