STF-1794: Add OpenAPI specs for the web services - #1
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Important Review skippedWe couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting You can disable this status message by setting the Use the checkbox below for a quick retry:
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Free Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (42)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe repository adds OpenAPI specifications and bundled documents for GeoIP, minFraud, downloads, license-key validation, and privacy exclusions. It also adds reusable schemas, examples, Go access to bundled YAML, and repository tooling for development, linting, and CI. ChangesOpenAPI service catalog
Estimated code review effort: 4 (Complex) | ~60 minutes A rabbit hops through YAML rows Comment |
STF-1794 MaxMind public web services have published OpenAPI specs
External users have no machine-readable description of the MaxMind public web services. This issue tracks OpenAPI 3.1 specs for those services in the new private repo https://github.com/maxmind/openapi, plus tests that check the specs against the implementation in mm_website. Scope
The legacy text APIs, device tracking, and the browser JavaScript client are out of scope. Plan
Related fixes
Acceptance criteria
STF-1823 Audit and enforce public API request limits
The OpenAPI review identified input fields without documented or enforced ScopeAudit request bodies, query parameters, path parameters, and headers consumed Cover string lengths, collection sizes, map keys, numeric ranges, and whole Acceptance criteria
Related work
|
9c25c56 to
4338746
Compare
Describe the GeoIP Country, City Plus, and Insights web services and the GeoLite Country and City services in OpenAPI 3.1. The schemas, descriptions, and examples follow the developer documentation. CI lints the specs with Redocly, which also checks each example against its schema, and checks that the committed bundle is current. The Go package embeds the bundles so services can validate their responses against them in tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4338746 to
2f7f8e1
Compare
horgh
left a comment
There was a problem hiding this comment.
Seems good. I mostly skimmed it. I had Claude check it in a couple ways so there are a bunch of comments from it.
| `<edition_id>_[<artifact_type>_]<YYYYMMDD>.<suffix>`. | ||
| schema: | ||
| type: string | ||
| Content-Type: |
There was a problem hiding this comment.
OpenAPI 3.1 says that a Content-Type entry under response headers SHALL be ignored. Thus this response does not describe the file media type. Tools that check media types can flag a HEAD response with Content-Type: application/gzip as undocumented.
Suggestion: remove this header entry. Declare content with the media types and no schema. The download worker sends application/gzip, application/zip, text/csv and, for the md5 and sha256 suffixes, text/plain. For example:
content:
application/gzip: {}
application/zip: {}
text/csv: {}
text/plain: {}🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Removed the ignored Content-Type response-header entry. I kept HEAD bodyless rather than adding content, which describes response payload media types; the GET response already declares the download media types.
Commits: 5129765.
🤖 Response by Codex on behalf of Greg.
| field that MaxMind does not recognize produces an `INPUT_UNKNOWN` warning. | ||
|
|
||
|
|
||
| A string field allows up to 255 valid Unicode characters unless its schema |
There was a problem hiding this comment.
This text says that the 255-character limit applies "unless its schema states a shorter limit". But device.user_agent allows 512 characters and order.referrer_uri allows 1024. A client author who follows this text can truncate valid input.
Suggestion: change "shorter" to "different".
🤖 Comment by Claude (Claude Code) on behalf of Will.
| schema: | ||
| $ref: "../components/errors.yaml#/schemas/Error" | ||
| example: | ||
| code: ACCOUNT_ID_REQUIRED |
There was a problem hiding this comment.
This example pairs code: ACCOUNT_ID_REQUIRED with the message "An account ID and license key are required to use this service." A request with no credentials to the live geofeed endpoint returns this message with AUTHORIZATION_INVALID:
{"code":"AUTHORIZATION_INVALID","error":"An account ID and license key are required to use this service."}The same mismatch is in specs/privacy-exclusions.yaml:176. A client coded from the example can branch on the wrong code for the no-credentials case. Suggestion: change the example code to AUTHORIZATION_INVALID.
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Keeping this example: the service uses that same message for both AUTHORIZATION_INVALID and ACCOUNT_ID_REQUIRED. Missing credentials and a Basic header with an empty account ID take different paths (go/pkg/webservice/authutil.go and wserrors/error.go). This is an example of the missing-account response, not a promise that every request without credentials returns this code.
🤖 Response by Codex on behalf of Greg.
| email: | ||
| domain: | ||
| classification: business | ||
| first_seen: "2015-01-20" |
There was a problem hiding this comment.
first_seen: "2015-01-20" is earlier than the earliest possible date that EmailDomain.first_seen documents (2019-01-01). The same value is in examples/minfraud/factors.yaml:181.
Suggestion: use a date on or after 2019-01-01.
🤖 Comment by Claude (Claude Code) on behalf of Will.
| disposition: | ||
| action: accept | ||
| reason: default | ||
| rule_label: my_custom_rule |
There was a problem hiding this comment.
This example pairs reason: default with rule_label: my_custom_rule. The schema says that rule_label is absent when no rule was triggered, and default means that no custom rule matched. The same pair is in examples/minfraud/insights.yaml:6 and examples/minfraud/factors.yaml:6.
Suggestion: remove rule_label, or change reason to custom_rule.
🤖 Comment by Claude (Claude Code) on behalf of Will.
| phone_country_code: | ||
| type: string | ||
| pattern: "^[0-9]{1,4}$" | ||
| description: The international calling code for the phone number. |
There was a problem hiding this comment.
Dev-site now says "Use digits only; do not include a leading +." for this field, and for credit_card.bank_phone_country_code at line 513. The pattern already enforces it, but the description should say it.
Suggestion: append that sentence to both descriptions.
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Leaving this optional prose addition out of the current changes. Both schema patterns already require digits only and reject a leading +, so validators enforce the documented rule.
🤖 Response by Codex on behalf of Greg.
| description: >- | ||
| The request body is too large. The response does not have a JSON body. | ||
| InternalServerError: | ||
| description: >- |
There was a problem hiding this comment.
Dev-site says "In both cases, you can try the request again later." for 500 and 503. The spec says "Send the request again later." only on the 503.
Suggestion: add the same sentence here.
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Leaving the additional retry guidance out of this PR. The 500 response does not prohibit retrying; adding the sentence would be a documentation enhancement rather than a contract correction.
🤖 Response by Codex on behalf of Greg.
| format: date-time | ||
| description: >- | ||
| The time the event occurred, in RFC 3339 format. If you omit this | ||
| field, MaxMind uses the time it receives the request. Do not send this |
There was a problem hiding this comment.
This says "Do not send this field for a live transaction." Dev-site says "It is not recommended to use this input when scoring live transactions as they occur."
Suggestion: "MaxMind does not recommend this field for a live transaction."
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Rephrased as a recommendation rather than a prohibition.
Commits: adf0dca.
🤖 Response by Codex on behalf of Greg.
| value: 2001:db8::1:0:0:1 | ||
| me: | ||
| value: me | ||
| Pretty: |
There was a problem hiding this comment.
The dev-site curl examples send ?pretty with no value. This parameter has a string schema, so a generated client sends ?pretty=.
Suggestion: add allowEmptyValue: true.
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Keeping this as-is: ?pretty= is accepted, so the generated-client form is valid. allowEmptyValue is not needed to force the bare ?pretty spelling, and callers do not need that exact spelling to enable pretty output.
🤖 Response by Codex on behalf of Greg.
| headers: | ||
| WWW-Authenticate: | ||
| description: >- | ||
| The authentication scheme, for example `Basic realm="minfraud"`. |
There was a problem hiding this comment.
This shared Unauthorized response is also used by the Dispositions endpoint at line 255. Dev-site says the Dispositions realm is minfraud-disposition, not minfraud.
Suggestion: give Dispositions its own Unauthorized response, or name both realms in this description.
🤖 Comment by Claude (Claude Code) on behalf of Will.
There was a problem hiding this comment.
Replaced the specific realm with a generic HTTP Basic challenge description. The shared response no longer claims that Dispositions uses the scoring service’s realm.
Commits: bfbdc68.
🤖 Response by Codex on behalf of Greg.
Describe the minFraud Score, Insights, and Factors endpoints, the Report Transaction and Dispositions APIs, and the minFraud Alerts webhook in OpenAPI 3.1. The schemas, descriptions, and examples follow the developer documentation. The Insights and Factors ip_address object reuses the GeoIP record schemas instead of duplicating them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Describe the Privacy Exclusions API, the License Key Validation API, and the database and geofeed report downloads in OpenAPI 3.1. A successful download is a redirect, so Redocly's rule that requires a 2xx response is off for the downloads spec only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2f7f8e1 to
4c64034
Compare
This reverts commit f6a8da5. SERVICE_INVALID is returned for unsupported services and is now being documented on the dev site.
Part of STF-1794.
This adds OpenAPI 3.1 specs for the MaxMind public web services, and the tooling to lint, bundle, and publish them. Review it one commit at a time: there is one commit for each group of specs.
Specs
geoip.yamlminfraud.yamlprivacy-exclusions.yamlGET /privacy/exclusionslicense-key-validation.yamlPOST /secrets/validate-license-keydownloads.yamlConventions
Tooling
bundled/matches the sources, and zizmor checks the workflows.🤖 Generated with Claude Code
Summary by CodeRabbit