Projects: Multi-Tenant Data Isolation¶
Vigolium supports project-based data isolation. Every scan record, finding, scope rule, source repo, and OAST(带外交互) interaction is tagged with a project_uuid, so multiple engagements can share 相同 database without data leaking across boundaries.
Concepts¶
- 项目 — A named container 所有 scan data. Each project has a UUID, name, description, optional access control lists, and optional 每-project config overlay.
- Default project — A built-in project (
00000000-0000-0000-0000-000000000001) created duringvigolium init. All data belongs to this project unless you specify otherwise. - 项目 config — An optional YAML overlay at
~/.vigolium/projects/<uuid>/config.yamlthat merges on top of the global config. - Access control — Projects can carry
allowed_domains(email domain patterns like@acme.com) andallowed_emails(exact addresses likealice@acme.com) to control who can access them. See Access Control below.
CLI Usage¶
Create a project¶
vigolium project create my-engagement
# Created project my-engagement
# UUID: a1b2c3d4-...
# Config: ~/.vigolium/projects/a1b2c3d4-.../config.yaml
# With a description
vigolium project create client-app --description "Q1 2026 pentest for client-app"
List projects¶
The active project is marked with *.
Set the active project¶
This exports the VIGOLIUM_PROJECT_UUID environment variable in your shell. All subsequent commands in that shell session will use this project.
View project config path¶
Manage project access¶
# Add allowed domains and emails (auto-detected)
vigolium project allow a1b2c3d4-... @acme.com @partner.io alice@external.com
# ✓ Added 2 domain(s) and 1 email(s) to project my-engagement
# Allowed domains: @acme.com, @partner.io
# Allowed emails: alice@external.com
# Mix freely — @-prefixed values go to domains, the rest to emails
vigolium project allow a1b2c3d4-... @newdomain.io bob@contractor.com
# Remove entries from both lists
vigolium project remove-access a1b2c3d4-... @partner.io alice@external.com
# ✓ Removed 2 entry/entries from project my-engagement
Readonly failsafe¶
Set VIGOLIUM_PROJECT_READONLY=true to prevent all mutating project commands (create, allow, remove-access) from the CLI. Read-only commands (list, use, config) still work.
export VIGOLIUM_PROJECT_READONLY=true
vigolium project allow a1b2c3d4-... @evil.com
# Error: project management is disabled (VIGOLIUM_PROJECT_READONLY=true)
vigolium project list
# still works
这很有用 生产环境中 or shared environments where projects should only be managed through the REST API.
Scoping Operations to a Project¶
有 several ways to scope operations to a project, listed by precedence (highest first):
| Method | Example |
|---|---|
--project-uuid flag |
vigolium scan -t https://example.com --project-uuid a1b2c3d4-... |
--project-name flag |
vigolium scan -t https://example.com --project-name my-engagement |
VIGOLIUM_PROJECT_UUID env var |
export VIGOLIUM_PROJECT_UUID=a1b2c3d4-... |
VIGOLIUM_PROJECT env var (legacy) |
export VIGOLIUM_PROJECT=a1b2c3d4-... |
| Default project | Used when no flag or env var is set |
--project-uuid and --project-name are mutually exclusive.
CLI examples¶
# Scan within a project (by UUID)
vigolium scan -t https://example.com --project-uuid a1b2c3d4-...
# Scan within a project (by name)
vigolium scan -t https://example.com --project-name my-engagement
# Ingest into a project
vigolium ingest --input urls.txt --project-uuid a1b2c3d4-...
# List findings for a project
vigolium db list findings --project-name my-engagement
# Export project data
vigolium db export --project-uuid a1b2c3d4-... -o findings.jsonl
Server API¶
When using the REST API, set the X-Project-UUID header to scope all operations to a project:
curl -X POST http://localhost:9002/api/ingest-http \
-H "Authorization: Bearer my-secret-key" \
-H "X-Project-UUID: a1b2c3d4-..." \
-H "Content-Type: application/json" \
-d '{"input_mode": "url", "content": "https://example.com"}'
If the header is omitted, 默认 project is used.
Config Merge Strategy¶
设置 is resolved in layers (later layers override earlier ones):
Built-in defaults
→ ~/.vigolium/vigolium-configs.yaml (global config)
→ ~/.vigolium/projects/<uuid>/config.yaml (project config overlay)
→ --scanning-profile flag (scanning profile)
→ CLI flags (highest precedence)
The project config file uses 相同 format as scanning profiles — a partial YAML overlay. Only the fields you specify are overridden:
# ~/.vigolium/projects/a1b2c3d4-.../config.yaml
scope:
hosts:
- "*.example.com"
scanning_pace:
concurrency: 30
rate_limit: 50
dynamic-assessment:
extensions:
enabled: true
variables:
auth_token: "Bearer project-specific-token"
Access Control¶
Projects can restrict access by email domain or exact email address using the allowed_domains and allowed_emails fields.
How it works¶
When a request includes both X-Project-UUID and X-User-Email headers, the server checks access:
- If
allowed_emailsis non-empty → the user's email must match exactly (case-insensitive). - Otherwise, if
allowed_domainsis non-empty → the user's email domain (e.g.@acme.com) must match. - If both lists are empty → the project is open to anyone.
- If
X-User-Emailis not sent → the check is skipped entirely.
Denied requests receive a 403 Forbidden response.
Managing via CLI¶
# Add domains and emails (auto-detected by format)
vigolium project allow <project-uuid> @acme.com alice@external.com
# Remove entries
vigolium project remove-access <project-uuid> @acme.com alice@external.com
Managing via API¶
# Set access lists on create
curl -X POST http://localhost:9002/api/projects \
-H "Content-Type: application/json" \
-d '{"name":"restricted","allowed_domains":["@acme.com"],"allowed_emails":["alice@ext.com"]}'
# Update access lists
curl -X PUT http://localhost:9002/api/projects/a1b2c3d4-... \
-H "Content-Type: application/json" \
-d '{"allowed_domains":["@acme.com","@partner.io"]}'
# Clear restrictions (project becomes open)
curl -X PUT http://localhost:9002/api/projects/a1b2c3d4-... \
-H "Content-Type: application/json" \
-d '{"allowed_domains":[],"allowed_emails":[]}'
# Get domain-to-project mapping (for frontend middleware)
curl http://localhost:9002/api/projects/domain-map
The domain-map endpoint returns:
{
"domains": {
"@acme.com": ["project-uuid-1", "project-uuid-2"]
},
"emails": {
"alice@ext.com": ["project-uuid-1"]
}
}
Database Isolation¶
All major data tables include a project_uuid column:
scanshttp_recordsfindingsscopessource_reposoast_interactionsscan_logs
Queries from the CLI, server API, and internal pipeline filter by 当前 project UUID. Existing databases are automatically migrated — the project_uuid column is added with 默认 project UUID as 默认 value.