Skip to content

Commit e77be6c

Browse files
authored
Merge pull request #1063 from Chidimj/infra/security-ci-dependabot-docs-sync
infra: wire security gate into CI and sync API docs
2 parents c850b50 + 0d488dd commit e77be6c

4 files changed

Lines changed: 122 additions & 4 deletions

File tree

.github/workflows/security.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ jobs:
4141
- name: Check for known vulnerabilities in backend (production dependencies)
4242
run: npm audit --workspace=backend --omit=dev --audit-level=critical
4343

44+
- name: Verify security setup
45+
run: npm run verify-security
46+
4447
codeql-analysis:
4548
name: CodeQL Analysis
4649
runs-on: ubuntu-latest

SECURITY.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ We take the security of FlowFi seriously. If you discover a security vulnerabili
1717

1818
**Please do not report security vulnerabilities through public GitHub issues.**
1919

20-
Instead, please report security vulnerabilities by:
20+
The preferred and fastest way to report a vulnerability is **GitHub Security Advisories**:
2121

22-
1. **Email**: Send details to `security@flowfi.dev` (if available) or create a private security advisory on GitHub
23-
2. **GitHub Security Advisory**: Use GitHub's [private vulnerability reporting](https://github.com/LabsCrypt/flowfi/security/advisories/new) feature
24-
3. **Direct Contact**: Reach out to the maintainers directly through GitHub
22+
1. Go to the [Security tab](https://github.com/LabsCrypt/flowfi/security) of this repository.
23+
2. Click **"Report a vulnerability"** (or use the direct link: [Report a vulnerability](https://github.com/LabsCrypt/flowfi/security/advisories/new)).
24+
3. Fill in the private advisory form with as much detail as possible (see "What to Include" below).
25+
26+
This opens a private channel between you and the maintainers — nothing is visible publicly until we agree on a disclosure timeline.
27+
28+
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).
2529

2630
### What to Include
2731

docs/api/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# API Collections
2+
3+
This directory contains hand-maintained Postman/Hoppscotch collections for exploring the FlowFi API.
4+
5+
**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).
6+
7+
`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:
8+
9+
1. Update the `@openapi` annotations on the affected route/controller first.
10+
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.
11+
3. If a collection and the Swagger spec ever disagree, the Swagger spec wins.

docs/api/flowfi.postman_collection.json

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,106 @@
240240
"body": "{\n \"streamId\": 1,\n \"claimableAmount\": \"5000\",\n \"actionable\": true,\n \"calculatedAt\": \"2024-02-21T14:30:00.000Z\",\n \"cached\": false\n}"
241241
}
242242
]
243+
},
244+
{
245+
"name": "Get user stream summary",
246+
"request": {
247+
"method": "GET",
248+
"header": [],
249+
"url": {
250+
"raw": "{{baseUrl}}/v1/streams/summary/{{senderPublicKey}}",
251+
"host": ["{{baseUrl}}"],
252+
"path": ["v1", "streams", "summary", "{{senderPublicKey}}"]
253+
},
254+
"description": "Get an aggregated stream summary for a Stellar public key."
255+
},
256+
"response": []
257+
},
258+
{
259+
"name": "Pause stream",
260+
"request": {
261+
"method": "POST",
262+
"header": [
263+
{ "key": "Authorization", "value": "Bearer {{authToken}}" }
264+
],
265+
"url": {
266+
"raw": "{{baseUrl}}/v1/streams/{{streamId}}/pause",
267+
"host": ["{{baseUrl}}"],
268+
"path": ["v1", "streams", "{{streamId}}", "pause"]
269+
},
270+
"description": "Pause an active stream. Only the sender can pause their own stream."
271+
},
272+
"response": []
273+
},
274+
{
275+
"name": "Resume stream",
276+
"request": {
277+
"method": "POST",
278+
"header": [
279+
{ "key": "Authorization", "value": "Bearer {{authToken}}" }
280+
],
281+
"url": {
282+
"raw": "{{baseUrl}}/v1/streams/{{streamId}}/resume",
283+
"host": ["{{baseUrl}}"],
284+
"path": ["v1", "streams", "{{streamId}}", "resume"]
285+
},
286+
"description": "Resume a paused stream. Only the sender can resume their own stream."
287+
},
288+
"response": []
289+
},
290+
{
291+
"name": "Withdraw from stream",
292+
"request": {
293+
"method": "POST",
294+
"header": [
295+
{ "key": "Authorization", "value": "Bearer {{authToken}}" }
296+
],
297+
"url": {
298+
"raw": "{{baseUrl}}/v1/streams/{{streamId}}/withdraw",
299+
"host": ["{{baseUrl}}"],
300+
"path": ["v1", "streams", "{{streamId}}", "withdraw"]
301+
},
302+
"description": "Withdraw the currently claimable amount. Only the recipient can withdraw."
303+
},
304+
"response": []
305+
},
306+
{
307+
"name": "Cancel stream",
308+
"request": {
309+
"method": "POST",
310+
"header": [
311+
{ "key": "Authorization", "value": "Bearer {{authToken}}" }
312+
],
313+
"url": {
314+
"raw": "{{baseUrl}}/v1/streams/{{streamId}}/cancel",
315+
"host": ["{{baseUrl}}"],
316+
"path": ["v1", "streams", "{{streamId}}", "cancel"]
317+
},
318+
"description": "Cancel an active stream. Only the original sender can cancel. Accrued tokens go to the recipient, remainder is refunded to the sender."
319+
},
320+
"response": []
321+
},
322+
{
323+
"name": "Top up stream",
324+
"request": {
325+
"method": "POST",
326+
"header": [
327+
{ "key": "Content-Type", "value": "application/json" },
328+
{ "key": "Authorization", "value": "Bearer {{authToken}}" }
329+
],
330+
"body": {
331+
"mode": "raw",
332+
"raw": "{\n \"amount\": \"5000\"\n}",
333+
"options": { "raw": { "language": "json" } }
334+
},
335+
"url": {
336+
"raw": "{{baseUrl}}/v1/streams/{{streamId}}/top-up",
337+
"host": ["{{baseUrl}}"],
338+
"path": ["v1", "streams", "{{streamId}}", "top-up"]
339+
},
340+
"description": "Add additional funds to an existing active stream. Only the original sender can top up."
341+
},
342+
"response": []
243343
}
244344
]
245345
},

0 commit comments

Comments
 (0)