Skip to content

Projects and Repositories

Projects and repositories are the foundation of the Vega domain model. Almost every other concept — scans, findings, events — exists in the context of a repository inside a project.

Concepts

A WorkspaceProject is a workspace container. Users create projects to group related security work. A project contains one or more repositories.

A Repository is a source code target. It can be: - A Git repository specified by URL — the ingest pipeline clones it - A zip/tar archive uploaded by the user — the ingest pipeline extracts it - A GitHub repository connected via the GitHub App — the ingest pipeline fetches it

After a repository is added, it goes through an ingest pipeline (tracked by an IngestJob). Only repositories in ready state can be scanned.

See the Data Model for the full entity hierarchy.

The ingest pipeline

User adds repository
    ↓
CreateRepositoryUseCase
  ├── git URL   → set source_kind=git
  ├── zip upload → set source_kind=zip
  └── GitHub   → set source_kind=github
    ↓
EnqueueRepositoryIngestUseCase
  → write IngestJob(state=queued)
  → enqueue to SQS ingest queue (or local queue)
    ↓
RunQueuedRepositoryIngestUseCase (ingest worker)
  → claim IngestJob (state=running)
    ↓
  ├── local mode → ExecuteRepositoryIngestUseCase in-process
  └── ecs mode   → ECSRepositoryIngestRunnerLauncher.launch()
                     → vega-repo-ingest-runner ECS task
    ↓
ExecuteRepositoryIngestUseCase
  ├── git clone / zip extract / GitHub API fetch
  ├── create SourceSnapshot
  ├── store snapshot (local dir or S3)
  └── transition Repository state: creating → snapshotted → ready

Archive safety — when users upload zip archives, the backend enforces limits to prevent zip bomb attacks and path traversal exploits. See Source Ingest for details.

Use cases (projects subdomain)

The application/projects/ module exposes the following use cases:

Use case What it does
CreateWorkspaceProjectUseCase Create a new project with name and description
UpdateWorkspaceProjectUseCase Update project name or description
DeleteWorkspaceProjectUseCase Delete project (fails with 409 if repositories remain)
CreateRepositoryUseCase Add a repository (git URL, zip, or GitHub) and enqueue ingest
ListRepositoriesUseCase List repositories for a user or project
GetRepositoryUseCase Get repository details including ingest state
SetRepositoryDefaultScopeUseCase Set the default include-path scope for new scans
GetRepositoryTreeUseCase List files in the repository snapshot
GetRepositorySourceFileUseCase Read a specific file from the snapshot
ProjectCatalogFacade Aggregates project-level rollup views (scan activity, finding counts)

Route structure

Router What it handles
api/routers/projects.py WorkspaceProject CRUD; project-level scan/finding/rollup views
api/routers/repositories.py Repository CRUD; ingest control; source tree; scans; findings (large router)

Example workflow via API

# Create a project
POST /api/projects
  {"name": "My App", "description": "Payment processing service"}

# Add a repository from a Git URL
POST /api/projects/:project_id/repositories
  {"name": "backend", "source_url": "https://github.com/org/repo.git"}

# Check ingest status (poll until state = ready)
GET /api/repositories/:repo_id

# Set a scan scope
PUT /api/repositories/:repo_id/default-scope
  {"include_paths": ["src/", "lib/"]}

# Start a scan
POST /api/repositories/:repo_id/scans

# Poll scan status
GET /api/scans/:scan_id/live

# Read findings
GET /api/findings/scans/:scan_id

Ingest control

Users can retry or cancel failed ingest jobs:

Action Route Use case
Cancel POST /api/repositories/:id/cancel-ingest CancelRepositoryIngestUseCase
Retry POST /api/repositories/:id/retry-ingest RetryRepositoryIngestUseCase

Stale ingest jobs are automatically recovered by ReconcileRepositoryIngestUseCase (called by the ingest worker on each loop).

Default scope and special threat modeling

Default scope (default_scope) — a repository can have a default set of include-paths that are pre-filled when creating new scans. Set via PUT /api/repositories/:id/default-scope.

Special threat modeling — a repository can have a custom threat modeling configuration stored in special_threat_modeling_id. Accessible via GET /PUT /api/repositories/:id/special-threat-modeling.

GitHub integration

Repositories connected via the GitHub App have additional metadata fields: - github_installation_id — the GitHub App installation - github_repo_full_nameowner/repo - github_default_branch — used when no branch is specified

GitHub-connected repositories can list branches and pull requests for targeted scanning: - GET /api/github/connections/:id/repositories — list available repos - GET /api/github/connections/:id/branches — list branches for a repo - GET /api/github/connections/:id/pull-requests — list open PRs

Debugging

Repository stuck in creating or snapshotted

  1. Check API logs for ingest errors from EnqueueRepositoryIngestUseCase.
  2. If the ingest queue mode is sqs, confirm the ingest worker is running and consuming the queue.
  3. Check the IngestJob record — query payload->>'state' from the ingest_jobs table.
  4. Check the ingest runner logs in CloudWatch for git clone or archive extraction errors.

Scan not progressing after creation

  1. Check VEGA_SCAN_EXECUTION_MODE. If external or sqs, a scan worker must be running.
  2. Check the ScanRecord state — if queued, the worker hasn't claimed it yet.
  3. If running for longer than expected, the runner may have crashed silently — check CloudWatch logs.
  4. See Scan Lifecycle for the complete flow.