Add QA test outputs, build scripts, and Dockerfile validation

- Created `qa-test-output-after-fix.txt` and `qa-test-output.txt` to log results of certificate page authentication tests.
- Added `build.sh` for deterministic backend builds in CI, utilizing `go list` for efficiency.
- Introduced `codeql_scan.sh` for CodeQL database creation and analysis for Go and JavaScript/TypeScript.
- Implemented `dockerfile_check.sh` to validate Dockerfiles for base image and package manager mismatches.
- Added `sourcery_precommit_wrapper.sh` to facilitate Sourcery CLI usage in pre-commit hooks.
This commit is contained in:
GitHub Actions
2025-12-11 18:26:24 +00:00
parent 65d837a13f
commit 8294d6ee49
609 changed files with 111623 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
import { describe, it, expect } from 'vitest';
import {
SECURITY_PRESETS,
getPresetById,
getPresetsByCategory,
calculateCIDRSize,
formatIPCount,
calculateTotalIPs,
} from '../securityPresets';
describe('securityPresets', () => {
describe('SECURITY_PRESETS', () => {
it('contains expected presets', () => {
expect(SECURITY_PRESETS.length).toBeGreaterThan(0);
// Verify preset structure
SECURITY_PRESETS.forEach((preset) => {
expect(preset).toHaveProperty('id');
expect(preset).toHaveProperty('name');
expect(preset).toHaveProperty('description');
expect(preset).toHaveProperty('category');
expect(preset).toHaveProperty('type');
expect(preset).toHaveProperty('estimatedIPs');
expect(preset).toHaveProperty('dataSource');
expect(preset).toHaveProperty('dataSourceUrl');
});
});
it('has valid categories', () => {
const validCategories = ['security', 'advanced'];
SECURITY_PRESETS.forEach((preset) => {
expect(validCategories).toContain(preset.category);
});
});
it('has valid types', () => {
const validTypes = ['geo_blacklist', 'blacklist'];
SECURITY_PRESETS.forEach((preset) => {
expect(validTypes).toContain(preset.type);
});
});
it('geo_blacklist presets have countryCodes', () => {
const geoPresets = SECURITY_PRESETS.filter((p) => p.type === 'geo_blacklist');
geoPresets.forEach((preset) => {
expect(preset.countryCodes).toBeDefined();
expect(preset.countryCodes!.length).toBeGreaterThan(0);
});
});
it('no IP-based blacklist presets are included (CrowdSec handles dynamic IP threats)', () => {
const ipPresets = SECURITY_PRESETS.filter((p) => p.type === 'blacklist');
// IP-based blacklists are deprecated and should be handled by CrowdSec / WAF / rate limiting
expect(ipPresets.length).toBe(0);
});
});
describe('getPresetById', () => {
it('returns preset when found', () => {
const preset = getPresetById('high-risk-countries');
expect(preset).toBeDefined();
expect(preset?.id).toBe('high-risk-countries');
expect(preset?.name).toBe('Block High-Risk Countries');
});
it('returns undefined when not found', () => {
const preset = getPresetById('nonexistent-preset');
expect(preset).toBeUndefined();
});
});
describe('getPresetsByCategory', () => {
it('returns security category presets', () => {
const securityPresets = getPresetsByCategory('security');
expect(securityPresets.length).toBeGreaterThan(0);
securityPresets.forEach((preset) => {
expect(preset.category).toBe('security');
});
});
it('returns advanced category presets (may be empty)', () => {
const advancedPresets = getPresetsByCategory('advanced');
expect(Array.isArray(advancedPresets)).toBe(true);
advancedPresets.forEach((preset) => {
expect(preset.category).toBe('advanced');
});
});
});
describe('calculateCIDRSize', () => {
it('calculates /32 as 1 IP', () => {
expect(calculateCIDRSize('192.168.1.1/32')).toBe(1);
});
it('calculates /24 as 256 IPs', () => {
expect(calculateCIDRSize('192.168.1.0/24')).toBe(256);
});
it('calculates /16 as 65536 IPs', () => {
expect(calculateCIDRSize('192.168.0.0/16')).toBe(65536);
});
it('calculates /8 as 16777216 IPs', () => {
expect(calculateCIDRSize('10.0.0.0/8')).toBe(16777216);
});
it('calculates /0 as all IPs', () => {
expect(calculateCIDRSize('0.0.0.0/0')).toBe(4294967296);
});
it('returns 1 for single IP without CIDR notation', () => {
expect(calculateCIDRSize('192.168.1.1')).toBe(1);
});
it('returns 1 for invalid CIDR', () => {
expect(calculateCIDRSize('invalid')).toBe(1);
expect(calculateCIDRSize('192.168.1.0/abc')).toBe(1);
expect(calculateCIDRSize('192.168.1.0/-1')).toBe(1);
expect(calculateCIDRSize('192.168.1.0/33')).toBe(1);
});
});
describe('formatIPCount', () => {
it('formats small numbers as-is', () => {
expect(formatIPCount(0)).toBe('0');
expect(formatIPCount(1)).toBe('1');
expect(formatIPCount(999)).toBe('999');
});
it('formats thousands with K suffix', () => {
expect(formatIPCount(1000)).toBe('1.0K');
expect(formatIPCount(1500)).toBe('1.5K');
expect(formatIPCount(999999)).toBe('1000.0K');
});
it('formats millions with M suffix', () => {
expect(formatIPCount(1000000)).toBe('1.0M');
expect(formatIPCount(2500000)).toBe('2.5M');
expect(formatIPCount(999999999)).toBe('1000.0M');
});
it('formats billions with B suffix', () => {
expect(formatIPCount(1000000000)).toBe('1.0B');
expect(formatIPCount(4294967296)).toBe('4.3B');
});
});
describe('calculateTotalIPs', () => {
it('calculates total for single CIDR', () => {
expect(calculateTotalIPs(['192.168.1.0/24'])).toBe(256);
});
it('calculates total for multiple CIDRs', () => {
expect(calculateTotalIPs(['192.168.1.0/24', '10.0.0.0/24'])).toBe(512);
});
it('handles empty array', () => {
expect(calculateTotalIPs([])).toBe(0);
});
it('handles mixed valid and invalid CIDRs', () => {
expect(calculateTotalIPs(['192.168.1.0/24', 'invalid'])).toBe(257);
});
});
});

