This Python script retrieves container inventory data from a Qualys subscription account using the Qualys Container Security API.
It automatically organizes and exports container data in JSON and CSV formats, grouped by weekly date ranges.
- Fetches container data from Qualys
/csapi/v1.3/containers/list - Exports data to two directories:
weekly_reports/→ JSON (includes empty weeks)weekly_csv_reports/→ CSV (only weeks with data)
- Automatically skips previously fetched weeks
- Supports date ranges, filters, and custom CSV columns
- Includes detailed logging and error handling
| Directory | Purpose |
|---|---|
weekly_reports/ |
Stores all weekly JSON files (even empty ones). |
weekly_csv_reports/ |
Stores weekly CSVs only when data exists. |
temp_reports/ |
Temporary storage for JSON files before moving to final directory. |
logs/ |
Contains runtime logs for each script execution. |
The script uses environment variables only for authentication and configuration — no hardcoded fallback tokens.
Before running, set the QUALYS_TOKEN environment variable:
export QUALYS_TOKEN="your_qualys_access_token_here"<<<<<<< HEAD
You can find it in Qualys UI → Configurations → Access Token.
If both an environment token and in-script token exist:
- The environment token is used first.
=======
You can find it in Qualys UI → Container Security → Configuration → API Access Token.
If the token is missing or invalid, the script exits immediately with an error.
You can provide the Qualys API Gateway URL either:
python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.comexport QUALYS_GATEWAY="https://gateway.qg2.apps.qualys.com"
python3 weeklycontainerreport.py --base_url_envIf the QUALYS_GATEWAY variable is missing while using --base_url_env, the script exits with an error.
export QUALYS_TOKEN="your_api_token_here"
export QUALYS_GATEWAY="https://gateway.qg2.apps.qualys.com"
python3 weeklycontainerreport.py --base_url_env✅ This setup is ideal for CI/CD pipelines, cron jobs, or secure automated runs — no secrets appear in command history or source files.
| Variable | Required | Description |
|---|---|---|
QUALYS_TOKEN |
✅ | Bearer token for Qualys API authentication |
QUALYS_GATEWAY |
⚙️ Optional | API Gateway base URL (used when --base_url_env flag is set) |
5073605 (No token hardcoding in the script, it will be called from the environmental variable)
⚙️ Note: The first argument is always the Qualys Gateway URL for your platform (see table below).
Example gateway:https://gateway.qg2.apps.qualys.com
python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.comFetches container data for the past year using default columns and date ranges.
python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.com --start_date 2025-09-27 --end_date 2025-10-04python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.com --start_date 2025-09-27 --end_date 2025-10-04 --optional_filter "state:RUNNING and imageId:d1a50f311f32"python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.com --csv_columns "containerId,uuid,name,state,vuln_qid,vuln_software_names"python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.com --start_date 2025-10-22 --end_date 2025-10-25 --optional_filter "state:RUNNING and imageId:d1a50f311f32" --csv_columns "containerId,uuid,name,state,vuln_qid,vuln_software_names"When using the --csv_columns flag, only the following column names are supported.
Custom column sets must be chosen from this list (you can specify any subset, comma-separated):
# Container identity & status
containerId, uuid, name, state, ipv4, ipv6,
created, updated, stateChanged, riskScore, qdsSeverity, maxQdsScore,
imageId, imageSha, imageUuid, customerUuid, privileged, isRoot,
isVulnPropagated, source, sensorUuid,
# Host / cluster info
host.sensorUuid, host.hostname, host.ipAddress,
cluster.name, cluster.uid, cluster.version,
cluster.k8s.pod.name, cluster.k8s.pod.namespace, cluster.k8s.pod.uuid,
cluster.k8s.pod.controller[0].name, cluster.k8s.pod.controller[0].type,
hostArchitecture,
# Runtime context
environment, command, arguments,
# Vulnerability fields (one row per QID)
vuln_qid, vuln_firstFound, vuln_lastFound, vuln_typeDetected, vuln_scanTypes,
# From vulnerability.software[] (joined if multiple)
vuln_software_names, vuln_software_versions, vuln_software_fixVersions, vuln_software_packagePaths
Example:
python3 weeklycontainerreport.py https://gateway.qg2.apps.qualys.com --csv_columns "containerId,name,state,vuln_qid,vuln_software_names"If a column outside this list is provided, it will appear as blank in the CSV output.
| Error Type | Script Behavior |
|---|---|
| 401 / 403 Unauthorized | Exits immediately with error |
| JWT Parsing Failed | Treated as token error, exits |
| Empty Data Week | JSON created, CSV skipped |
| Invalid Dates | Graceful error message and exit |
| Duplicate Week | Skipped automatically |
- Python 3.8+
- Internet access to Qualys API
- Modules:
requests,tzlocal
Install dependencies:
pip install requests tzlocal| Feature | Description |
|---|---|
| API | /csapi/v1.3/containers/list |
| Formats | JSON + CSV |
| Token Handling | Environment-only |
| Date Range | Weekly batching |
| Custom Columns | Supported |
| Filters | Supported |
| Logging | Detailed logs in logs/ |
Below is a list of Qualys API Gateway URLs by platform.
You must pass the correct gateway URL for your Qualys subscription region as the first argument to the script, or through the environment variable when using --base_url_env.
This script provides a reliable, incremental way to extract and analyze Qualys container security data, ensuring that weekly history is preserved and redundant downloads are avoided.