Skip to content

Data lifecycle and privacy

This page describes the data lifecycle implemented by the current BoardReadyOps repository. It is an implementation contract for operators and customers, not a privacy policy, data processing agreement, or claim that every retention and erasure workflow is complete.

Storage boundaries

GitHub Actions execution boundary

In the target-repository GitHub Actions path, source checkouts, workflow logs, and GitHub Actions artifacts remain in the customer's GitHub repository and GitHub Actions boundary. Their retention is controlled by the repository and GitHub settings, not by the BoardReadyOps control-plane database. BoardReadyOps receives normalized run results, findings, metadata, report links, and any report artifacts that the runner explicitly uploads. It does not automatically upload a source archive.

BoardReadyOps control-plane boundary

The control plane stores tenant-scoped metadata in PostgreSQL. Optional managed report artifacts are stored by the configured artifact driver. The currently implemented physical deletion worker supports ARTIFACT_STORAGE_DRIVER=local. Database backups, reverse-proxy logs, container logs, platform logs, and copies of the artifact directory are outside the application-level sweeper and must have a separate operator policy.

Customer self-hosted runner boundary

The customer self-hosted runner stores its Ed25519 identity under its configured identity directory and uses temporary source workspaces while a job runs. Temporary workspaces are removed by default. Enabling --keep-workspace deliberately retains source files for debugging and transfers responsibility for their deletion to the operator for standard-trust jobs. Safe-mode jobs always remove their temporary workspace; --keep-workspace is ignored so reduced-trust source cannot be retained by that debug option. Workspaces should not be included in general-purpose backups.

Current data lifecycle matrix

Data class Stored content and scope Current lifecycle
GitHub webhook intake Delivery and event metadata, installation/repository identifiers, a payload SHA-256 digest, bounded normalized lifecycle actions, state, timestamps, and bounded errors. BoardReadyOps does not persist the raw GitHub webhook body. Successful processing marks the row processed and normalized actions are replaced with an empty array. BOARDREADYOPS_WEBHOOK_RETENTION_DAYS defaults terminal metadata retention to 30 days. Bounded cleanup removes only processed, failed, or dead-letter rows after their persisted deadline; accepted and processing rows are not purged.
Installation and repository records GitHub installation/account identifiers and repository identity, visibility, default branch, enablement, suspension, and routing state. Installation or repository scoped. Retained until an explicit installation/repository lifecycle operation removes the parent record. No customer-facing uninstall export, erasure, or legal-hold workflow is implemented.
Logical runs, attempts, transitions, outbox, and reconciliation Commit/ref/PR metadata, run and attempt state, transition history, bounded side-effect payloads, external results, replay records, reconciliation state, and bounded errors. Repository/run scoped. BOARDREADYOPS_CONTROL_PLANE_HISTORY_RETENTION_DAYS defaults completed outbox-effect and completed reconciliation-item retention to 90 days. Bounded cleanup preserves active, dead-letter, and reconciliation-required records. Logical runs, attempts, transitions, and replay operations have no automatic age-based purge.
Findings and accepted result payloads Rule IDs, severities, messages, repository-relative paths, metrics, report links, result digests, and the raw normalized runner result payload accepted by the result contract. Run scoped. No automatic age-based purge is implemented. The result payload remains available for dashboard, replay, and publication consistency until its parent run is removed by a future retention or erasure workflow.
Artifact metadata and report objects Kind, name, role, byte count, SHA-256 digest, normalized content type, internal storage locator, optional execution-attempt binding, and optional persisted retention deadline. Artifact metadata is run scoped; tenant ownership derives through the run/repository/installation relationship and the backing object belongs to the configured artifact driver. A durable artifact row is the availability source of truth. When an artifact set is replaced by a newer accepted result, old metadata is removed transactionally and a durable deletion job is queued when the locator is no longer referenced. Local objects are then deleted asynchronously and audited. General age-based artifact expiry is not implemented, and non-local storage drivers do not yet have a physical-deletion adapter.
Audit events Privacy-bounded actor, subject, tenant dimensions, event type, timestamps, and allowlisted metadata. Installation scoped with optional repository/run/artifact/runner dimensions. Audit events are append-only: direct update and delete operations are rejected. No automatic age-based purge is implemented. Any future erasure or retention procedure must explicitly define which evidence is retained, removed, or protected by legal hold.
Runner registrations and routing policy Runner names, allowed repository scope, public verification keys/fingerprints, capabilities, heartbeat/status data, and installation/repository routing policy. Retained until disabled or removed by an installation lifecycle operation. Runner private keys are not stored in the control plane.
Runner leases, enrollment, upload capabilities, and request nonces Lease/capability state, public identifiers, timestamps, declared artifact metadata, and SHA-256 digests of bearer values. Plaintext capability, lease, enrollment, and nonce secrets are not persisted. Expired runner request nonce digests are removed periodically in bounded batches after their persisted deadline. Pending artifact upload capabilities are marked expired and unconsumed enrollment tokens are revoked after their persisted deadline in bounded batches. BOARDREADYOPS_EPHEMERAL_RECORD_RETENTION_DAYS defaults terminal artifact capability, consumed or revoked enrollment, and terminal setup-probe metadata retention to 30 days; bounded cleanup then deletes those one-time rows without deleting their durable run, finding, artifact, setup revision, or audit evidence.
Artifact deletion jobs Tenant/run identifiers, storage driver/path, reason, digest, byte count, attempts, lease state, terminal outcome, and bounded errors. Durable jobs retry transient failures, recover expired leases, and end as completed or dead-letter. Completed rows are retained as operational proof; no automatic age-based purge is implemented.

