No description
  • Go 96%
  • Makefile 4%
Find a file
2026-02-20 12:27:07 +02:00
cmd_delete.go initial import 2026-02-20 12:06:18 +02:00
cmd_export.go initial import 2026-02-20 12:06:18 +02:00
cmd_inspect.go initial import 2026-02-20 12:06:18 +02:00
config.yaml.example add missing files 2026-02-20 12:27:07 +02:00
db.go initial import 2026-02-20 12:06:18 +02:00
flags.go add missing files 2026-02-20 12:27:07 +02:00
go.mod add missing files 2026-02-20 12:27:07 +02:00
go.sum add missing files 2026-02-20 12:27:07 +02:00
main.go add missing files 2026-02-20 12:27:07 +02:00
Makefile add missing files 2026-02-20 12:27:07 +02:00
README.md initial import 2026-02-20 12:06:18 +02:00

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 driver
  • github.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_deletedtrue on 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 delete operations run inside a single PostgreSQL transaction. If any step fails, the entire operation is rolled back.
  • A --dry-run flag is available on all commands and prints the SQL statements that would be executed without touching the database.
  • Take a database backup before running delete in production:
    pg_dump indico > indico_backup_$(date +%Y%m%d).sql
    

Limitations & caveats

  1. 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 in uploaded_files.json by matching the storage_key values against the archive folder.

  2. 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.

  3. 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 *.* in psql before running in production.

  4. Audit log — Consider keeping an internal record (outside the Indico DB) of each GDPR deletion request and when it was fulfilled.