- Go 96%
- Makefile 4%
| cmd_delete.go | ||
| cmd_export.go | ||
| cmd_inspect.go | ||
| config.yaml.example | ||
| db.go | ||
| flags.go | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| Makefile | ||
| README.md | ||
indico-gdpr
A command-line tool written in Go to help Indico administrators fulfill GDPR "right to erasure" (Article 17) and "right of access" (Article 15) requests for their Indico instances.
Features
| Command | What it does |
|---|---|
inspect |
Prints a summary of all data held for a user |
export |
Exports all personal data as JSON files into a folder |
delete |
Anonymizes (or hard-deletes) all personal data for a user |
Every destructive command supports --dry-run to preview SQL before touching
the database.
Build
go mod tidy
go build -o indico-gdpr .
Requires Go 1.21+ and the following dependencies (fetched automatically):
github.com/lib/pq— PostgreSQL drivergithub.com/spf13/cobra— CLI framework
Usage
Global flags
--dsn PostgreSQL DSN (required for all commands)
--dry-run Preview changes without modifying the database
inspect — view all data for a user
# By numeric user ID
indico-gdpr --dsn "postgres://indico:password@localhost/indico?sslmode=disable" \
inspect 1234
# By email address
indico-gdpr --dsn "..." inspect alice@example.com
Sample output:
=== USER ACCOUNT ===
ID: 1234
Email: alice@example.com
Name: Alice Smith
Affiliation: CERN
Phone: +41 22 767 0000
Deleted: false
Admin: false
=== EMAILS ===
alice@example.com (primary)
alice.smith@cern.ch
=== DATA SUMMARY ===
ABSTRACTS SUBMITTED: 3
CONTRIBUTIONS (as person link): 12
REGISTRATIONS: 7
ATTACHMENTS UPLOADED: 4
EVENT PERSONS: 9
EDITING REVISIONS: 1
SURVEY SUBMISSIONS: 2
EVENT LOG ENTRIES: 88
IDENTITY PROVIDERS: 1
AGREEMENTS: 3
BLOCKINGS CREATED: 0
ROOM BOOKINGS: 5
export — export personal data to a folder
indico-gdpr --dsn "..." export alice@example.com --output ./gdpr-exports
# Dry run (shows what would be exported without writing files)
indico-gdpr --dsn "..." --dry-run export alice@example.com
Creates a folder like ./gdpr-exports/user_1234_alice_example.com/ containing:
account.json
emails.json
registrations.json
abstracts.json
contributions.json
uploaded_files.json
event_persons.json
room_bookings.json
survey_submissions.json
You can send this folder to the data subject as a ZIP archive to satisfy an Article 15 (access) request.
delete — anonymize or delete personal data
Always run with --dry-run first.
Default mode: anonymization (GDPR-safe, preserves data integrity)
# Dry run first
indico-gdpr --dsn "..." --dry-run delete alice@example.com
# Then execute (will prompt for confirmation)
indico-gdpr --dsn "..." delete alice@example.com
# Skip interactive confirmation (for scripting)
indico-gdpr --dsn "..." delete --yes alice@example.com
Anonymization replaces all PII with:
- Name →
GDPR DELETED - Email →
gdpr-deleted-<id>@localhost.invalid - Affiliation, phone, address → empty string
is_deleted→trueon the users row- Identities (passwords, SSO, LDAP) → deleted
- API keys → deleted
- Registration field answers → emptied
Event records (contributions, timetable slots) are preserved with anonymized person links, so event programmes remain coherent.
Hard-delete mode: full row removal
indico-gdpr --dsn "..." delete --hard-delete alice@example.com
In addition to anonymization, this also removes rows for:
- Registrations
- Abstracts (soft-delete flag set)
- Survey submissions
- Room bookings
⚠️ Hard-delete may break foreign key integrity if Indico's cascades are not set. Test on a staging database first.
What data is processed
The tool covers the following Indico PostgreSQL schemas and tables:
| Schema | Tables touched |
|---|---|
users |
users, emails, identities, api_keys, settings, group_members, favorite_*, data_export_requests |
events |
persons, event_role_members, agreements, logs |
event_registration |
registrations, registration_data |
event_abstracts |
abstracts, abstract_person_links |
event_contributions |
contribution_person_links |
event_editing |
revisions, revision_comments, editables |
event_surveys |
submissions |
event_notes |
revisions |
roombooking |
reservations |
categories |
category_role_members |
Safety
- All
deleteoperations run inside a single PostgreSQL transaction. If any step fails, the entire operation is rolled back. - A
--dry-runflag is available on all commands and prints the SQL statements that would be executed without touching the database. - Take a database backup before running
deletein production:pg_dump indico > indico_backup_$(date +%Y%m%d).sql
Limitations & caveats
-
File system materials — Indico stores uploaded files under
/opt/indico/archive. This tool does not delete those files. After running the database export/delete, you should also identify and remove files whose metadata appears inuploaded_files.jsonby matching thestorage_keyvalues against the archive folder. -
Plugin data — Third-party Indico plugins may store user PII in additional tables not covered here. Audit your plugins and extend the tool as needed.
-
Indico version compatibility — This tool targets the Indico 3.x schema. The schema names and column names were derived from the Indico master branch source code. Verify against your actual schema using
\dt *.*inpsqlbefore running in production. -
Audit log — Consider keeping an internal record (outside the Indico DB) of each GDPR deletion request and when it was fulfilled.