feat(config): add the usage_data config fragment (S23 Step 1)

What

Step 1 of the S23 usage data foundation plan: the usage_data configuration fragment.

  • UsageDataConfig/GitLabStandardConfig proto messages (Config tag 14). All collector_url validation is message-level CEL gated on enabled (required-when-enabled, isUri, https outside environment: development), so a disabled section loads with every field unset.
  • Runtime conversion (usageDataFromProto) with the app_id default; an absent block yields the zero value (emission disabled, privacy-safe).
  • Commented-out config.example.yaml section.

Also patches the spec's Configuration section in the same MR (spec gap found during implementation): gitlab_standard.environment is now allow-listed (production/staging/development), mirroring the realm rule. Previously a typo like prod loaded silently and would misclassify analytics.

Spec coverage

Spec: docs/specs/S23-usage-data-collection.md

Acceptance criteria

# Criterion Tests
AC-1 Disabled/omitted section: Track and lifecycle succeed, no HTTP Config half: TestLoad_UsageData_AbsentBlockYieldsZeroValue, TestLoad_UsageData_DisabledSectionLoads. Tracker: Step 2.
AC-2 Track produces collector POST with both context schema URIs Owned by Step 2 (internal/usagedata). Not tested in this MR.
AC-3 ar_instance_version equals app.Version, not settable via Attrs Owned by Step 2. Not tested in this MR.
AC-4 correlation_id equals the request's correlation ID Owned by Step 2. Not tested in this MR.
AC-5 Out-of-enum RepositoryKind/UpstreamType drops + counts Owned by Step 2. Not tested in this MR.
AC-6 Forced gitlab_standard validation failure drops through same path Owned by Step 2. Not tested in this MR.
AC-7 Shutdown delivers queued events; bounded when unreachable Owned by Step 2. Not tested in this MR.
AC-8 Track safe under concurrent use (race test) Owned by Step 2. Not tested in this MR.
AC-9 Successful S17 create emits exactly one event; failed create none Owned by Step 5. Not tested in this MR.
AC-10 Emitter metrics under service prefix; dropped counter registered Owned by Step 3. Not tested in this MR.

Error cases

# Condition Tests
E-1 Malformed/non-https collector_url, enabled without required fields, or values outside the allow-lists: load fails TestLoad_UsageData_ValidationRejections (8 cases); boundaries pinned by TestLoad_UsageData_HTTPAllowedInDevelopment, TestLoad_UsageData_AcceptsAllowedRealms, TestLoad_UsageData_AcceptsProductionEnvironment
E-2 Collector unreachable at runtime: retry/queue/drop, Track never blocks LabKit-owned emitter internals; Track/shutdown seams owned by Step 2. Not tested in this MR.
E-3 Context validation failure: drop + counter + log Owned by Step 2. Not tested in this MR.
E-4 Track after Shutdown: no-op, reason="stopped" Owned by Step 2. Not tested in this MR.
E-5 Process exit with queued events: events lost Accepted data loss per ADR-012; deliberately untested (no falsifiable assertion).

Security considerations

# Concern Tests
S-1 No tokens, credentials, or raw PII in payloads Owned by Steps 2/5 (payload assembly). Not tested in this MR.
S-2 Props limited to ADR-012 catalog dimensions Review-enforced per spec; no automated test.
S-3 Attrs cannot carry instance version, correlation ID, or identity Owned by Step 2 (type surface). Not tested in this MR.
S-4 TLS enforced for the collector outside development TestLoad_UsageData_ValidationRejections/enabled_with_http_collector_url_outside_development, TestLoad_UsageData_HTTPAllowedInDevelopment
S-5 enabled = false guarantees nothing leaves the process Config half: TestLoad_UsageData_DisabledSectionLoads, TestLoad_UsageData_AbsentBlockYieldsZeroValue. Tracker no-op: Step 2.

Notes

  • internal/config/testdata/usage_data_happy_path.yaml supports the planned tests; the plan's Step 1 Files: entry does not list it explicitly.
  • ADR-012's collector-endpoint wording ("environment variable") predates the merged spec; handbook amendment: gitlab-com/content-sites/handbook!20410 (merged).
  • The first commit is the documented test-first --no-verify carve-out; every other commit ran the full hook chain.

Related to #272 (closed)

Merge request reports

Loading
Loading