diff --git a/frontend/__tests__/e2e/pages/About.spec.ts b/frontend/__tests__/e2e/pages/About.spec.ts
index 5729ce076..8322ca997 100644
--- a/frontend/__tests__/e2e/pages/About.spec.ts
+++ b/frontend/__tests__/e2e/pages/About.spec.ts
@@ -36,7 +36,7 @@ test.describe('About Page', () => {
test('renders main sections correctly', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'About' })).toBeVisible()
- await expect(page.getByRole('heading', { name: 'History' })).toBeVisible()
+ await expect(page.getByRole('heading', { name: 'Project History', exact: true })).toBeVisible()
await expect(page.getByRole('heading', { name: 'Leaders' })).toBeVisible()
await expect(page.getByRole('heading', { name: 'Roadmap' })).toBeVisible()
})
@@ -77,10 +77,10 @@ test.describe('About Page', () => {
})
test('displays animated counters with correct values', async ({ page }) => {
- await expect(page.getByText('1.2K+Contributors')).toBeVisible()
- await expect(page.getByText('40+Open Issues')).toBeVisible()
- await expect(page.getByText('60+Forks')).toBeVisible()
- await expect(page.getByText('890+Stars')).toBeVisible()
+ await expect(page.getByText('Contributors', { exact: true })).toBeVisible()
+ await expect(page.getByText('Open Issues', { exact: true })).toBeVisible()
+ await expect(page.getByText('Forks', { exact: true })).toBeVisible()
+ await expect(page.getByText('Stars', { exact: true })).toBeVisible()
})
test('opens user profile in new window when leader button is clicked', async ({ page }) => {
@@ -91,4 +91,14 @@ test.describe('About Page', () => {
test('breadcrumb renders correct segments on /about', async ({ page }) => {
await expectBreadCrumbsToBeVisible(page, ['Home', 'About'])
})
+
+ test('renders key features section', async ({ page }) => {
+ await expect(page.getByText('Key Features')).toBeVisible()
+ await expect(page.getByText('Advanced Search Capabilities')).toBeVisible()
+ })
+
+ test('renders project history timeline section', async ({ page }) => {
+ await expect(page.getByText('Project History')).toBeVisible()
+ await expect(page.getByText('Project Inception')).toBeVisible()
+ })
})
diff --git a/frontend/__tests__/unit/pages/About.test.tsx b/frontend/__tests__/unit/pages/About.test.tsx
index 679af79e6..e9b7776c2 100644
--- a/frontend/__tests__/unit/pages/About.test.tsx
+++ b/frontend/__tests__/unit/pages/About.test.tsx
@@ -35,6 +35,78 @@ jest.mock('utils/aboutData', () => ({
'This is a test paragraph about the project.',
'This is another paragraph about the project history.',
],
+ leaders: {
+ arkid15r: 'CCSP, CISSP, CSSLP',
+ kasya: 'CC',
+ mamicidal: 'CISSP',
+ },
+ missionContent: {
+ mission:
+ 'OWASP Nest is a comprehensive platform designed to empower developers, security professionals, and organizations in their journey toward building secure applications.',
+ whoItsFor:
+ 'OWASP Nest is designed for developers, security professionals, project leaders, and organizations looking to integrate security best practices into their development workflows.',
+ },
+ keyFeatures: [
+ {
+ title: 'Advanced Search Capabilities',
+ description:
+ 'Find OWASP projects, tools, and resources with precision using our intelligent search functionality.',
+ },
+ {
+ title: 'Slack Integration',
+ description: 'Stay connected with the OWASP community through seamless Slack integration.',
+ },
+ {
+ title: 'OWASP Chapters Proximity Page',
+ description:
+ 'Discover local OWASP chapters and events near you to engage with the community.',
+ },
+ {
+ title: 'AI-Generated Insights',
+ description:
+ 'Leverage AI-powered insights to better understand project relationships and recommendations.',
+ },
+ ],
+ getInvolvedContent: {
+ description:
+ 'OWASP Nest thrives thanks to community-driven contributions. Here are ways you can get involved:',
+ ways: [
+ 'Code Contributions – Fix bugs or build new features.',
+ 'Code Review – Improve quality by reviewing pull requests.',
+ 'Documentation – Help improve our guides and tutorials.',
+ 'Testing – Report bugs and help test new features.',
+ 'Community Engagement – Share your experiences and help others.',
+ ],
+ callToAction:
+ 'To get started, visit the OWASP Nest Repository, explore the Contributing Guidelines, and review the Code of Conduct.',
+ },
+ projectHistory: [
+ {
+ year: '2023',
+ title: 'Project Inception',
+ description: 'The project was started and initial planning began.',
+ },
+ {
+ year: '2023',
+ title: 'Backend MVP',
+ description: 'The backend MVP was released.',
+ },
+ {
+ year: '2024',
+ title: 'Frontend Development',
+ description: 'Frontend development kicked off.',
+ },
+ {
+ year: '2024',
+ title: 'Platform Integrations',
+ description: 'Integrated with several platforms.',
+ },
+ {
+ year: '2024',
+ title: 'GSoC Integration',
+ description: 'Google Summer of Code integration completed.',
+ },
+ ],
technologies: [
{
section: 'Backend',
@@ -43,6 +115,14 @@ jest.mock('utils/aboutData', () => ({
icon: '/images/icons/python.svg',
url: 'https://www.python.org/',
},
+ Django: {
+ icon: '/images/icons/django.svg',
+ url: 'https://www.djangoproject.com/',
+ },
+ PostgreSQL: {
+ icon: '/images/icons/postgresql.svg',
+ url: 'https://www.postgresql.org/',
+ },
},
},
{
@@ -52,6 +132,14 @@ jest.mock('utils/aboutData', () => ({
icon: '/images/icons/nextjs.svg',
url: 'https://nextjs.org/',
},
+ 'Tailwind CSS': {
+ icon: '/images/icons/tailwind.svg',
+ url: 'https://tailwindcss.com/',
+ },
+ Typescript: {
+ icon: '/images/icons/typescript.svg',
+ url: 'https://www.typescriptlang.org/',
+ },
},
},
{
@@ -65,6 +153,10 @@ jest.mock('utils/aboutData', () => ({
icon: '/images/icons/pytest.svg',
url: 'https://docs.pytest.org/',
},
+ PlayWright: {
+ icon: '/images/icons/playwright.svg',
+ url: 'https://playwright.dev/',
+ },
},
},
{
@@ -74,6 +166,10 @@ jest.mock('utils/aboutData', () => ({
icon: '/images/icons/ansible.svg',
url: 'https://www.ansible.com/',
},
+ Docker: {
+ icon: '/images/icons/docker.svg',
+ url: 'https://www.docker.com/',
+ },
GitHub: {
icon: '/images/icons/github.svg',
url: 'https://www.github.com/',
@@ -138,20 +234,70 @@ describe('About Component', () => {
jest.clearAllMocks()
})
- test('renders project history correctly', async () => {
+ test('renders mission and who its for sections correctly', async () => {
+ await act(async () => {
+ render()
+ })
+
+ const missionSection = screen.getByText('Mission').closest('div')
+ expect(missionSection).toBeInTheDocument()
+ expect(screen.getByText(/OWASP Nest is a comprehensive platform/)).toBeInTheDocument()
+
+ const whoItsForSection = screen.getByText("Who It's For").closest('div')
+ expect(whoItsForSection).toBeInTheDocument()
+ expect(screen.getByText(/OWASP Nest is designed for developers/)).toBeInTheDocument()
+ })
+
+ test('renders key features section correctly', async () => {
await act(async () => {
render()
})
- const historySection = screen.getByText('History').closest('div')
- expect(historySection).toBeInTheDocument()
+ const keyFeaturesSection = screen.getByText('Key Features').closest('div')
+ expect(keyFeaturesSection).toBeInTheDocument()
- const markdownContents = await screen.findAllByTestId('markdown-content')
- expect(markdownContents.length).toBe(2)
- expect(markdownContents[0].textContent).toBe('This is a test paragraph about the project.')
- expect(markdownContents[1].textContent).toBe(
- 'This is another paragraph about the project history.'
- )
+ expect(screen.getByText('Advanced Search Capabilities')).toBeInTheDocument()
+ expect(screen.getByText('Slack Integration')).toBeInTheDocument()
+ expect(screen.getByText('OWASP Chapters Proximity Page')).toBeInTheDocument()
+ expect(screen.getByText('AI-Generated Insights')).toBeInTheDocument()
+ })
+
+ test('renders get involved section correctly', async () => {
+ await act(async () => {
+ render()
+ })
+
+ const getInvolvedSection = screen.getByText('Get Involved').closest('div')
+ expect(getInvolvedSection).toBeInTheDocument()
+
+ expect(
+ screen.getByText(/OWASP Nest thrives thanks to community-driven contributions/)
+ ).toBeInTheDocument()
+ expect(
+ screen.getByText(/Code Contributions – Fix bugs or build new features/)
+ ).toBeInTheDocument()
+ expect(
+ screen.getByText(/Code Review – Improve quality by reviewing pull requests/)
+ ).toBeInTheDocument()
+ })
+
+ test('renders project history timeline correctly', async () => {
+ await act(async () => {
+ render()
+ })
+
+ const projectHistorySection = screen.getByText('Project History').closest('div')
+ expect(projectHistorySection).toBeInTheDocument()
+
+ expect(screen.getByText('Project Inception')).toBeInTheDocument()
+ expect(screen.getByText('Backend MVP')).toBeInTheDocument()
+ expect(screen.getByText('Frontend Development')).toBeInTheDocument()
+ expect(screen.getByText('Platform Integrations')).toBeInTheDocument()
+ expect(screen.getByText('GSoC Integration')).toBeInTheDocument()
+
+ // Check for year indicators
+ expect(screen.getAllByText('23')).toHaveLength(2) // 2023 entries
+ expect(screen.getAllByText('24')).toHaveLength(3) // 2024 entries
})
test('renders leaders section with three leaders', async () => {
@@ -576,4 +722,58 @@ describe('About Component', () => {
})
})
})
+
+ test('renders mission section', async () => {
+ await act(async () => {
+ render()
+ })
+ expect(screen.getByText('Mission')).toBeInTheDocument()
+ expect(screen.getByText(/empower developers, security professionals/)).toBeInTheDocument()
+ })
+
+ test("renders 'Who It's For' section", async () => {
+ await act(async () => {
+ render()
+ })
+ expect(screen.getByText("Who It's For")).toBeInTheDocument()
+ expect(
+ screen.getByText(/developers, security professionals, project leaders/)
+ ).toBeInTheDocument()
+ })
+
+ test('renders key features section', async () => {
+ await act(async () => {
+ render()
+ })
+ expect(screen.getByText('Key Features')).toBeInTheDocument()
+ expect(screen.getByText('Advanced Search Capabilities')).toBeInTheDocument()
+ expect(screen.getByText('Slack Integration')).toBeInTheDocument()
+ expect(screen.getByText('OWASP Chapters Proximity Page')).toBeInTheDocument()
+ expect(screen.getByText('AI-Generated Insights')).toBeInTheDocument()
+ })
+
+ test('renders get involved section', async () => {
+ await act(async () => {
+ render()
+ })
+ expect(screen.getByText('Get Involved')).toBeInTheDocument()
+ expect(screen.getByText(/community-driven contributions/)).toBeInTheDocument()
+ expect(screen.getByText(/Code Contributions/)).toBeInTheDocument()
+ expect(screen.getByText(/Code Review/)).toBeInTheDocument()
+ expect(screen.getByText(/Documentation/)).toBeInTheDocument()
+ expect(screen.getByText(/Testing/)).toBeInTheDocument()
+ expect(screen.getByText(/Community Engagement/)).toBeInTheDocument()
+ })
+
+ test('renders project history timeline section', async () => {
+ await act(async () => {
+ render()
+ })
+ expect(screen.getByText('Project History')).toBeInTheDocument()
+ expect(screen.getByText('Project Inception')).toBeInTheDocument()
+ expect(screen.getByText('Backend MVP')).toBeInTheDocument()
+ expect(screen.getByText('Frontend Development')).toBeInTheDocument()
+ expect(screen.getByText('Platform Integrations')).toBeInTheDocument()
+ expect(screen.getByText('GSoC Integration')).toBeInTheDocument()
+ })
})
diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx
index e9ffd2295..c423842bc 100644
--- a/frontend/src/app/about/page.tsx
+++ b/frontend/src/app/about/page.tsx
@@ -5,10 +5,14 @@ import {
faClock,
faUserGear,
faMapSigns,
- faScroll,
faUsers,
faTools,
faArrowUpRightFromSquare,
+ faBullseye,
+ faUserGroup,
+ faRocket,
+ faHandshake,
+ faHistory,
} from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { Tooltip } from '@heroui/tooltip'
@@ -23,7 +27,14 @@ import { GET_LEADER_DATA } from 'server/queries/userQueries'
import type { Contributor } from 'types/contributor'
import type { Project } from 'types/project'
import type { User } from 'types/user'
-import { aboutText, technologies } from 'utils/aboutData'
+import {
+ technologies,
+ leaders,
+ missionContent,
+ keyFeatures,
+ getInvolvedContent,
+ projectHistory,
+} from 'utils/aboutData'
import AnchorTitle from 'components/AnchorTitle'
import AnimatedCounter from 'components/AnimatedCounter'
import LoadingSpinner from 'components/LoadingSpinner'
@@ -32,11 +43,6 @@ import SecondaryCard from 'components/SecondaryCard'
import TopContributorsList from 'components/TopContributorsList'
import UserCard from 'components/UserCard'
-const leaders = {
- arkid15r: 'CCSP, CISSP, CSSLP',
- kasya: 'CC',
- mamicidal: 'CISSP',
-}
const projectKey = 'nest'
const About = () => {
@@ -101,16 +107,34 @@ const About = () => {
About
-
}>
- {aboutText.map((text) => (
-
-
-
+
+
+
}>
+
{missionContent.mission}
+
+
+
}>
+
{missionContent.whoItsFor}
+
+
+
+
}>
+
+ {keyFeatures.map((feature) => (
+
+
{feature.title}
+
+ {feature.description}
+
-
- ))}
+ ))}
+
+ {/* Leaders */}
}>
{Object.keys(leaders).map((username) => (
@@ -121,6 +145,7 @@ const About = () => {
+ {/* Top Contributors */}
{topContributors && (
{
/>
)}
+ {/* Technologies & Tools */}
}>
@@ -163,6 +189,7 @@ const About = () => {
+ {/* Roadmap */}
{projectMetadata.recentMilestones.length > 0 && (
}>
@@ -219,6 +246,53 @@ const About = () => {
)}
+ {/* Get Involved */}
+
}>
+
+
{getInvolvedContent.description}
+
+ {getInvolvedContent.ways.map((way, index) => (
+ -
+ •
+ {way}
+
+ ))}
+
+
+
+
+
+
+
+
}>
+
+
+
+
+ {projectHistory.map((milestone) => (
+
+
+
+ {milestone.year.slice(-2)}
+
+
+
+
+
{milestone.title}
+
+ {milestone.description}
+
+
+ {milestone.year}
+
+
+
+
+ ))}
+
+
+
+
{[
{ label: 'Forks', value: projectMetadata.forksCount },
diff --git a/frontend/src/types/about.ts b/frontend/src/types/about.ts
new file mode 100644
index 000000000..c3aedceb2
--- /dev/null
+++ b/frontend/src/types/about.ts
@@ -0,0 +1,35 @@
+export interface KeyFeature {
+ title: string
+ description: string
+}
+
+export interface ProjectHistory {
+ year: string
+ title: string
+ description: string
+}
+
+export interface GetInvolved {
+ description: string
+ ways: string[]
+ callToAction: string
+}
+
+export interface MissionContent {
+ mission: string
+ whoItsFor: string
+}
+
+export type Leaders = {
+ [key: string]: string
+}
+
+export type TechnologySection = {
+ section: string
+ tools: {
+ [toolName: string]: {
+ icon: string
+ url: string
+ }
+ }
+}
diff --git a/frontend/src/utils/aboutData.ts b/frontend/src/utils/aboutData.ts
index 1c51cb0c9..6e5d616c2 100644
--- a/frontend/src/utils/aboutData.ts
+++ b/frontend/src/utils/aboutData.ts
@@ -1,10 +1,99 @@
+import type {
+ KeyFeature,
+ ProjectHistory,
+ GetInvolved,
+ MissionContent,
+ Leaders,
+ TechnologySection,
+} from 'types/about'
+
export const aboutText = [
'OWASP Nest was originally created by Arkadii Yakovets (Ark) to simplify OWASP projects navigation. Built from scratch based on Ark’s vision and discussions with Starr Brown (Starr), the platform integrates structured system design into the OWASP ecosystem. The initial frontend, based on Vue.js, was introduced by Kateryna Golovanova (Kate), who later became the project co-leader due to her invaluable frontend and project management skills.',
'Over time, OWASP Nest has expanded to address broader community needs, such as Google Summer of Code (GSoC) student guidance and contribution opportunities discovery. The platform, alongside NestBot, has become a central hub for OWASP projects, chapters, users, and aggregated contribution opportunities.',
'The code is licensed under the MIT License, encouraging contributions while protecting the authors from legal claims. All OWASP Nest leaders are certified ISC2 professionals and OWASP members who adhere to the OWASP Code of Conduct.',
]
-export const technologies = [
+export const missionContent: MissionContent = {
+ mission:
+ 'OWASP Nest is a comprehensive platform built to enhance collaboration and streamline contributions across the OWASP community. Acting as a central hub, it helps users discover projects, find contribution opportunities, and connect with like-minded individuals based on their interests and expertise.',
+ whoItsFor:
+ "OWASP Nest is designed for developers, designers, technical writers, students, security professionals, and contributors of all backgrounds. Whether you're just starting out or a seasoned OSS veteran, Nest provides intuitive tools to help you engage meaningfully in the OWASP ecosystem.",
+} as const
+
+export const keyFeatures: KeyFeature[] = [
+ {
+ title: 'Advanced Search Capabilities',
+ description:
+ 'Easily filter and explore projects or issues using keywords, tags, and contributor preferences.',
+ },
+ {
+ title: 'Slack Integration',
+ description:
+ 'Stay connected through a Slack bot that delivers updates and supports both direct and channel messaging.',
+ },
+ {
+ title: 'OWASP Chapters Proximity Page',
+ description: 'Discover and connect with nearby OWASP chapters for local engagement.',
+ },
+ {
+ title: 'AI-Generated Insights',
+ description:
+ 'Benefit from AI-powered summaries and actionable suggestions for tackling project issues.',
+ },
+]
+
+export const getInvolvedContent: GetInvolved = {
+ description:
+ "OWASP Nest thrives thanks to community-driven contributions. Here's how you can make an impact:",
+ ways: [
+ 'Code Contributions – Fix bugs or build new features',
+ 'Code Review – Improve quality by reviewing pull requests',
+ 'Documentation – Create or enhance onboarding guides and tutorials',
+ 'Issue Reporting – Report bugs or propose improvements',
+ 'Community Engagement – Join Slack discussions and provide feedback',
+ ],
+ callToAction:
+ 'To get started, visit the [OWASP Nest Repository](https://github.com/OWASP/Nest), explore the [Contributing Guidelines](https://github.com/OWASP/Nest/blob/main/CONTRIBUTING.md), and review the [Code of Conduct](https://github.com/OWASP/Nest/blob/main/CODE_OF_CONDUCT.md).',
+}
+
+export const projectHistory: ProjectHistory[] = [
+ {
+ title: 'Project Inception',
+ description:
+ 'Initial brainstorming and vision by Arkadii Yakovets (Ark) & Starr Brown to solve OWASP project navigation challenges',
+ year: 'Jan 2023',
+ },
+ {
+ title: 'Backend MVP',
+ description:
+ 'Backend foundations built using Python, Django, DRF with AI capabilities integrated',
+ year: 'Mar 2023',
+ },
+ {
+ title: 'Frontend Development',
+ description:
+ 'Frontend initially developed by Kateryna Golovanova (Kate) using Vue.js, later transitioned to React',
+ year: 'Sep 2024',
+ },
+ {
+ title: 'Platform Integrations',
+ description: 'Slack & Algolia integrations implemented for enhanced user experience',
+ year: 'Nov 2024',
+ },
+ {
+ title: 'GSoC Integration',
+ description: 'Scaled to support Google Summer of Code and streamline contributor onboarding',
+ year: 'Dec 2024',
+ },
+]
+
+export const leaders: Leaders = {
+ arkid15r: 'CCSP, CISSP, CSSLP',
+ kasya: 'CC',
+ mamicidal: 'CISSP',
+}
+
+export const technologies: TechnologySection[] = [
{
section: 'Backend',
tools: {