Skip to content

POLPROG-TECH/AppSecOne

appsecone

Python 3.12+ Tests: 464 passed License: AGPL-3.0 CI FastAPI Source: Fortify SSC i18n: EN | PL

Enterprise-grade security posture dashboard that answers: "Are we ready to release?"
Fortify SSC . Policy Engine . Trend Analytics . Waiver Management . Release Readiness . i18n

About . Screenshots . Features . Installation . Quick Start . Configuration . API . Architecture . Testing

Support this project


What is AppSecOne?

AppSecOne is an enterprise application security dashboard that aggregates vulnerability data from Fortify SSC, evaluates release readiness through a deterministic policy engine, and presents the results in a real-time web dashboard with full API access.

Security teams, engineering managers, and release coordinators use it to answer critical questions every sprint:

  • "Can we ship this release?" - Policy engine evaluates every repository against configurable thresholds for critical, high, and medium findings.
  • "What's our security posture across the portfolio?" - Aggregated severity breakdowns, readiness scores, and trend analytics across all repositories.
  • "Are we improving or regressing?" - Historical trend snapshots with 5% threshold direction classification (improving / stable / worsening).
  • "Which teams need attention?" - Filter by team, repository type, criticality level, and readiness status.
  • "What did we waive, and why?" - Full waiver management with audit trail, expiry tracking, and approval workflows.

AppSecOne syncs from Fortify SSC on a configurable interval (default 30 minutes), stores a local read model in SQLite, and serves a server-rendered dashboard via FastAPI + Jinja2 - no JavaScript frameworks, no build steps, no external CSS dependencies.


Screenshots

Portfolio Dashboard

Aggregated severity breakdown, readiness donut chart, repository cards with status indicators, trend badges, and policy evaluation - all in a single overview.

AppSecOne - Portfolio dashboard with severity breakdown, readiness chart, and repository cards

Repository Detail

Deep-dive into a single repository - findings table with severity badges, policy evaluation with blocker panels, stacked severity bar, and historical trend chart.

AppSecOne - Repository detail with findings, policy evaluation, and trend chart


Features

Data Integration

  • Fortify SSC sync - periodic (30 min) and on-demand, with auto-pagination and retry
  • Full re-sync every 24 hours to catch deletions and metadata changes
  • Concurrent sync - up to 5 parallel project syncs for large portfolios
  • Local SQLite read model - fast queries, offline resilience, zero external DB dependencies

Policy Engine

  • Deterministic evaluation - pure functions, no side effects, fully testable
  • Configurable thresholds - max critical, max high, max medium per severity
  • Finding age limits - flag findings older than N days (e.g., 30 days for critical)
  • Named policy profiles - different rules for different criticality levels (e.g., strict for business-critical)
  • Waiver management - create, revoke, and track waivers with expiry and audit trail
  • Risk acceptance - configurable per policy profile

Dashboard & Presentation

  • Server-side rendered - Jinja2 templates with vanilla JS, no framework, no build step
  • Responsive layout - works on desktop, tablet, and mobile
  • 4 themes - light, dark, midnight, and system auto-detect
  • Custom design system - CSS custom properties for tokens, severities, and branding
  • Internationalization - full i18n with locale catalogs (English, Polish)
  • Accessibility - ARIA roles, focus-visible indicators, keyboard navigation, screen reader support
  • Export - findings to CSV/JSON, dashboard to standalone HTML

Analytics

  • Trend snapshots - daily aggregates for historical analysis
  • Direction classification - improving / stable / worsening with 5% threshold
  • Configurable period - 7 to 365 days of trend data

Operations

  • Health probes - Kubernetes-ready /health/live and /health/ready
  • SSE streaming - real-time sync progress via Server-Sent Events
  • Correlation IDs - end-to-end request tracing
  • Structured logging - JSON-ready, verbose mode via CLI flag

Table of Contents


Installation

Prerequisites

  • Python 3.12+
  • Access to a Fortify SSC instance (with a valid API token)

Install from source

git clone https://github.com/polprog-tech/AppSecOne.git
cd AppSecOne
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

Install with dev dependencies

