From 0d488ddda3eaa376a405c3ff8ffdeb9c1c877266 Mon Sep 17 00:00:00 2001 From: Chidimj <165854539+Chidimj@users.noreply.github.com> Date: Wed, 29 Jul 2026 01:22:39 +0100 Subject: [PATCH] infra: wire security gate into CI and sync API docs - Run npm run verify-security as part of the Security Checks workflow so a misconfigured security setup fails CI instead of only being caught manually. - Add explicit GitHub Security Advisories reporting instructions to SECURITY.md. - Add missing stream lifecycle endpoints (summary, pause, resume, withdraw, cancel, top-up) to the Postman collection and document the Swagger spec as the source of truth in docs/api/README.md. Closes #1059 Closes #1061 Closes #1062 --- .github/workflows/security.yml | 3 + SECURITY.md | 12 ++- docs/api/README.md | 11 +++ docs/api/flowfi.postman_collection.json | 100 ++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 docs/api/README.md diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 5f48309b..211ef770 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -41,6 +41,9 @@ jobs: - name: Check for known vulnerabilities in backend (production dependencies) run: npm audit --workspace=backend --omit=dev --audit-level=critical + - name: Verify security setup + run: npm run verify-security + codeql-analysis: name: CodeQL Analysis runs-on: ubuntu-latest diff --git a/SECURITY.md b/SECURITY.md index e45ccc48..7db9a99b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -17,11 +17,15 @@ We take the security of FlowFi seriously. If you discover a security vulnerabili **Please do not report security vulnerabilities through public GitHub issues.** -Instead, please report security vulnerabilities by: +The preferred and fastest way to report a vulnerability is **GitHub Security Advisories**: -1. **Email**: Send details to `security@flowfi.dev` (if available) or create a private security advisory on GitHub -2. **GitHub Security Advisory**: Use GitHub's [private vulnerability reporting](https://github.com/LabsCrypt/flowfi/security/advisories/new) feature -3. **Direct Contact**: Reach out to the maintainers directly through GitHub +1. Go to the [Security tab](https://github.com/LabsCrypt/flowfi/security) of this repository. +2. Click **"Report a vulnerability"** (or use the direct link: [Report a vulnerability](https://github.com/LabsCrypt/flowfi/security/advisories/new)). +3. Fill in the private advisory form with as much detail as possible (see "What to Include" below). + +This opens a private channel between you and the maintainers — nothing is visible publicly until we agree on a disclosure timeline. + +If you cannot use GitHub Security Advisories for any reason, you may instead reach out to the maintainers directly through the [community Telegram](https://t.me/+DOylgFv1jyJlNzM0) and request a private contact, or send a message via GitHub Discussions asking to be contacted privately (do not include vulnerability details in the public message). ### What to Include diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 00000000..cc4720ad --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,11 @@ +# API Collections + +This directory contains hand-maintained Postman/Hoppscotch collections for exploring the FlowFi API. + +**Source of truth:** [`backend/src/config/swagger.ts`](../../backend/src/config/swagger.ts) and the `@openapi` JSDoc annotations on each route. The generated spec is served live at `http://localhost:3001/api-docs` (UI) and `http://localhost:3001/api-docs.json` (raw OpenAPI JSON). + +`flowfi.postman_collection.json` and `flowfi.hoppscotch_collection.json` are convenience collections for manual testing — they are not generated from the OpenAPI spec and can drift. When routes change: + +1. Update the `@openapi` annotations on the affected route/controller first. +2. Re-check the endpoints in this directory's collections against `http://localhost:3001/api-docs.json` and update paths, methods, and bodies to match. +3. If a collection and the Swagger spec ever disagree, the Swagger spec wins. diff --git a/docs/api/flowfi.postman_collection.json b/docs/api/flowfi.postman_collection.json index 6a180da1..15cfdff0 100644 --- a/docs/api/flowfi.postman_collection.json +++ b/docs/api/flowfi.postman_collection.json @@ -240,6 +240,106 @@ "body": "{\n \"streamId\": 1,\n \"claimableAmount\": \"5000\",\n \"actionable\": true,\n \"calculatedAt\": \"2024-02-21T14:30:00.000Z\",\n \"cached\": false\n}" } ] + }, + { + "name": "Get user stream summary", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/streams/summary/{{senderPublicKey}}", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "summary", "{{senderPublicKey}}"] + }, + "description": "Get an aggregated stream summary for a Stellar public key." + }, + "response": [] + }, + { + "name": "Pause stream", + "request": { + "method": "POST", + "header": [ + { "key": "Authorization", "value": "Bearer {{authToken}}" } + ], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/pause", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "pause"] + }, + "description": "Pause an active stream. Only the sender can pause their own stream." + }, + "response": [] + }, + { + "name": "Resume stream", + "request": { + "method": "POST", + "header": [ + { "key": "Authorization", "value": "Bearer {{authToken}}" } + ], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/resume", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "resume"] + }, + "description": "Resume a paused stream. Only the sender can resume their own stream." + }, + "response": [] + }, + { + "name": "Withdraw from stream", + "request": { + "method": "POST", + "header": [ + { "key": "Authorization", "value": "Bearer {{authToken}}" } + ], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/withdraw", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "withdraw"] + }, + "description": "Withdraw the currently claimable amount. Only the recipient can withdraw." + }, + "response": [] + }, + { + "name": "Cancel stream", + "request": { + "method": "POST", + "header": [ + { "key": "Authorization", "value": "Bearer {{authToken}}" } + ], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/cancel", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "cancel"] + }, + "description": "Cancel an active stream. Only the original sender can cancel. Accrued tokens go to the recipient, remainder is refunded to the sender." + }, + "response": [] + }, + { + "name": "Top up stream", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" }, + { "key": "Authorization", "value": "Bearer {{authToken}}" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"amount\": \"5000\"\n}", + "options": { "raw": { "language": "json" } } + }, + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/top-up", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "top-up"] + }, + "description": "Add additional funds to an existing active stream. Only the original sender can top up." + }, + "response": [] } ] },