pg_timetable stores task-time credentials (SMTP passwords, remote-database connection strings, PROGRAM tokens) as plaintext in timetable.parameter.value and timetable.task.database_connection, and persists parameter values verbatim to timetable.execution_log.params, to scheduler debug logs, and — at debug level — to the timetable.log table via the pgx query tracer.
This issue proposes a Postgres-native, GitHub-Actions-shaped secret store (timetable.secret), a ${secret:name} reference syntax resolved by the scheduler in-process immediately before use, and the mandatory masking changes that make the store meaningful rather than theater.
The reference point is GitHub Actions repository secrets, not a general-purpose vault:
| GitHub Actions secrets |
pg_timetable equivalent |
Settings → Secrets and variables |
timetable.secret catalog table |
${{ secrets.SMTP_PASSWORD }} in workflow YAML |
"password": "${secret:smtp_main}" in task parameters |
| Write-only (value not readable back) |
No plaintext SELECT path; decryption only via timetable.resolve_secret() with the key |
Masked in run logs (***) |
Reference form persisted to execution_log.params; resolved values kept out of all logs |
| No rotation/versioning/leasing |
Same — deliberately absent |
| Scoped to repo or org |
Scoped to exactly one client_name |
pg_timetable stores task-time credentials (SMTP passwords, remote-database connection strings, PROGRAM tokens) as plaintext in
timetable.parameter.valueandtimetable.task.database_connection, and persists parameter values verbatim totimetable.execution_log.params, to scheduler debug logs, and — at debug level — to thetimetable.logtable via the pgx query tracer.This issue proposes a Postgres-native, GitHub-Actions-shaped secret store (
timetable.secret), a${secret:name}reference syntax resolved by the scheduler in-process immediately before use, and the mandatory masking changes that make the store meaningful rather than theater.The reference point is GitHub Actions repository secrets, not a general-purpose vault:
Settings → Secrets and variablestimetable.secretcatalog table${{ secrets.SMTP_PASSWORD }}in workflow YAML"password": "${secret:smtp_main}"in task parametersSELECTpath; decryption only viatimetable.resolve_secret()with the key***)execution_log.params; resolved values kept out of all logsclient_name