pip install -e ".[dev]"

Quick Start

1. Create your configuration file:

cp examples/config.json appsecone.json
cp examples/.env.example .env

2. Set your Fortify SSC token:

export FORTIFY_SSC_TOKEN=your-fortify-token-here

3. Validate the configuration:

appsecone validate --config appsecone.json

4. Run your first sync:

appsecone sync --config appsecone.json

5. Launch the dashboard:

appsecone serve --config appsecone.json

Open http://127.0.0.1:8090 in your browser.


Configuration

Configuration File (appsecone.json)

{
  "fortify": {
    "base_url": "https://fortify.corp.example.com/ssc",
    "token_env_var": "APPSECONE_FORTIFY_TOKEN",
    "timeout_seconds": 30,
    "max_retries": 3,
    "verify_ssl": true
  },
  "sync": {
    "interval_minutes": 30,
    "full_sync_interval_hours": 24,
    "max_concurrent": 5,
    "enabled": true
  },
  "policy": {
    "max_critical": 0,
    "max_high": 5,
    "max_open_findings": null,
    "max_age_days_critical": 30,
    "max_age_days_high": 90,
    "allow_risk_acceptance": true
  },
  "branding": {
    "title": "AppSecOne",
    "company": "Your Company",
    "primary_color": "#fb6400"
  },
  "settings": {
    "theme": "system",
    "log_level": "info",
    "host": "127.0.0.1",
    "port": 8090
  },
  "repositories": [
    {
      "slug": "web-app",
      "name": "WebApp",
      "fortify_project_name": "Corp WebApp",
      "type": "web",
      "team": "platform",
      "criticality": "high",
      "layer": "frontend"
    }
  ],
  "policy_profiles": {
    "strict": {
      "max_critical": 0,
      "max_high": 0,
      "max_medium": 10,
      "max_age_days_critical": 14,
      "max_age_days_high": 30
    }
  }
}

Environment Variables

Variable Description Default
APPSECONE_FORTIFY_TOKEN Fortify SSC API token (required) -
APPSECONE_HOST Server bind address 127.0.0.1
APPSECONE_PORT Server bind port 8090
APPSECONE_DEBUG Enable debug mode false
APPSECONE_LOG_LEVEL Log level (debug, info, warning, error) info
APPSECONE_API_KEY API key for admin endpoints (optional) -
APPSECONE_ALLOW_FRAMING Allow embedding in iframes false
APPSECONE_CORS_ORIGINS Allowed CORS origins (comma-separated) -
HTTP_PROXY Corporate HTTP proxy -
HTTPS_PROXY Corporate HTTPS proxy -
SSL_CERT_FILE Custom CA certificate bundle -

Web Server Mode

Start the web server with custom host and port:

appsecone serve --config appsecone.json --host 0.0.0.0 --port 8080 --verbose

The server provides:

  • Server-side rendered dashboard at / (Jinja2 + HTMX, no JS build step)
  • RESTful JSON API under /api/ for programmatic access
  • Health probes at /health/live and /health/ready for container orchestration
  • SSE streaming for real-time sync progress at /api/admin/sync/stream

Tip: Use --verbose to enable detailed request logging with correlation IDs for debugging.


CLI Reference

AppSecOne ships a Typer-based CLI with five commands:

Command Description Key Options
appsecone serve Start the web dashboard server --config, --host, --port, --verbose
appsecone sync Run a one-time sync from Fortify SSC --config, --verbose
appsecone evaluate Evaluate release readiness (all or one repo) --config, --repo, --verbose
appsecone validate Validate a configuration file --config
appsecone version Show AppSecOne version -

Examples

# Evaluate a single repository
appsecone evaluate --config appsecone.json --repo web-app

# Evaluate all repositories
appsecone evaluate --config appsecone.json --verbose

# Validate config before deployment
appsecone validate --config /etc/appsecone/production.json

API Reference

All JSON endpoints return {"ok": true, ...} on success and {"ok": false, "error": "..."} on failure.

Health & Status

Method Endpoint Description
GET /health/live Liveness probe - always returns 200
GET /health/ready Readiness probe - checks config, DB, sync freshness
GET /api/status System status: version, uptime, config state, last sync

