This Python script resolves activity UUIDs and removes SecureFlag user assignments through APIs. Note: if an activity was assigned and it has been solved, it cannot be removed and will be marked as solved. Important: Once an activity has been unassigned, it cannot be undone and needs to be reassigned via the management UI or the assignment APIs.
- Fetches fresh catalogs every run:
Learning-Path-Data.csvfrom/pathsLab-Exercise-Data.csvfrom/exercises(includes all exercise types and an extraTypecolumn fromlabType)
- Resolves/validates UUIDs in your input CSV (strict exact match by Activity + Technology when UUID is blank).
- Performs a preflight over the entire input:
- Halts if any row is invalid (prints errors and exits
1).
- Halts if any row is invalid (prints errors and exits
- Batch removals per user, performing one API request for each user.
- Prints a concise, per-user summary and "Completed successfully." on success.
Python version 3.8 or higher is required.
-
Save the script (e.g., as
remove_activities.py). -
Install dependencies:
pip install requests
-
Setup Authentication: The script requires a Bearer Token for API authentication
Refer to our help center for instructions on obtaining your Bearer Token.
Headers (exact, in order):
User(email)Activity(Path name or Lab title)TechnologyType(PathorLab)UUID(optional; blank allowed)
Accepts both Unix \n and Windows \r\n line endings.
This data can be obtained from the Track Progress Report in the platform (see more details here). When working with the report, use columns 2–5, which share the same headers.
If you plan to use the report, ensure that you include only activities that do not have the status “Solved” or “Already Solved”
-
Learning-Path-Data.csv
Columns:Name of LP,Technology,UUID -
Lab-Exercise-Data.csv
Columns:Name of Lab,Technology,UUID,Type
(Typecomes fromlabTypeas returned) -
<input>-resolved.csv
A resolved copy of your input CSV. Always overwritten.-resolvedis inserted before.csv
GET https://api.secureflag.com/rest/management/v2/pathsGET https://api.secureflag.com/rest/management/v2/exercisesPOST https://api.secureflag.com/rest/management/v2/users/removeAssignment
Headers:
Authorization: Bearer <TOKEN>Accept: application/jsonContent-Type: application/json(POST only)
Timeout: 30s per request.
- Verifies the UUID exists in the corresponding catalog (if UUID is present). Path vs Lab catalogs apply.
- Resolves using a strict exact match (If UUID is blank):
Activity==Name of LPandTechnology(forType = Path)Activity==Name of LabandTechnology(forType = Lab)
- Comparisons are case-sensitive and space-sensitive (no trimming/normalization).
- Fails with a preflight error and halts execution (if zero or multiple name + tech matches are found).
Typemust be exactlyPathorLab(otherwise halts execution).- Duplicate rows are not fatal; removals are deduplicated by: user + type + UUID.
Processes one POST request per user, including both arrays if present:
{
"users": ["user@example.com"],
"assignedLabs": ["..."], // omit if empty
"assignedPaths": ["..."] // omit if empty
}Common issues:
- Fails with a preflight error and halts execution (if a user has neither labs nor paths after deduplication).
- Fails with a preflight error and halts execution (if HTTP 200 is returned but the response body indicates a partial failure).
- Fails fast and logs the body (no retries).
python remove_activities.py --token YOUR_TOKEN --csv customer1-to-remove.csvOptional Flags:
--dry-run— validate and show intended actions, no POSTs--verbose— detailed logs (resolutions, payloads, bodies)
Examples:
# dry-run + verbose
python remove_activities.py --token YOUR_TOKEN --csv customer1-to-remove.csv --dry-run --verbose- Prints startup banner.
- On success: per-user summaries and "Completed successfully." → exit code
0. - On error: prints aggregated reasons (format:
User + UUID + reason) → exit code1.
User,Activity,Technology,Type,UUID
(UUID column may be omitted in the input; it will appear in the -resolved.csv.)
- Catalog filenames are fixed. They're regenerated fresh each run.
- Input file must use lowercase
.csvextension.