View File

@@ -0,0 +1,77 @@
export interface CrowdsecPreset {
slug: string
title: string
description: string
content: string
tags?: string[]
warning?: string
}
export const CROWDSEC_PRESETS: CrowdsecPreset[] = [
{
slug: 'bot-mitigation-essentials',
title: 'Bot Mitigation Essentials',
description:
'Core HTTP parsers and scenarios aimed at credential stuffing, scanners, and bad crawlers with minimal false positives.',
tags: ['bots', 'web', 'auth'],
content: `configs:
collections:
- crowdsecurity/base-http-scenarios
- crowdsecurity/http-cve
- crowdsecurity/http-bad-user-agent
parsers:
- crowdsecurity/http-logs
- crowdsecurity/nginx-logs
- crowdsecurity/apache2-logs
scenarios:
- crowdsecurity/http-bf
- crowdsecurity/http-sensitive-files
- crowdsecurity/http-probing
- crowdsecurity/http-crawl-non_statics
postoverflows:
- crowdsecurity/whitelists
`,
warning: 'Best for internet-facing apps; ensure allowlists cover SSO and monitoring probes.',
},
{
slug: 'honeypot-friendly-defaults',
title: 'Honeypot Friendly Defaults',
description: 'Lightweight defaults tuned for tarpits and research honeypots to reduce noisy bans.',
tags: ['low-noise', 'ssh', 'http'],
content: `configs:
collections:
- crowdsecurity/sshd
- crowdsecurity/caddy
parsers:
- crowdsecurity/sshd-logs
- crowdsecurity/caddy-logs
scenarios:
- crowdsecurity/ssh-bf
- crowdsecurity/http-backdoors-attempts
- crowdsecurity/http-probing
postoverflows:
- crowdsecurity/whitelists
`,
warning: 'Keep honeypot endpoints isolated; avoid applying to production ingress.',
},
{
slug: 'geolocation-aware',
title: 'Geolocation Aware',
description: 'Adds geo-enrichment and region-aware scenarios to tighten access by country.',
tags: ['geo', 'access-control'],
content: `configs:
collections:
- crowdsecurity/geoip-enricher
scenarios:
- crowdsecurity/geo-fencing
- crowdsecurity/geo-bf
postoverflows:
- crowdsecurity/whitelists
`,
warning: 'Requires GeoIP database. Pair with ACLs to avoid blocking legitimate traffic.',
},
]
export const findCrowdsecPreset = (slug: string): CrowdsecPreset | undefined => {
return CROWDSEC_PRESETS.find((preset) => preset.slug === slug)
}

View File

@@ -0,0 +1,124 @@
/**
* Security Presets for Access Control Lists
*
* Data sources:
* - High-risk countries: Based on common attack origin statistics from threat intelligence feeds
* - Cloud scanner IPs: Known IP ranges used for mass scanning (Shodan, Censys, etc.)
* - Botnet IPs: Curated from public blocklists (Spamhaus, abuse.ch, etc.)
*
* References:
* - SANS Internet Storm Center: https://isc.sans.edu/
* - Spamhaus DROP/EDROP lists: https://www.spamhaus.org/drop/
* - Abuse.ch threat feeds: https://abuse.ch/
*/
export interface SecurityPreset {
id: string;
name: string;
description: string;
category: 'security' | 'advanced';
type: 'geo_blacklist' | 'blacklist';
countryCodes?: string[];
ipRanges?: Array<{ cidr: string; description: string }>;
estimatedIPs: string;
dataSource: string;
dataSourceUrl: string;
warning?: string;
}
export const SECURITY_PRESETS: SecurityPreset[] = [
{
id: 'high-risk-countries',
name: 'Block High-Risk Countries',
description: 'Block countries with highest attack/spam rates (OFAC sanctioned + known attack sources)',
category: 'security',
type: 'geo_blacklist',
countryCodes: [
'RU', // Russia
'CN', // China
'KP', // North Korea
'IR', // Iran
'BY', // Belarus
'SY', // Syria
'VE', // Venezuela
'CU', // Cuba
'SD', // Sudan
],
estimatedIPs: '~800 million',
dataSource: 'SANS ISC Top Attack Origins',
dataSourceUrl: 'https://isc.sans.edu/sources.html',
warning: 'This blocks entire countries. Legitimate users from these countries will be blocked.',
},
{
id: 'expanded-threat-countries',
name: 'Block Expanded Threat List',
description: 'High-risk countries plus additional sources of bot traffic and spam',
category: 'security',
type: 'geo_blacklist',
countryCodes: [
'RU', // Russia
'CN', // China
'KP', // North Korea
'IR', // Iran
'BY', // Belarus
'SY', // Syria
'VE', // Venezuela
'CU', // Cuba
'SD', // Sudan
'PK', // Pakistan
'BD', // Bangladesh
'NG', // Nigeria
'UA', // Ukraine (high bot activity)
'VN', // Vietnam
'ID', // Indonesia
],
estimatedIPs: '~1.2 billion',
dataSource: 'Combined threat intelligence feeds',
dataSourceUrl: 'https://isc.sans.edu/',
warning: 'Aggressive blocking. May impact legitimate international users.',
},
];
export const getPresetById = (id: string): SecurityPreset | undefined => {
return SECURITY_PRESETS.find((preset) => preset.id === id);
};
export const getPresetsByCategory = (category: 'security' | 'advanced'): SecurityPreset[] => {
return SECURITY_PRESETS.filter((preset) => preset.category === category);
};
/**
* Calculate approximate number of IPs in a CIDR range
*/
export const calculateCIDRSize = (cidr: string): number => {
const parts = cidr.split('/');
if (parts.length !== 2) return 1;
const bits = parseInt(parts[1], 10);
if (isNaN(bits) || bits < 0 || bits > 32) return 1;
return Math.pow(2, 32 - bits);
};
/**
* Format IP count for display
*/
export const formatIPCount = (count: number): string => {
if (count >= 1000000000) {
return `${(count / 1000000000).toFixed(1)}B`;
}
if (count >= 1000000) {
return `${(count / 1000000).toFixed(1)}M`;
}
if (count >= 1000) {
return `${(count / 1000).toFixed(1)}K`;
}
return count.toString();
};
/**
* Calculate total IPs in a list of CIDR ranges
*/
export const calculateTotalIPs = (cidrs: string[]): number => {
return cidrs.reduce((total, cidr) => total + calculateCIDRSize(cidr), 0);
};