Overview & Trends

Method Endpoint Description
GET /api/overview Portfolio-wide severity breakdown and readiness summary
GET /api/trends Portfolio trend data over a configurable period (?period=30)
GET /api/trends/{slug} Trend data for a single repository

Repositories

Method Endpoint Description
GET /api/repositories Paginated list with filters: type, team, readiness, search, sort_by, sort_dir
GET /api/repositories/{slug} Detail view for a single repository
GET /api/repositories/{slug}/findings Findings for a repository with severity, status, category filters

Findings

Method Endpoint Description
GET /api/findings All findings, paginated, with filters: severity, status, repository, category, search

Readiness

Method Endpoint Description
GET /api/readiness Readiness summary for all repositories
GET /api/readiness/{slug} Detailed readiness evaluation for one repository

Policies

Method Endpoint Description
GET /api/policies Default policy and all named policy profiles

Waivers

Method Endpoint Description
GET /api/waivers List all active waivers
POST /api/waivers Create a waiver (requires repository_id, severity, reason, approved_by)
DELETE /api/waivers/{waiver_id} Revoke a waiver

Sync & Admin

Method Endpoint Description
GET /api/sync-runs Sync run history (?limit=20)
POST /api/admin/sync Trigger manual sync (background task)
POST /api/admin/sync/stream Trigger sync with SSE real-time progress stream
PUT /api/admin/sync-interval Update sync interval (body: {"interval_minutes": 30})

Setup Wizard

Method Endpoint Description
POST /api/setup/test-connection Test connectivity to Fortify SSC
POST /api/setup/discover Discover projects and versions from Fortify SSC
POST /api/setup/save-config Save wizard configuration to appsecone.json

Export

Method Endpoint Description
GET /api/export/findings Export findings as CSV or JSON (?format=csv)
GET /api/export/dashboard Export current dashboard as standalone HTML

Internationalization

Method Endpoint Description
GET /api/i18n/{locale} Translation catalog for the given locale

Server-Rendered Pages

Method Endpoint Description
GET / Portfolio dashboard
GET /repo/{slug} Repository detail page
GET /findings Findings explorer with filters
GET /policies Policy & waiver management page
GET /admin Admin / system status page
GET /setup Integration setup wizard

Note: State-changing endpoints (POST, PUT, DELETE, PATCH) require a valid API key when APPSECONE_API_KEY is set. See Security.


Architecture

AppSecOne follows a clean layered architecture - the domain layer has zero I/O dependencies, the application layer orchestrates async workflows, and the web layer is a thin adapter.

Project Structure

src/appsecone/
├── __init__.py              # Version (0.1.0)
├── domain/                  # Pure domain: enums, models, policy engine
├── config/                  # JSON config loading + schema validation
├── fortify/                 # Fortify SSC integration layer
│   ├── client/              # HTTP client, auth, endpoints
│   └── mappers/             # DTO → domain mapping
├── persistence/             # SQLite DAL (repos, findings, aggregates)
├── application/             # Service layer (sync, query)
├── analysis/                # Trend analytics & historical snapshots
├── presentation/            # Jinja2 renderer, view models, theme, templates
├── web/                     # FastAPI server + middleware stack
├── cli/                     # Typer CLI commands
├── i18n/                    # Internationalization catalogs
└── shared/                  # Logging, type aliases

Design Principles

  1. Domain purity - business rules live in domain/ with zero imports from infrastructure layers.
  2. Dependency inversion - application services depend on abstractions, not concrete implementations.
  3. Local read model - Fortify SSC is the source of truth, but all reads come from a local SQLite store for speed and resilience.
  4. Server-rendered first - Jinja2 templates with HTMX for interactivity; no SPA, no JS bundler.
  5. Configuration as code - all behavior is driven by a single JSON config file + environment variables.

Layer Dependency Flow

CLI / Web  →  Application  →  Domain
                  ↓               ↑
             Persistence    Analysis
                  ↓
              Fortify (sync only)

Testing

