Skip to content
Notifications
Clear all

Check out my script for cleaning up orphaned evidence files

3 Posts
3 Users
0 Reactions
4 Views
(@crm_hopper_2027)
Reputable Member
Joined: 2 months ago
Posts: 133
Topic starter   [#12400]

Another year, another compliance platform. This time it's Hyperproof, and while the core framework is solid, the evidence management layer has that familiar, bloated feel of a feature built by committee. Specifically, the "orphaned file" problem.

You know the drill: you upload a file as evidence for a control, then someone re-evaluates the workflow, the control requirement changes, or you simply unlink it. The file, however, persists in the evidence repository forever. Over two quarters, this left us with over 400 "orphaned" evidence files. Not a storage cost issue per se, but a nightmare for audit readiness and general hygiene. The UI offers no bulk cleanup for this. Of course.

After the third support ticket that went nowhere useful, I built a script to handle it. It uses the Hyperproof API to enumerate all evidence files, cross-references them against currently linked control IDs, and archives the orphans. It's not a one-click solution—Hyperproof's API is, let's say, *deliberately paced*—but it works.

You'll need:
* A service account in Hyperproof with Admin rights.
* The `requests` library.
* A considerable amount of patience for pagination.

The basic workflow:

1. **Fetch all evidence items.** This is the longest pole. The endpoint is `GET /api/v1/evidence-items`. You'll need to loop through pages and pull down the `id`, `linkedControlIds`, and `fileId` for each.

2. **Build a set of all currently valid control IDs.** You can get these from `GET /api/v1/controls`. This is your "allow list."

3. **Identify orphans.** Iterate through your evidence items. If `linkedControlIds` is empty **or** none of the IDs in that array exist in your current control ID set, that evidence item is an orphan. Add its `fileId` to a removal list.

4. **Archive the files.** For each orphaned `fileId`, call `DELETE /api/v1/files/{fileId}`. This doesn't permanently delete but moves it to the archive, which is sufficient for cleaning up the active evidence view.

Major caveats:
* This does **not** handle evidence linked to tasks, only direct control links. Adjust if your workflow differs.
* The script must handle rate limiting (429 responses). I added a simple exponential backoff.
* Always, **always** run this in a test environment first or against a small, manually identified subset. You don't want to explain to your CISO why all your evidence vanished.

The result? A clean evidence library that actually reflects reality. It's absurd that this needs a custom script, but here we are. I've moved from Salesforce to HubSpot to this, and the pattern is constant: platforms excel at accumulation, but they treat systematic cleanup as an afterthought. This script just restores a bit of sanity.



   
Quote
(@carlj)
Trusted Member
Joined: 5 days ago
Posts: 62
 

Your point about the API being "deliberately paced" is the understatement of the year. I've scripted similar cleanup routines and the pagination, combined with the rate limiting, makes this a genuinely slow batch job. You'll want to implement exponential backoff and local caching of the control ID list to avoid hammering the endpoints unnecessarily on each run.

A critical caveat you didn't mention: the script's safety depends entirely on the fidelity of the API's `evidenceFiles` and `controls` endpoints being in perfect sync. Before you archive anything en masse, run a dry-fetch to log the orphan list and manually spot-check a dozen. I've seen APIs where a recently unlinked file remains listed as active for a few minutes, creating a race condition.

For anyone implementing this, also consider the audit trail. Hyperproof likely logs the API call that archives the file, but you should augment your script to generate a manifest (CSV with file ID, original name, date archived) and store it as an artifact. An auditor will ask how you determined what was "orphaned," and "a Python script" is not a sufficient answer without the supporting evidence.


Trust but verify.


   
ReplyQuote
(@gregoryp)
Estimable Member
Joined: 7 days ago
Posts: 65
 

You're absolutely right about the need for an immutable audit manifest. I'd take that a step further and suggest the manifest should be stored in the same compliance platform as a piece of evidence itself, linking to the cleanup procedure's control. This creates a closed loop an auditor can follow.

On the topic of API sync, I've observed a similar lag, though in my case it was closer to 30 minutes. A pragmatic mitigation is to run the orphan identification logic, then introduce a mandatory delay before the archival phase. Treating the two as separate, scheduled jobs with a buffer period significantly reduces the risk.

Implementing local caching for controls is essential, but don't forget to version that cache. If a control is deleted between your script's runs, you'll need to differentiate between a truly missing control and a caching artifact. A simple timestamp file can solve this.


infra nerd, cost hawk


   
ReplyQuote