From 2eb36d8ea82ae2eee0d2b5812e9ee3cb0af716c4 Mon Sep 17 00:00:00 2001 From: dergigi Date: Sat, 8 Aug 2026 17:25:12 +0200 Subject: [PATCH] feat: add security grant focus --- .../steps/ProjectDetails.tsx | 1 + pages/api/github.ts | 51 ++++--------------- .../opensats-grant-application-template.md | 2 +- utils/application-routing.test.js | 38 ++++++++++++++ utils/application-routing.ts | 41 +++++++++++++++ 5 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 utils/application-routing.test.js create mode 100644 utils/application-routing.ts diff --git a/components/grant-application/steps/ProjectDetails.tsx b/components/grant-application/steps/ProjectDetails.tsx index 96690696a..1595d6d6a 100644 --- a/components/grant-application/steps/ProjectDetails.tsx +++ b/components/grant-application/steps/ProjectDetails.tsx @@ -19,6 +19,7 @@ export default function ProjectDetails({ register, watch, errors }: StepProps) { + diff --git a/pages/api/github.ts b/pages/api/github.ts index 481124b16..f29b819a2 100644 --- a/pages/api/github.ts +++ b/pages/api/github.ts @@ -1,4 +1,9 @@ import { NextApiRequest, NextApiResponse } from 'next/types' +import { + getApplicationIssueLabels, + getApplicationRepo, + normalizeMainFocus, +} from '../../utils/application-routing' const GH_ACCESS_TOKEN = process.env.GH_ACCESS_TOKEN const GH_ORG = process.env.GH_ORG @@ -134,48 +139,10 @@ ${req.body.video_application ? req.body.video_application : 'None provided.'} ${req.body.anything_else ? req.body.anything_else : 'No.'} ${contactFooter}` - // Label set according to "main focus" (absent for RED applications) - const mainFocus = req.body.main_focus - ? `${req.body.main_focus}`.toLowerCase() - : '' - const issueLabels = mainFocus ? [mainFocus] : [] - if (mainFocus === 'layer1' || mainFocus === 'layer2') { - issueLabels.push('bitcoin') // L1 & L2 = subset of Bitcoin - } - - // Add label for applications from common grant app - if (req.body.source === 'common-grant-app') { - issueLabels.push('common-grant-app') - } - - // Repo set according to "main focus" - let appRepo = GH_APP_REPO - if (mainFocus === 'nostr') { - appRepo = `${GH_APP_REPO}-nostr` - } - if (mainFocus === 'layer1') { - appRepo = `${GH_APP_REPO}-layer1` - } - if (mainFocus === 'layer2') { - appRepo = `${GH_APP_REPO}-layer2` - } - if (mainFocus === 'core') { - appRepo = `${GH_APP_REPO}-core` - } - if (mainFocus === 'ecash') { - appRepo = `${GH_APP_REPO}-ecash` - } - - // Tag depending on request for grant and/or request for listing - req.body.LTS && issueLabels.push('LTS') - req.body.RED && issueLabels.push('RED') - - // Additional tags based on yes/no answers - req.body.has_received_funding === 'yes' && issueLabels.push('prior funding') - if (!req.body.RED) { - !req.body.free_open_source && issueLabels.push('not FLOSS') - !req.body.are_you_lead && issueLabels.push('surrogate') - } + // Labels and repo are set according to main focus. + const mainFocus = normalizeMainFocus(req.body.main_focus) + const issueLabels = getApplicationIssueLabels(req.body) + const appRepo = getApplicationRepo(GH_APP_REPO, mainFocus) try { await octokit.rest.issues.create({ diff --git a/public/static/opensats-grant-application-template.md b/public/static/opensats-grant-application-template.md index 74440bfc8..a8b180e49 100644 --- a/public/static/opensats-grant-application-template.md +++ b/public/static/opensats-grant-application-template.md @@ -9,7 +9,7 @@ application at https://opensats.org/apply/grant **Project Name:** -**Main Focus:** (Bitcoin, Nostr, Layer 1, Layer 2, Core, Ecash, Education, Other) +**Main Focus:** (Bitcoin, Nostr, Layer 1, Layer 2, Core, Ecash, Education, Security, Other) ### Project Description diff --git a/utils/application-routing.test.js b/utils/application-routing.test.js new file mode 100644 index 000000000..b86ee4543 --- /dev/null +++ b/utils/application-routing.test.js @@ -0,0 +1,38 @@ +/** @jest-environment node */ +/* eslint-env jest, node */ + +const { + getApplicationIssueLabels, + getApplicationRepo, + normalizeMainFocus, +} = require('./application-routing.ts') + +describe('application routing', () => { + it('normalizes main focus values', () => { + expect(normalizeMainFocus('Security')).toBe('security') + expect(normalizeMainFocus(undefined)).toBe('') + }) + + it('labels regular security grant applications', () => { + expect( + getApplicationIssueLabels({ + main_focus: 'security', + free_open_source: true, + are_you_lead: true, + }) + ).toEqual(['security']) + }) + + it('keeps security applications in the default applications repo', () => { + expect(getApplicationRepo('applications', 'security')).toBe('applications') + }) + + it('routes known focus-specific applications to their repos', () => { + expect(getApplicationRepo('applications', 'layer1')).toBe( + 'applications-layer1' + ) + expect(getApplicationIssueLabels({ main_focus: 'layer2' })).toContain( + 'bitcoin' + ) + }) +}) diff --git a/utils/application-routing.ts b/utils/application-routing.ts new file mode 100644 index 000000000..0e845d01d --- /dev/null +++ b/utils/application-routing.ts @@ -0,0 +1,41 @@ +const REPO_SUFFIX_BY_MAIN_FOCUS: Record = { + core: '-core', + ecash: '-ecash', + layer1: '-layer1', + layer2: '-layer2', + nostr: '-nostr', +} + +export function normalizeMainFocus(mainFocus: unknown) { + return mainFocus ? `${mainFocus}`.toLowerCase() : '' +} + +export function getApplicationRepo(baseRepo: string, mainFocus: unknown) { + return `${baseRepo}${ + REPO_SUFFIX_BY_MAIN_FOCUS[normalizeMainFocus(mainFocus)] || '' + }` +} + +export function getApplicationIssueLabels(body: Record) { + const mainFocus = normalizeMainFocus(body.main_focus) + const issueLabels = mainFocus ? [mainFocus] : [] + + if (mainFocus === 'layer1' || mainFocus === 'layer2') { + issueLabels.push('bitcoin') + } + + if (body.source === 'common-grant-app') { + issueLabels.push('common-grant-app') + } + + if (body.LTS) issueLabels.push('LTS') + if (body.RED) issueLabels.push('RED') + if (body.has_received_funding === 'yes') issueLabels.push('prior funding') + + if (!body.RED) { + if (!body.free_open_source) issueLabels.push('not FLOSS') + if (!body.are_you_lead) issueLabels.push('surrogate') + } + + return issueLabels +}