Implemented controls

Webhook minimization and retention

BoardReadyOps verifies the GitHub signature before normalization. The raw request body is used for signature verification and digest calculation but is not inserted into PostgreSQL. Successful processing clears normalized actions immediately. Dead-letter actions remain available only until the row's configured terminal retention deadline so operators can investigate or replay bounded lifecycle work. Changing BOARDREADYOPS_WEBHOOK_RETENTION_DAYS applies only to newly accepted rows and does not rewrite existing retention_until values.

Terminal ephemeral record retention

BOARDREADYOPS_EPHEMERAL_RECORD_RETENTION_DAYS defaults to 30 and accepts values from 1 through 3650 days. Each cleanup cycle derives a cutoff from the current configured value and deletes at most the configured batch size from each terminal scope with deterministic FOR UPDATE SKIP LOCKED selection. Eligible rows are uploaded, failed, expired, or revoked artifact upload capabilities; consumed or revoked runner enrollments; and completed, failed, or expired repository setup probes. Pending capabilities, active uploads, unconsumed active enrollments, and pending or dispatched probes are excluded. The cleanup logs only aggregate counts and error classes.

These rows contain one-time capability or probe history, not the durable release result. Their deletion does not remove release runs, findings, artifact metadata or objects, repository setup revisions, runner registrations, or append-only audit events. Changing the setting changes future cutoff calculations and does not rewrite timestamps already stored on rows.

Completed control-plane history retention

BOARDREADYOPS_CONTROL_PLANE_HISTORY_RETENTION_DAYS defaults to 90 and accepts values from 1 through 3650 days. Each cleanup cycle deletes bounded batches of completed outbox effects and completed reconciliation items older than the calculated cutoff. Completed outbox effects with retained reconciliation references are preserved; dead-letter and reconciliation-required records are preserved, and all available or leased records are excluded. The cleanup logs only aggregate counts and error classes; outbox payloads, external results, tenant identifiers, and reconciliation diagnostics are not logged.

This cleanup removes delivery and reconciliation history only. It does not remove logical runs, execution attempts, findings, accepted result payloads, artifacts, replay operations, transition events, or append-only audit events. Changing the setting changes future cutoff calculations and does not rewrite persisted completion timestamps.

Artifact access and replacement deletion

A dashboard download URL is bound to one run, artifact, and expiry and is accepted for at most 15 minutes. The route must also find the current artifact metadata, validate the signature, resolve a regular file inside ARTIFACT_STORAGE_ROOT, and match the stored byte count. Removing artifact metadata therefore makes an old URL unusable through the BoardReadyOps route even while a physical-deletion job is pending. Rotating the dedicated signing key invalidates all previously issued URLs.

A durable artifact row is the availability source of truth. A deployment that cannot mint a signed download URL does not make that artifact metadata-only; it means the access channel is unavailable. The explicit metadata-only runner mode emits no managed artifact row because report bytes are never uploaded to the control plane. Schema version 39 also records a normalized media type, the execution attempt when known, and an optional persisted retention deadline. That optional persisted retention deadline is metadata only until a separate lifecycle policy and deletion path enforce it; general age-based artifact expiry remains unimplemented.

For a replaced artifact, metadata deletion and deletion-job creation occur in one PostgreSQL transaction. The worker records artifact.object.deleted after the local object was removed or was already absent; the audit metadata distinguishes outcome=deleted from outcome=missing. Unsafe paths, unsupported drivers, and terminal failures are not reported as successful deletion. This behavior covers only artifacts replaced by a newer accepted result.

Run dashboard repository authorization

Public repository run dashboards remain readable from their opaque run identifier. Private repository run dashboards fail closed as not found before findings, artifacts, attempts, or transition evidence is queried. A private run can be loaded only when the calling route supplies explicit repository authorization; the current public run routes do not grant that authorization. This boundary also prevents private runs from minting signed artifact links through an unauthenticated dashboard request.

Tenant scope and auditability

Installations are the top-level tenant boundary. Repository, run, artifact, runner, replay, reconciliation, transition, and deletion records are validated against that boundary by foreign keys and scope-validation functions. Operational database records may contain finding messages, repository-relative paths, and internal artifact storage paths. Audit exports and worker telemetry intentionally omit raw source payloads, finding content, artifact names, and storage paths.

Current gaps

The current release does not provide all lifecycle controls requested by issue

44. In particular:

  • per-organization or per-repository retention settings are not implemented;
  • general age-based expiry for runs, findings, accepted result payloads, audit events, replay/transition history, or managed artifacts is not implemented;
  • an organization, repository, or user erasure workflow is not implemented;
  • an uninstall export and post-uninstall deletion workflow is not implemented;
  • a legal-hold workflow is not implemented;
  • physical deletion for object-storage drivers is not implemented; and
  • backup and platform-log expiry remain operator responsibilities.

Operators must not interpret database cascade relationships as a supported customer erasure procedure. A future erasure implementation must be tenant scoped, durable, recoverable, auditable, explicit about immutable evidence, and able to report what remains in backups or external systems.