Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
# Security Policy
## Reporting a Vulnerability
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them via email to **[email protected]** with:
- Description of the vulnerability
- Steps to reproduce
- Affected versions
- Any proof of concept
You can expect:
- Acknowledgment within 24 hours
- Regular updates on progress
- Credit for your discovery (if desired)
For more details, see our full [Security Policy](./docs/SECURITY.md).
## Supported Versions
| Version | Supported |
| :------ | :-------- |
| 1.0.x | ✅ |
| < 1.0 | ❌ |
## Bug Bounty
We offer bounties for qualifying vulnerabilities. See [full policy](./docs/SECURITY.md#-bug-bounty-program) for details.
# Security Policy

## Reporting a Vulnerability

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

Instead, please report them via email to **[email protected]** with:

- Description of the vulnerability
- Steps to reproduce
- Affected versions
- Any proof of concept

You can expect:

- Acknowledgment within 24 hours
- Regular updates on progress
- Credit for your discovery (if desired)

For more details, see our full [Security Policy](./docs/SECURITY.md).

## Supported Versions

| Version | Supported |
| :------ | :-------- |
| 1.0.x | ✅ |
| < 1.0 | ❌ |

## Bug Bounty

We offer bounties for qualifying vulnerabilities. See [full policy](./docs/SECURITY.md#-bug-bounty-program) for details.
96 changes: 76 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# CI: lint, format check, type check, and tests on PR and push to main
# Branch protection: enable "Require status checks to pass" for this workflow in repo Settings > Branches

name: CI
name: Backend CI Quality Gates

on:
pull_request:
Expand All @@ -10,14 +7,46 @@ on:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
ci:
name: Lint, typecheck, format, test
quality:
name: Quality gates
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: learnault_ci
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d learnault_ci"
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
NODE_ENV: test
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/learnault_ci?schema=public
REDIS_URL: redis://localhost:6379
JWT_SECRET: ci-test-secret
AUDIT_IP_HASH_SECRET: ci-audit-secret

steps:
- name: Checkout
Expand All @@ -26,6 +55,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.0.0
run_install: false

- name: Setup Node.js
Expand All @@ -35,26 +65,52 @@ jobs:
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Check Prisma formatting
run: pnpm prisma:format:check

- name: Generate Prisma Client
run: npx prisma generate
env:
DATABASE_URL: "file:./dev.db"
run: pnpm db:generate

- name: Validate migrations on an empty database
run: pnpm db:deploy

- name: Check formatting
run: pnpm format:check

- name: Lint (ESLint)
run: pnpm run lint
- name: Lint
run: pnpm lint

- name: Validate Docker Compose stack
run: docker compose config --quiet
- name: Type check
run: pnpm typecheck

- name: Run tests with coverage
run: pnpm run test:coverage
- name: Run tests
run: pnpm test:ci

- name: Enforce coverage
run: pnpm test:coverage

- name: Build
run: pnpm build

- name: Upload failure diagnostics
if: failure()
uses: actions/upload-artifact@v4
with:
name: ci-failure-diagnostics
path: |
coverage/
**/test-results/**
**/*.log
if-no-files-found: ignore
retention-days: 7

- name: Upload coverage (optional)
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
if: success() && (github.event_name == 'pull_request' || github.ref == 'refs/heads/main')
with:
name: coverage-report
path: coverage/
if-no-files-found: ignore
retention-days: 7
16 changes: 8 additions & 8 deletions .github/workflows/deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: staging

steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down Expand Up @@ -44,7 +44,7 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max

# We simulate the staging deployment locally on the GitHub Runner
# We simulate the staging deployment locally on the GitHub Runner
# since there's no remote target specified yet.
- name: Deploy to Staging (Runner)
env:
Expand All @@ -53,11 +53,11 @@ jobs:
run: |
echo "Actor: ${{ github.actor }}"
echo "Digest/Tag: ${{ steps.meta.outputs.version }}"

# We need to run the postgres db as a mock for staging
docker compose -f docker-compose.staging.yml up -d db
sleep 10 # Wait for db to initialize

# Run deployment
./scripts/deploy-staging.sh ${{ steps.meta.outputs.version }}

Expand All @@ -68,16 +68,16 @@ jobs:
if: failure()
run: |
echo "Deployment or Smoke Tests failed. Initiating Rollback..."

# Get the previous commit SHA to rollback to
PREV_SHA=$(git rev-parse HEAD^)
PREV_TAG="sha-$PREV_SHA"

echo "Rolling back to tag: $PREV_TAG"

# Since this is a CI mock, we just run the rollback script
# In reality, this tag would be pulled from the registry
# We'll just build it to simulate
docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$PREV_TAG .

./scripts/rollback-staging.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$PREV_TAG
13 changes: 13 additions & 0 deletions PR_DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# Credential Controller & Routes Implementation

## Overview

Implements credential management endpoints for certificates and achievements as specified in issue #8.

## Changes Made

### New Files

- `src/controllers/credential.controller.ts` - Controller with three main endpoints
- `src/routes/v1/credentials.routes.ts` - Route definitions with validation
- `tests/unit/credential.controller.test.ts` - Comprehensive unit tests (14 tests, all passing)

### Modified Files

- `src/routes/index.ts` - Added credentials routes to API

## Implemented Endpoints

### 1. GET /api/v1/credentials

- **Auth**: Required
- **Purpose**: Retrieve all credentials for authenticated user
- **Query Params**: `moduleId`, `fromDate`, `toDate`, `page`, `limit`
Expand All @@ -27,6 +31,7 @@ Implements credential management endpoints for certificates and achievements as
- Includes shareable verification links

### 2. GET /api/v1/credentials/:id

- **Auth**: Required (user must own credential)
- **Purpose**: Retrieve single credential details
- **Features**:
Expand All @@ -37,6 +42,7 @@ Implements credential management endpoints for certificates and achievements as
- Shareable link

### 3. GET /api/v1/credentials/verify/:onChainId

- **Auth**: Not required (public endpoint)
- **Purpose**: Public verification of credentials
- **Features**:
Expand All @@ -48,31 +54,36 @@ Implements credential management endpoints for certificates and achievements as
## Technical Details

### Validation

- Uses Zod schemas for input validation
- UUID validation for IDs
- ISO 8601 datetime validation for date filters
- Numeric validation for pagination parameters

### Error Handling

- Proper HTTP status codes (400, 401, 404)
- Descriptive error messages
- Uses custom error classes (BadRequestError, NotFoundError, UnauthorizedError)
- Wrapped with asyncHandler for promise rejection handling

### Database

- Uses Prisma ORM
- Efficient queries with proper includes
- Pagination with count queries
- Indexed lookups by ID and onChainId

## Testing

- 14 unit tests covering all endpoints
- Tests for success cases
- Tests for error cases (invalid input, unauthorized access, not found)
- Tests for filtering and pagination
- All tests passing ✅

## Acceptance Criteria Met

- ✅ Users can view all their earned credentials
- ✅ Public verification endpoint returns credential validity
- ✅ Verification works without authentication
Expand All @@ -81,6 +92,7 @@ Implements credential management endpoints for certificates and achievements as
- ✅ Unit tests written and passing

## Code Quality

- ✅ Linting passed
- ✅ All existing tests still passing (225 tests total)
- ✅ Follows existing codebase patterns
Expand All @@ -89,6 +101,7 @@ Implements credential management endpoints for certificates and achievements as
- ✅ Clean, readable code with comments

## Next Steps

- Integration testing with actual database
- E2E testing for complete user flows
- Performance testing with large datasets
Expand Down
Loading
Loading