Add gkg_verbose_logs feature flag and propagate to GKG via headers
What does this MR do and why?
Thread a new gkg_verbose_logs ops feature flag through to the
GitLab Knowledge Graph (GKG) service so that a
middleware on the GKG side
can gate verbose / potentially-PII debug logging. The propagation uses
the same two header names that ai-assist's FeatureFlagMiddleware
already parses, so the GKG middleware can be lifted almost verbatim
from ai-assist:
x-gitlab-enabled-feature-flags- SaaS-only, a comma-separated list of flag names, populated from Rails feature flags.x-gitlab-enabled-instance-verbose-ai-logs- self-hosted boolean, sourced from the existingAi::Setting#enabled_instance_verbose_ai_logsrecord (reused, not duplicated).
Generic Headers map (Workhorse path)
Per reviewer feedback,
the Workhorse GkgServer struct uses a single generic Headers map[string]string
instead of separate JWT and per-feature fields. The Ruby layer composes all
per-call metadata (including authorization: Bearer <jwt>) into this map before
passing it to Workhorse, which forwards every entry as gRPC metadata verbatim.
This keeps the Go side policy-free and avoids future struct changes when new
headers are needed.
For the direct Ruby gRPC path, headers are built by the class method
GrpcClient.outgoing_headers and merged into auth_metadata.
Related: knowledge-graph#305 (parallel GKG-side middleware work), internal tracker dgruzd/tasks#2528.
Precedent
Mirrors Gitlab::AiGateway (ee/lib/gitlab/ai_gateway.rb):
#enabled_instance_verbose_ai_logs(line 47-49) - sameAi::Settingread#expanded_ai_logging_on_self_managed?(line 87-93) - sameGitlab::Saas.feature_available?(:gitlab_com_subscriptions)check to decide whether to send the flag-list header#public_headers(line 173-174) - same two header names, same string representation
Feature flag
| Name | gkg_verbose_logs |
| Type | ops |
| Group | group::knowledge-graph |
| Default | false |
| Rollout | TBD (see "Rollout issue" placeholder in the YAML - will be filled in once the GKG-side middleware lands) |
How to set up and validate locally
- Run a GKG service locally (or point
Gitlab.config.knowledge_graph.grpc_endpointat one). - Enable the flag:
Feature.enable(:gkg_verbose_logs)(on a SaaS-like instance). - Trigger any KG RPC, e.g. from a Rails console:
Analytics::KnowledgeGraph::GrpcClient.new.list_tools( user: User.first, source_type: Analytics::KnowledgeGraph::SourceType::REST ) - Observe the gRPC metadata on the GKG side -
x-gitlab-enabled-feature-flagsshould containgkg_verbose_logs.
For the self-hosted path:
Ai::Setting.instance.update!(enabled_instance_verbose_ai_logs: true)-> x-gitlab-enabled-instance-verbose-ai-logs: true on outgoing requests.
Changelog
Added.
Testing
Ruby (grpc_client_spec.rb): 8 new examples in a
describe 'verbose logging headers' block covering:
- SaaS + flag on -> header includes
verbose_gkg_logs - SaaS + flag off -> flag absent from header, header omitted if empty
- Self-managed -> flag-list header not sent at all (parity with
expanded_ai_logging) - Instance setting
true/false/nil-> corresponding header values - Future-flag append safety (existing flag names preserved)
Ruby (workhorse_spec.rb): 2 new examples verifying the verbose logging
headers flow end-to-end through send_orbit_query into the unified headers map.
Go (sendquery_test.go): TestBuildOutgoingContext (5 cases) and
TestInjectHeaders (integration test) covering the generic headers map
forwarding in Workhorse.
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
- I've followed the style guide.
- I've added unit tests.
- I've tested locally against a running GKG instance.
- I've verified the feature flag follows the feature-flags guidelines.
- I've confirmed this is EE-only (Knowledge Graph is EE).