|
| 1 | +# Security Assessment Infrastructure |
| 2 | + |
| 3 | +Central infrastructure for creating security assessment pages across eSolia projects. This enables each site to display OWASP ASVS compliance status with a design that matches the site's look and feel. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The security assessment system consists of: |
| 8 | +1. **Scanner Script** - Runs pattern-based security checks against OWASP ASVS 5.0 |
| 9 | +2. **JSON Report** - Generated output consumed by the assessment page |
| 10 | +3. **Assessment Page** - Displays results in site-native styling |
| 11 | + |
| 12 | +## Quick Start for Claude Code |
| 13 | + |
| 14 | +When implementing a security assessment page on a new site: |
| 15 | + |
| 16 | +```markdown |
| 17 | +Read the implementation guide at: |
| 18 | +https://github.com/eSolia/.github/blob/main/security-assessment/README.md |
| 19 | + |
| 20 | +Then implement: |
| 21 | +1. Copy and customize the scanner script for this project's stack |
| 22 | +2. Generate the JSON report to the appropriate location |
| 23 | +3. Create the assessment page matching the site's design system |
| 24 | +``` |
| 25 | + |
| 26 | +## Implementation Steps |
| 27 | + |
| 28 | +### Step 1: Create the Scanner Script |
| 29 | + |
| 30 | +Copy `asvs-check-template.ts` to your project's `scripts/` directory and customize: |
| 31 | + |
| 32 | +```bash |
| 33 | +# From your project root |
| 34 | +curl -O https://raw.githubusercontent.com/eSolia/.github/main/security-assessment/asvs-check-template.ts |
| 35 | +mv asvs-check-template.ts scripts/asvs-check.ts |
| 36 | +``` |
| 37 | + |
| 38 | +**Required customizations:** |
| 39 | + |
| 40 | +1. Update `PROJECT_CONFIG` at the top of the file: |
| 41 | +```typescript |
| 42 | +const PROJECT_CONFIG = { |
| 43 | + name: 'your-project-name', |
| 44 | + sourcePaths: ['src/'], // Paths to scan |
| 45 | + apiPaths: ['src/routes/api/'], // API-specific paths |
| 46 | + webPaths: ['src/routes/'], // Web/frontend paths |
| 47 | + packageManager: 'npm', // npm | pnpm | yarn | bun |
| 48 | + corsOrigins: ['yourdomain.com'], // Expected CORS origins |
| 49 | +}; |
| 50 | +``` |
| 51 | + |
| 52 | +2. Adjust the ASVS checks for your stack (see "Check Customization" below) |
| 53 | + |
| 54 | +### Step 2: Configure the Output Location |
| 55 | + |
| 56 | +The scanner outputs JSON that must be accessible to your assessment page: |
| 57 | + |
| 58 | +| Framework | Recommended Location | |
| 59 | +|-----------|---------------------| |
| 60 | +| SvelteKit | `src/lib/data/asvs-assessment.json` | |
| 61 | +| Astro | `src/data/asvs-assessment.json` | |
| 62 | +| Next.js | `public/data/asvs-assessment.json` | |
| 63 | +| Hono API | `static/asvs-assessment.json` | |
| 64 | + |
| 65 | +### Step 3: Create the Assessment Page |
| 66 | + |
| 67 | +The page should: |
| 68 | +1. Import the JSON report |
| 69 | +2. Calculate compliance score |
| 70 | +3. Display results grouped by ASVS category |
| 71 | +4. Match the site's design system |
| 72 | + |
| 73 | +**SvelteKit Example:** |
| 74 | +```svelte |
| 75 | +<script lang="ts"> |
| 76 | + import assessmentData from '$lib/data/asvs-assessment.json'; |
| 77 | +
|
| 78 | + const report = assessmentData; |
| 79 | + const score = Math.round((report.summary.passed / report.summary.total) * 100); |
| 80 | +</script> |
| 81 | +
|
| 82 | +<h1>Security Assessment</h1> |
| 83 | +<p>Compliance Score: {score}%</p> |
| 84 | +
|
| 85 | +{#each report.checks as check} |
| 86 | + <div class="check" data-status={check.status}> |
| 87 | + <strong>[{check.id}]</strong> {check.name} |
| 88 | + <p>{check.description}</p> |
| 89 | + </div> |
| 90 | +{/each} |
| 91 | +``` |
| 92 | + |
| 93 | +### Step 4: Add to CI/CD Pipeline |
| 94 | + |
| 95 | +Add to your GitHub Actions workflow: |
| 96 | + |
| 97 | +```yaml |
| 98 | +- name: Run ASVS Check |
| 99 | + run: npx tsx scripts/asvs-check.ts --format json --output src/lib/data/asvs-assessment.json |
| 100 | +``` |
| 101 | +
|
| 102 | +Or use the shared security workflow with `run-asvs: true`: |
| 103 | + |
| 104 | +```yaml |
| 105 | +jobs: |
| 106 | + security: |
| 107 | + uses: eSolia/.github/.github/workflows/security.yml@main |
| 108 | + with: |
| 109 | + run-asvs: true |
| 110 | +``` |
| 111 | + |
| 112 | +## Check Customization |
| 113 | + |
| 114 | +### Available Check Categories |
| 115 | + |
| 116 | +| Category | ASVS Section | Checks Available | |
| 117 | +|----------|-------------|------------------| |
| 118 | +| V2 Authentication | Password hashing, token entropy, MFA | 3 | |
| 119 | +| V3 Session | Token expiration, session management | 2 | |
| 120 | +| V4 Access Control | CORS, rate limiting, authorization | 3 | |
| 121 | +| V5 Validation | Input validation, SQL injection, XSS | 4 | |
| 122 | +| V7 Error Handling | Stack trace exposure, error messages | 2 | |
| 123 | +| V8 Data Protection | Secrets management, encryption | 2 | |
| 124 | +| V9 Communication | Security headers, TLS | 2 | |
| 125 | +| V10 Malicious Code | Dependency audit, integrity | 2 | |
| 126 | + |
| 127 | +### Adding Custom Checks |
| 128 | + |
| 129 | +```typescript |
| 130 | +// In your customized asvs-check.ts |
| 131 | +results.push({ |
| 132 | + id: 'CUSTOM-001', |
| 133 | + category: 'V5 Validation', |
| 134 | + name: 'Custom Validation Check', |
| 135 | + status: someCondition ? 'pass' : 'fail', |
| 136 | + description: 'Description of what this checks', |
| 137 | + asvsRef: 'V5.x.x', |
| 138 | + locations: matchingLocations, |
| 139 | + remediation: 'How to fix if failing', |
| 140 | +}); |
| 141 | +``` |
| 142 | + |
| 143 | +### Stack-Specific Patterns |
| 144 | + |
| 145 | +**SvelteKit + Cloudflare:** |
| 146 | +```typescript |
| 147 | +// Check for platform.env usage (not process.env) |
| 148 | +const platformEnvLocations = searchPattern(serverFiles, /platform\.env\./); |
| 149 | +``` |
| 150 | + |
| 151 | +**Hono:** |
| 152 | +```typescript |
| 153 | +// Check for c.env usage |
| 154 | +const honoEnvLocations = searchPattern(apiFiles, /c\.env\./); |
| 155 | +``` |
| 156 | + |
| 157 | +**Drizzle ORM:** |
| 158 | +```typescript |
| 159 | +// Verify parameterized queries |
| 160 | +const drizzleLocations = searchPattern(apiFiles, /\.select\(\)|\.insert\(\)|\.update\(\)/); |
| 161 | +``` |
| 162 | + |
| 163 | +## Design Matching Guidelines |
| 164 | + |
| 165 | +The assessment page should feel native to each site. Key elements to match: |
| 166 | + |
| 167 | +1. **Typography** - Use site's heading and body fonts |
| 168 | +2. **Colors** - Map status colors to site's palette: |
| 169 | + - Pass → site's success/green |
| 170 | + - Fail → site's error/red |
| 171 | + - Warning → site's warning/amber |
| 172 | +3. **Layout** - Use site's container widths and spacing scale |
| 173 | +4. **Components** - Reuse site's card, badge, and icon components |
| 174 | + |
| 175 | +### Example: Mapping to Design Tokens |
| 176 | + |
| 177 | +```css |
| 178 | +/* Map assessment status to site's design tokens */ |
| 179 | +.check[data-status="pass"] { |
| 180 | + border-color: var(--color-success); |
| 181 | +} |
| 182 | +.check[data-status="fail"] { |
| 183 | + border-color: var(--color-error); |
| 184 | +} |
| 185 | +.check[data-status="warning"] { |
| 186 | + border-color: var(--color-warning); |
| 187 | +} |
| 188 | +``` |
| 189 | + |
| 190 | +## JSON Schema |
| 191 | + |
| 192 | +See [SCHEMA.md](./SCHEMA.md) for the complete JSON report schema. |
| 193 | + |
| 194 | +## File Structure |
| 195 | + |
| 196 | +After implementation, your project should have: |
| 197 | + |
| 198 | +``` |
| 199 | +your-project/ |
| 200 | +├── scripts/ |
| 201 | +│ └── asvs-check.ts # Customized scanner |
| 202 | +├── src/ |
| 203 | +│ ├── lib/data/ # Or appropriate location |
| 204 | +│ │ └── asvs-assessment.json |
| 205 | +│ └── routes/security/assessment/ |
| 206 | +│ └── +page.svelte # Assessment page |
| 207 | +└── .github/workflows/ |
| 208 | + └── security.yml # Uses shared workflow |
| 209 | +``` |
| 210 | + |
| 211 | +## Troubleshooting |
| 212 | + |
| 213 | +### Scanner exits with error code 1 |
| 214 | +This is intentional - the script exits non-zero when checks fail. Use `|| true` in CI if you want to continue despite failures. |
| 215 | + |
| 216 | +### JSON not updating |
| 217 | +Ensure the scanner runs before build and the output path matches your import. |
| 218 | + |
| 219 | +### Checks showing "warning" instead of "pass" |
| 220 | +Warnings indicate the pattern wasn't found but it's not critical. Review if the check patterns match your codebase. |
| 221 | + |
| 222 | +## Reference Implementation |
| 223 | + |
| 224 | +See pub-cogley for a complete working implementation: |
| 225 | +- Scanner: `scripts/asvs-check.ts` |
| 226 | +- Page: `apps/web/src/routes/security/assessment/+page.svelte` |
| 227 | +- Report: `apps/web/src/lib/data/asvs-assessment.json` |
0 commit comments