From c68ad5c6675246dc6a8ab793ab6f2cdcdc540772 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Fri, 12 Jun 2026 01:14:11 +0200 Subject: [PATCH 1/2] Add Fern SDK generator scaffold Add a fern/ directory that configures Fern-based SDK generation: - fern.config.json with the Castle organization and CLI version. - generators.yml defining a ruby-sdk group that runs the fernapi/fern-ruby-sdk generator against the OpenAPI spec, writing output to ../generated/ruby. - openapi/openapi.yml, the OpenAPI spec covering the scoring, Lists, Privacy and Events endpoints. - README.md documenting the layout and the fern check / fern generate workflow. Generated SDK output goes to ../generated/ruby and is not committed. --- fern/README.md | 35 ++++++ fern/fern.config.json | 4 + fern/generators.yml | 13 +++ fern/openapi/openapi.yml | 240 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 fern/README.md create mode 100644 fern/fern.config.json create mode 100644 fern/generators.yml create mode 100644 fern/openapi/openapi.yml diff --git a/fern/README.md b/fern/README.md new file mode 100644 index 0000000..62cc72f --- /dev/null +++ b/fern/README.md @@ -0,0 +1,35 @@ +# Fern SDK generator scaffold (proposal) + +This directory is a **proposal** for generating the Castle Ruby SDK from a shared +OpenAPI spec using [Fern](https://buildwithfern.com/). + +## Layout + +- `fern.config.json` — Fern CLI configuration (organization and CLI version). +- `generators.yml` — generator definitions; defines the `ruby-sdk` group that + runs the `fernapi/fern-ruby-sdk` generator against the spec. +- `openapi/openapi.yml` — the OpenAPI spec describing the Castle API + (scoring, Lists, Privacy and Events endpoints). + +## Usage + +Install the Fern CLI: + +```bash +npm install -g fern-api +``` + +Validate the spec and configuration: + +```bash +fern check +``` + +Generate the Ruby SDK locally: + +```bash +fern generate --group ruby-sdk --local +``` + +Generated output is written to `../generated/ruby` and is **not** committed to +this repository. diff --git a/fern/fern.config.json b/fern/fern.config.json new file mode 100644 index 0000000..460b099 --- /dev/null +++ b/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "castle", + "version": "5.47.1" +} diff --git a/fern/generators.yml b/fern/generators.yml new file mode 100644 index 0000000..353b291 --- /dev/null +++ b/fern/generators.yml @@ -0,0 +1,13 @@ +api: + specs: + - openapi: ./openapi/openapi.yml +groups: + ruby-sdk: + generators: + - name: fernapi/fern-ruby-sdk + version: 1.13.1 + output: + location: local-file-system + path: ../generated/ruby + github: + repository: castle/castle-ruby diff --git a/fern/openapi/openapi.yml b/fern/openapi/openapi.yml new file mode 100644 index 0000000..05fd9f0 --- /dev/null +++ b/fern/openapi/openapi.yml @@ -0,0 +1,240 @@ +openapi: 3.0.3 +info: + title: Castle API + version: "1.0.0" + description: > + Server-side Castle API covering the scoring endpoints (risk, filter, log), + the Lists and Privacy management endpoints, and the Events API. This + specification is the input for Fern SDK generation. + license: + name: MIT + url: https://opensource.org/licenses/MIT +servers: + - url: https://api.castle.io/v1 +security: + - apiSecret: [] +tags: + - name: Scoring + - name: Lists + - name: Privacy + - name: Events +paths: + /risk: + post: + operationId: risk + tags: [Scoring] + summary: Evaluate the risk of an authenticated event. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ScoringRequest" + responses: + "200": + description: Verdict for the evaluated event. + content: + application/json: + schema: + $ref: "#/components/schemas/Verdict" + /filter: + post: + operationId: filter + tags: [Scoring] + summary: Evaluate the risk of an unauthenticated event. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ScoringRequest" + responses: + "200": + description: Verdict for the evaluated event. + content: + application/json: + schema: + $ref: "#/components/schemas/Verdict" + /log: + post: + operationId: log + tags: [Scoring] + summary: Log an event without scoring it. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ScoringRequest" + responses: + "200": + description: The logged event was accepted. + content: + application/json: + schema: + type: object + /lists: + get: + operationId: listAllLists + tags: [Lists] + summary: Return all lists. + responses: + "200": + description: The available lists. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/List" + post: + operationId: createList + tags: [Lists] + summary: Create a list. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ListRequest" + responses: + "201": + description: The created list. + content: + application/json: + schema: + $ref: "#/components/schemas/List" + /privacy/users: + post: + operationId: requestUserData + tags: [Privacy] + summary: Request a data export for a user. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PrivacyRequest" + responses: + "200": + description: The privacy request was accepted. + content: + application/json: + schema: + type: object + delete: + operationId: deleteUserData + tags: [Privacy] + summary: Request deletion of a user's data. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PrivacyRequest" + responses: + "200": + description: The deletion request was accepted. + content: + application/json: + schema: + type: object + /events/schema: + get: + operationId: eventsSchema + tags: [Events] + summary: Return the event schema for the account. + responses: + "200": + description: The event schema. + content: + application/json: + schema: + type: object +components: + securitySchemes: + apiSecret: + type: http + scheme: basic + description: HTTP Basic auth with the API secret as the username and an empty password. + schemas: + ScoringRequest: + type: object + required: [type] + properties: + type: + type: string + example: "$login" + status: + type: string + example: "$succeeded" + request_token: + type: string + user: + $ref: "#/components/schemas/User" + properties: + type: object + additionalProperties: true + context: + type: object + additionalProperties: true + User: + type: object + properties: + id: + type: string + email: + type: string + name: + type: string + traits: + type: object + additionalProperties: true + Verdict: + type: object + properties: + risk: + type: number + format: double + policy: + $ref: "#/components/schemas/Policy" + signals: + type: object + additionalProperties: true + failover: + type: boolean + failover_reason: + type: string + Policy: + type: object + properties: + action: + type: string + enum: [allow, challenge, deny] + name: + type: string + id: + type: string + List: + type: object + properties: + id: + type: string + name: + type: string + color: + type: string + ListRequest: + type: object + required: [name] + properties: + name: + type: string + color: + type: string + PrivacyRequest: + type: object + required: [user_id] + properties: + user_id: + type: string From 855a8532482b9e4f5fa56a0f43f319fe09979a08 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Fri, 12 Jun 2026 01:14:43 +0200 Subject: [PATCH 2/2] Modernize the CI test matrix Add a Ruby 3.1 (Rails 7.0) entry to the Specs workflow matrix so the test matrix now covers Ruby 3.1, 3.2, 3.3 and 3.4 across the existing Rails gemfiles. --- .github/workflows/specs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/specs.yml b/.github/workflows/specs.yml index 3289034..f001bb1 100644 --- a/.github/workflows/specs.yml +++ b/.github/workflows/specs.yml @@ -13,6 +13,8 @@ jobs: fail-fast: false matrix: include: + - ruby: '3.1' + rails: '7.0' - ruby: '3.2' rails: '7.0' - ruby: '3.2'