Skip to content

Commit 8f1b00b

Browse files
committed
feat: initial AppSecOne implementation
Signed-off-by: Damian Skrzyński <polprog.tech@gmail.com>
1 parent 91f7b70 commit 8f1b00b

123 files changed

Lines changed: 24783 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# =============================================================================
2+
# AppSecOne — Environment Variables
3+
# =============================================================================
4+
# Copy this file to .env and fill in the values for your environment.
5+
# All variables are optional unless noted otherwise.
6+
7+
# --- Fortify SSC Integration ---
8+
# Auth token for Fortify SSC API (required for sync to work).
9+
# The variable name can be customized in appsecone.json → fortify.token_env_var
10+
FORTIFY_SSC_TOKEN=
11+
12+
# --- API Security ---
13+
# When set, all state-changing API requests (POST/PUT/DELETE) require this key
14+
# in the X-API-Key header. GET requests and health endpoints are always public.
15+
# Uses timing-safe HMAC comparison to prevent timing attacks.
16+
APPSECONE_API_KEY=
17+
18+
# --- CORS (Cross-Origin Resource Sharing) ---
19+
# Comma-separated list of allowed origins for cross-origin requests.
20+
# If not set, CORS will reject all cross-origin requests.
21+
# Example: https://dashboard.example.com,https://staging.example.com
22+
APPSECONE_CORS_ORIGINS=
23+
24+
# --- Framing / Embedding ---
25+
# Set to "true" to allow the dashboard to be embedded in iframes.
26+
# When enabled, frame-ancestors is set to 'self' + CORS origins.
27+
# Default: false (X-Frame-Options: DENY)
28+
APPSECONE_ALLOW_FRAMING=false

.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-python@v5
15+
with:
16+
python-version: "3.13"
17+
- name: Install dependencies
18+
run: pip install --quiet -e ".[dev]"
19+
- name: Lint
20+
run: python -m ruff check src/ tests/
21+
22+
test:
23+
runs-on: ubuntu-latest
24+
strategy:
25+
matrix:
26+
python-version: ["3.12", "3.13"]
27+
steps:
28+
- uses: actions/checkout@v4
29+
- uses: actions/setup-python@v5
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
- name: Install dependencies
33+
run: pip install --quiet -e ".[dev]"
34+
- name: Run tests
35+
run: python -m pytest --tb=short -q --junitxml=results.xml
36+
- name: Upload test results
37+
uses: actions/upload-artifact@v4
38+
if: always()
39+
with:
40+
name: test-results-${{ matrix.python-version }}
41+
path: results.xml