AppSecOne has 464 tests covering domain logic, policy evaluation, API endpoints, persistence, Fortify integration, UX/UI regression, accessibility, and localization.

Run the test suite

# All tests
python3 -m pytest

# With coverage report
python3 -m pytest --cov=appsecone --cov-report=term-missing

# Unit tests only
python3 -m pytest tests/unit/

Test organization

Directory Scope What it covers
tests/unit/domain/ Unit Enums, models, value objects
tests/unit/policy/ Unit Policy engine rule evaluation
tests/unit/mappers/ Unit DTO → domain mapping (Fortify → domain)
tests/unit/presentation/ Unit Template rendering, view models, UX/UI regression
tests/unit/shared/ Unit i18n, networking, utilities
tests/unit/test_audit_regression.py Regression UX audit fixes - layout, a11y, responsive
tests/unit/test_blocker_regression.py Regression Production blocker fixes - security, data integrity

Note: Async tests run automatically via pytest-asyncio with asyncio_mode = "auto". HTTP mocking uses respx.


Security

AppSecOne ships with a six-layer middleware stack applied to every request:

Middleware Stack (execution order)

# Middleware Purpose
1 SecurityHeadersMiddleware Injects X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, CSP, XSS protection
2 RequestLoggingMiddleware Generates correlation IDs, logs method/path/status/duration for audit trails
3 RateLimitMiddleware Per-IP fixed-window: 120 req/min general, 5 req/min for /api/admin/* POST
4 CORSMiddleware Configurable origins via APPSECONE_CORS_ORIGINS, restricts methods and headers
5 CSRFMiddleware Origin/Referer validation on all state-changing requests (POST/PUT/DELETE/PATCH)
6 APIKeyMiddleware Optional HMAC-verified API key for admin endpoints via X-API-Key header

CSRF Protection

  • All state-changing methods require valid Origin or Referer matching the Host
  • Requests with X-API-Key bypass CSRF (machine-to-machine)
  • Requests without cookies bypass CSRF (no session to exploit)
  • API-style requests (Content-Type: application/json or X-Requested-With: XMLHttpRequest) are allowed
  • Health and streaming endpoints are exempt

API Key Authentication

  • Enabled when APPSECONE_API_KEY environment variable is set
  • Uses hmac.compare_digest() for timing-safe comparison (prevents timing attacks)
  • Protects all state-changing methods; GET requests are exempt
  • Returns 401 Unauthorized on invalid or missing key

Secret Handling

  • No hardcoded credentials - all secrets loaded from environment variables
  • Fortify token referenced by env var name in config (token_env_var), never stored in JSON
  • API key read from APPSECONE_API_KEY at startup
  • Token expiry validation for Fortify SSC authentication

Corporate Network (Zscaler / VPN / Proxy)

AppSecOne includes a centralized SSL context factory (shared/network.py) that automatically detects corporate CA certificates. Resolution order:

  1. SSL_CERT_FILE / REQUESTS_CA_BUNDLE env var (explicit override)
  2. certifi package (ships Mozilla CA bundle)
  3. macOS system keychain (automatic - includes corporate CAs like Zscaler)
  4. Python default

macOS / Linux - export your corporate CA bundle:

# macOS: extract certs from system keychain
security find-certificate -a -p \
  /Library/Keychains/System.keychain \
  /System/Library/Keychains/SystemRootCertificates.keychain \
  > ~/combined-ca-bundle.pem

# Add to shell profile (~/.zshrc or ~/.bashrc)
export SSL_CERT_FILE=~/combined-ca-bundle.pem
export REQUESTS_CA_BUNDLE=~/combined-ca-bundle.pem

Proxy configuration:

export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.internal.example.com

For detailed troubleshooting, see docs/troubleshooting.md.


Release Notes

See CHANGELOG.md for release history. AppSecOne follows Semantic Versioning.

Author

Created and maintained by POLPROG (@polprog-tech).


Contributing & Community

License

This project is licensed under the GNU Affero General Public License v3.0.

About

AppSecOne aggregates Fortify SSC vulnerability data, evaluates release readiness through deterministic security policies, and delivers real-time portfolio visibility with waivers, trends, and auditability.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors