Multi-tenant security scanning platform wrapping Amazon Security Helper
Project description
Vehlo Code Scanner
Multi-tenant security scanning platform wrapping Amazon Security Helper (ASH). Runs ASH across Vehlo's 500+ repos, centralizes findings in PostgreSQL, and surfaces them through a React dashboard with triage workflows and analytics.
Architecture
CI/CD pipeline → ASH scan → vcs CLI (--push) → POST /api/v1/scans → FastAPI + PostgreSQL → React Dashboard
Three components:
- CLI / scanner — Python package (
vcs) that wraps ASH. Supports container, local, and pre-commit modes. Outputs rich terminal tables, optionally pushes results to the central API, and can fail the build on a severity threshold. - API service — FastAPI monolith handling ingest, findings lifecycle, and analytics. Backed by PostgreSQL. Auto-resolves findings when they disappear from subsequent scans.
- Dashboard — React + Vite SPA. Overview, findings browser, per-repo drill-down, scan history, and analytics.
Quick Start
# Start all services
docker compose up
# API → http://localhost:8002
# Dashboard → http://localhost:5175
Installation
Distribution is dual-mode: a public path (PyPI + ECR Public, no AWS
account needed) and an AWS-gated path (CodeArtifact + private ECR) for
internal users. The tool itself is open to install — the API token gates
pushing results and SSO gates viewing them. The [scan] extra adds the
ASH engine (vehlo-ash, a rename-only repackaging of AWS's Apache-2.0
automated-security-helper — see packaging/vehlo-ash/); without it you still
get the CLI, --push, and the client.
Public (no AWS):
# pip from PyPI
pip install 'vehlo-code-scanner[scan]'
# Docker from ECR Public (ASH bundled, nothing else to install)
docker run --rm -v "$PWD:/src" \
public.ecr.aws/<alias>/vehlo-code-scanner:latest scan /src
AWS-gated (internal): authenticate once with aws sso login, then:
# pip via CodeArtifact (configures the index, then installs)
aws codeartifact login --tool pip \
--domain "$VCS_CA_DOMAIN" --repository "$VCS_CA_REPO"
pip install 'vehlo-code-scanner[scan]'
# Docker via ECR
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS --password-stdin "$ECR_REGISTRY"
docker run --rm -v "$PWD:/src" \
"$ECR_REGISTRY/vehlo-code-scanner:latest" scan /src
GitHub Actions (the calling job needs permissions: id-token: write):
- uses: Vehlo-CyberSec/vehlo-code-scanner@v1
with:
api-url: ${{ vars.VCS_API_URL }}
api-token: ${{ secrets.VCS_API_TOKEN }}
image: ${{ vars.VCS_ECR_IMAGE }} # full ECR URI
aws-role: ${{ secrets.VCS_AWS_ROLE }} # OIDC role with ECR pull
aws-region: ${{ vars.AWS_REGION }}
fail-on: high
ASH is git-only upstream (and its PyPI name is squatted), so
vcs scanwithout the engine prints install guidance. The container images bundle ASH; pip users get it via the[scan]extra (vehlo-ashfrom PyPI or CodeArtifact, depending on the index you install from).
For local development from a checkout:
uv tool install '.[scan]' # or: uv sync --group local-scan (ASH from git)
After installation, vcs (and vcs-admin) are available on your PATH.
Local development
# Install Python deps
uv sync
# Apply migrations
VCS_DATABASE_URL=postgresql+psycopg://vcs:<password>@localhost:5433/vcs alembic upgrade head
# (dev password: see docker-compose.yml)
# Run API
VCS_DATABASE_URL=... uvicorn vcs.api.app:create_app --factory --reload
# Run dashboard (in ./dashboard)
npm run dev
Running a scan
# Scan current directory and print results
vcs scan .
# Scan and push results to central API
VCS_API_URL=http://localhost:8002 VCS_API_TOKEN=<token> vcs scan . --push
# Fail CI if critical or high findings exist
vcs scan . --push --fail-on high
Project Structure
src/vcs/
├── api/
│ ├── routes/ # health, ingest, findings, repos, scans, overview, analytics
│ ├── services/ # ingest logic, auto-resolve
│ ├── app.py # FastAPI factory
│ ├── deps.py # DB session injection
│ └── schemas.py # Pydantic request/response models
├── models/ # SQLAlchemy ORM: org, group, user, repo, scan, finding, api_token
├── scanner/ # ASH wrapper: runner, parser, result models
├── cli/ # Typer CLI: scan command, rich output
├── client/ # HTTP client for pushing results to API
├── db.py # Database connection factory
├── enums.py # Severity, FindingStatus, etc.
└── config.py # Settings from environment
dashboard/src/
├── pages/ # Overview, Findings, FindingDetail, Repos, RepoDetail, Scans, Analytics
├── components/ # Layout, SeverityBadge, StatusBadge, Pagination, Panel, etc.
├── api/ # TanStack Query hooks
└── types.ts # TypeScript types
alembic/versions/ # Database migrations
tests/ # Unit + integration tests
Environment Variables
| Variable | Description | Default |
|---|---|---|
VCS_DATABASE_URL |
PostgreSQL connection string | required |
VCS_API_URL |
Central API base URL (CLI push) | required for --push |
VCS_API_TOKEN |
Bearer token for API auth (CLI push) | required for --push |
VCS_REDIS_URL |
Celery broker/result backend | redis://localhost:6380/0 |
VCS_S3_ENDPOINT |
S3/MinIO endpoint for raw-result archiving | http://localhost:9002 |
VCS_SESSION_SECRET |
Secret for signing dashboard session cookies | dev default (required once OIDC is configured — startup fails without it) |
VCS_CORS_ORIGINS |
Comma-separated allowed CORS origins; empty value = deny cross-origin (prod) | unset → any localhost port (dev) |
VCS_OIDC_ISSUER |
OIDC issuer URL (enables dashboard SSO) | unset → SSO disabled |
VCS_OIDC_CLIENT_ID / VCS_OIDC_CLIENT_SECRET |
OIDC client credentials | unset |
VCS_OIDC_REDIRECT_URI |
OIDC callback URL | .../api/v1/auth/callback |
VCS_OIDC_GROUPS_CLAIM |
Claim holding the user's group names | groups |
VCS_DASHBOARD_URL |
Post-login redirect target | http://localhost:5175 |
VCS_DEV_LOGIN |
Dev only — enables /api/v1/auth/dev-login (one-click local session, no IdP). Never set in prod. |
unset → disabled |
Running Tests
pytest
pytest --cov=vcs --cov-report=term-missing
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vehlo_code_scanner-0.1.1rc2.tar.gz.
File metadata
- Download URL: vehlo_code_scanner-0.1.1rc2.tar.gz
- Upload date:
- Size: 36.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f8200669de7a4c0ffa7be1f9a674b952ce6c02d22b7e3e98cdd088296d2e2d9
|
|
| MD5 |
3d7a5a1db6aa5120edd083bc9847c5ad
|
|
| BLAKE2b-256 |
05d2be32fedf0da05190eb9616fdde18cb5567f3f313bf66aa5fcccec2029fb9
|
File details
Details for the file vehlo_code_scanner-0.1.1rc2-py3-none-any.whl.
File metadata
- Download URL: vehlo_code_scanner-0.1.1rc2-py3-none-any.whl
- Upload date:
- Size: 56.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94f0f5e5d60c216d8055fdd7173e753197a90209022cf245227705befa323693
|
|
| MD5 |
29fbbf4663404dbafe1bdc6a21cd7e09
|
|
| BLAKE2b-256 |
827a0f08b635340d981f8fecd5cd149a62fd6a811a9b5c9721e201ef0a3d77c9
|