Skip to content

POLPROG-TECH/AppSecOne

AppSecOne Security Posture & Release Readiness Intelligence

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

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

What is AppSecOne?ScreenshotsFeaturesInstallationQuick StartConfigurationAPIArchitectureTesting


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.


Contributing

Contributions are welcome! Please read our Contributing Guide before submitting a pull request.

Author

Created and maintained by POLPROG (@POLPROG).

License

AGPL-3.0 — see LICENSE

Releases

No releases published

Packages

 
 
 

Contributors