.gitignore

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# ── Byte-compiled / optimized / DLL files ──────────────────────────────────
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.pyo
6+
7+
# ── Distribution / packaging ───────────────────────────────────────────────
8+
dist/
9+
build/
10+
*.egg-info/
11+
*.egg
12+
.eggs/
13+
14+
# ── Virtual environments ───────────────────────────────────────────────────
15+
.venv/
16+
venv/
17+
env/
18+
19+
# ── IDE / Editor ───────────────────────────────────────────────────────────
20+
.idea/
21+
.vscode/
22+
*.swp
23+
*.swo
24+
*~
25+
26+
# ── Testing ────────────────────────────────────────────────────────────────
27+
.coverage
28+
htmlcov/
29+
.pytest_cache/
30+
.ruff_cache/
31+
32+
# ── Generated output ──────────────────────────────────────────────────────
33+
output/
34+
*.html
35+
!src/appsecone/presentation/templates/*.html.j2
36+
37+
# ── OS files ───────────────────────────────────────────────────────────────
38+
.DS_Store
39+
Thumbs.db
40+
41+
# ── Environment / secrets ──────────────────────────────────────────────────
42+
.env
43+
.env.local
44+
*.pem
45+
*.key
46+
47+
# ── Database ───────────────────────────────────────────────────────────────
48+
*.db
49+
*.sqlite3
50+
51+
# ── User config ────────────────────────────────────────────────────────────
52+
appsecone.json
53+
appsecone.json.bak
54+
data/*.db
55+
data/*.db-shm
56+
data/*.db-wal

.gitlab-ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
stages:
2+
- lint
3+
- test
4+
5+
variables:
6+
PYTHONDONTWRITEBYTECODE: "1"
7+
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
8+
PYTHONPATH: "src"
9+
10+
default:
11+
cache:
12+
key: pip-${CI_COMMIT_REF_SLUG}
13+
paths:
14+
- .pip-cache/
15+
16+
lint:
17+
stage: lint
18+
image: python:3.13-slim
19+
before_script:
20+
- pip install --quiet -e ".[dev]"
21+
script:
22+
- python -m ruff check src/ tests/
23+
24+
test:
25+
stage: test
26+
image: python:${PYTHON_VERSION}-slim
27+
parallel:
28+
matrix:
29+
- PYTHON_VERSION: ["3.12", "3.13"]
30+
before_script:
31+
- pip install --quiet -e ".[dev]"
32+
script:
33+
- pytest --tb=short -q --junitxml=results.xml
34+
artifacts:
35+
reports:
36+
junit: results.xml
37+
expire_in: 7 days

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Changelog
2+
3+
All notable changes to AppSecOne will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] — 2026-03-28
9+
10+
### Added
11+
- **Portfolio Dashboard** — aggregated severity breakdown, readiness donut chart, repository cards with status indicators, and trend badges
12+
- **Findings Explorer** — filterable, sortable, paginated table of all findings across the portfolio with severity badges and export to CSV/JSON
13+
- **Repository Detail** — deep-dive into a single repository with findings table, policy evaluation, blocker panels, stacked severity bar, and trend chart
14+
- **Policy & Waivers** — policy rules overview, active waivers with expiry tracking, and waiver creation form with audit trail
15+
- **Admin & Sync** — system configuration summary, manual sync trigger with real-time SSE progress, sync history log
16+
- **Setup Wizard** — guided 4-step setup: Fortify connection → project discovery → repository mapping → policy & sync configuration
17+
- **Fortify SSC integration** — full sync with rate limiting, exponential backoff retry, pagination, and corporate SSL support
18+
- **Deterministic policy engine** — configurable thresholds for critical/high/medium findings, issue age limits, waiver support
19+
- **Trend analytics** — historical daily snapshots with 5% threshold direction classification (improving / stable / worsening)
20+
- **i18n support** — English and Polish locales with pluralization, interpolation, and async-safe context management
21+
- **Security middleware stack** — CSP with nonce, CSRF protection, rate limiting, API key auth, body size limits, correlation IDs
22+
- **CLI**`serve`, `sync`, `evaluate`, `validate`, `version` commands via Typer
23+
- **REST API** — 15+ endpoints for overview, repositories, findings, readiness, policies, waivers, sync, trends, export, health, i18n
24+
- **464 tests** — unit, integration, security regression, i18n validation, UI regression
25+
26+
[1.0.0]: https://github.com/polprog-tech/AppSecOne/releases/tag/v1.0.0

CODE_OF_CONDUCT.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
We as members, contributors, and leaders pledge to make participation in our
6+
community a harassment-free experience for everyone, regardless of age, body
7+
size, visible or invisible disability, ethnicity, sex characteristics, gender
8+
identity and expression, level of experience, education, socio-economic status,
9+
nationality, personal appearance, race, caste, color, religion, or sexual
10+
identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to a positive environment:
15+
16+
* Using welcoming and inclusive language
17+
* Being respectful of differing viewpoints and experiences
18+
* Gracefully accepting constructive criticism
19+
* Focusing on what is best for the community
20+
* Showing empathy towards other community members
21+
22+
Examples of unacceptable behavior:
23+
24+
* The use of sexualized language or imagery
25+
* Trolling, insulting/derogatory comments, and personal or political attacks
26+
* Public or private harassment
27+
* Publishing others' private information without explicit permission
28+
* Other conduct which could reasonably be considered inappropriate
29+
30+
## Enforcement
31+
32+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
33+
reported to the project maintainers. All complaints will be reviewed and
34+
investigated promptly and fairly.
35+
36+
## Attribution
37+
38+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
39+
version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.

CONTRIBUTING.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Contributing to AppSecOne
2+
3+
Thank you for your interest in contributing to AppSecOne! This guide will help you get started.
4+
5+
## Development Setup
6+
7+
### Prerequisites
8+
9+
- Python 3.12 or higher
10+
- Git
11+
12+
### Installation
13+
14+
```bash
15+
git clone https://github.com/polprog-tech/AppSecOne.git
16+
cd AppSecOne
17+
python3 -m venv .venv
18+
source .venv/bin/activate
19+
python3 -m pip install -e ".[dev]"
20+
```
21+
22+
### Running the development server
23+
24+
```bash
25+
appsecone serve --config appsecone.json --port 8080 --verbose
26+
```
27+
28+
### Running tests
29+
30+
```bash
31+
# Full suite (464 tests)
32+
python3 -m pytest tests/ -q
33+
34+
# With coverage
35+
python3 -m pytest --cov=appsecone --cov-report=term-missing
36+
```
37+
38+
### Linting & Formatting
39+
40+
```bash
41+
# Check
42+
python3 -m ruff check src/ tests/
43+
44+
# Auto-fix
45+
python3 -m ruff check --fix src/ tests/
46+
47+
# Format
48+
python3 -m ruff format src/ tests/
49+
```
50+
51+
## Project Structure
52+
53+
```
54+
src/appsecone/
55+
├── domain/ # Pure domain models and enums (zero I/O)
56+
├── config/ # Configuration loading and validation
57+
├── fortify/ # Fortify SSC integration client
58+
│ ├── client/ # HTTP client, auth, endpoints
59+
│ └── mappers/ # DTO → domain model mapping
60+
├── persistence/ # Database layer (SQLite)
61+
├── application/ # Sync and query services (async)
62+
├── analysis/ # Trend analytics & historical snapshots
63+
├── presentation/ # Jinja2 renderer, view models, templates
64+
│ └── templates/ # HTML templates with design system
65+
├── web/ # FastAPI server, middleware, routes
66+
├── cli/ # Typer CLI commands
67+
├── i18n/ # Internationalization catalogs (EN, PL)
68+
│ └── locales/ # JSON translation files
69+
└── shared/ # Logging, networking, type aliases
70+
```
71+
72+
## Code Style
73+
74+
- **Python 3.12+** features encouraged (`StrEnum`, type unions, f-strings)
75+
- **Ruff** for linting and formatting (config in `pyproject.toml`)
76+
- **Frozen dataclasses** for domain models — immutability by default
77+
- **Type hints** everywhere — no untyped public APIs
78+
- **Async** for all I/O operations (database, network, file system)
79+
- **CSS custom properties** for all design tokens — no hardcoded colors or spacing in templates
80+
- **No inline styles** — all visual styling via CSS classes
81+
- **CSP-safe JavaScript** — all scripts use nonce attributes, no inline event handlers
82+
83+
## Making Changes
84+
85+
1. Create a feature branch: `git checkout -b feature/your-feature`
86+
2. Make your changes
87+
3. Run tests: `python3 -m pytest tests/ -q`
88+
4. Run linter: `python3 -m ruff check src/ tests/`
89+
5. Verify no regressions in UX/UI: `python3 -m pytest tests/unit/presentation/ -q`
90+
6. Commit with a descriptive message
91+
7. Open a pull request
92+
93+
## Architecture Principles
94+
95+
- **Domain layer has zero I/O** — pure functions and frozen dataclasses only
96+
- **Application layer is async** — all database and network calls are awaited
97+
- **Presentation layer builds view models** — no business logic in templates
98+
- **Web layer is thin** — routes delegate to services, never contain business logic
99+
- **Config-driven policy** — release readiness rules live in JSON, not code
100+
- **Security by default** — CSP headers, CSRF protection, rate limiting, API key auth
101+
102+
## Internationalization
103+
104+
AppSecOne supports multiple languages. Translation catalogs live in `src/appsecone/i18n/locales/`.
105+
106+
- Use `t('key.name')` in Jinja2 templates
107+
- Use `t('key', count=N)` for pluralization (keys: `.one`, `.other`, `.few` for Polish)
108+
- Always add keys to **both** `en.json` and `pl.json`
109+
110+
## Reporting Issues
111+
112+
- Use GitHub Issues for bug reports and feature requests
113+
- Include reproduction steps for bugs
114+
- Include expected vs actual behavior
115+
- For UI issues, include the browser, theme, and language used

0 commit comments

Comments
 (0)