Skip to content

fix: mask write-only credentials in debug logs [ENG-9372] - #259

Merged
wgrant merged 1 commit into
mainfrom
wgrant/fix/mask-credentials-in-debug-logs
Oct 22, 2026
Merged

wgrant merged 1 commit into
mainfrom
wgrant/fix/mask-credentials-in-debug-logs

Conversation

@wgrant

@wgrant wgrant commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

ENG-9372

what

at TF_LOG=DEBUG or TRACE the API client logs whole GraphQL request bodies, including write-only credentials; mask them

  • mutations that send a credential register it with tflog.MaskLogStrings on the request context, through a maskSecrets helper that also masks its JSON-encoded form
  • the logging transport logs through the request's context rather than the one it was built with, so the masking applies (the client no longer takes a context)
  • covers every write-only credential: account and binding security contexts, Azure and GCP discovery credentials, the Datadog keys, repository auth, and the Email, Jira, ServiceNow, Slack and Symphony profiles

#257 adds the Anthropic integration's admin key; whichever of the two lands second adds ctx = maskSecrets(ctx, input.AdminKey) to its upsert

why

debug logs are often shared when reporting problems, and shouldn't carry credentials

testing

unit test capturing the provider's debug logs for a Datadog update, asserting both keys appear only masked, including one JSON-encoding escapes; existing tests pass

docs

none needed

[ENG-9372](https://stacklet.atlassian.net/browse/ENG-9372)

### what

at `TF_LOG=DEBUG` or `TRACE` the API client logs whole GraphQL request bodies, including write-only credentials; mask them

- mutations that send a credential register it with `tflog.MaskLogStrings` on the request context, through a `maskSecrets` helper that also masks its JSON-encoded form
- the logging transport logs through the request's context rather than the one it was built with, so the masking applies (the client no longer takes a context)
- covers every write-only credential: account and binding security contexts, Azure and GCP discovery credentials, the Datadog keys, repository auth, and the Email, Jira, ServiceNow, Slack and Symphony profiles

#257 adds the Anthropic integration's admin key; whichever of the two lands second adds `ctx = maskSecrets(ctx, input.AdminKey)` to its upsert

### why

debug logs are often shared when reporting problems, and shouldn't carry credentials

### testing

unit test capturing the provider's debug logs for a Datadog update, asserting both keys appear only masked, including one JSON-encoding escapes; existing tests pass

### docs

none needed
@wgrant
wgrant requested a review from a team as a code owner October 22, 2026 06:01

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 11 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant Provider as Terraform Provider
    participant API as API Client (api package)
    participant Mask as maskSecrets Helper
    participant LogCtx as Request Context with Log Masking
    participant Transport as logTransport
    participant HTTP as HTTP Transport
    participant Server as GraphQL API Server
    participant Logs as Debug Logs

    Note over Provider,Server: Credential Masking in Debug Logs Flow

    Provider->>API: Call mutation (e.g., Datadog Update)
    API->>API: Build GraphQL mutation with input
    
    Note over API,Mask: NEW: Register secrets for masking
    API->>Mask: maskSecrets(ctx, secrets...)
    Mask->>Mask: Check nil/empty secrets
    alt Has secrets to mask
        Mask->>Mask: JSON-encode each secret
        Mask->>Mask: Collect raw + encoded values
        Mask->>LogCtx: Create tflog.MaskLogStrings context
        LogCtx-->>API: Return masked context
    else No secrets to mask
        Mask-->>API: Return original context
    end
    
    API->>API: Assign masked context to request
    
    API->>Transport: Mutate(maskedCtx, mutation, variables)
    Transport->>Transport: Log request with masked context
    LogCtx->>Transport: Apply masking rules
    Transport->>HTTP: Send HTTP request
    
    HTTP->>Server: GraphQL request with credentials
    Server-->>HTTP: GraphQL response
    
    HTTP-->>Transport: Return response
    Transport->>Transport: Log response with masked context
    LogCtx->>Transport: Apply masking rules
    
    Note over Transport,Logs: NEW: Credentials appear as "***"
    Transport->>Logs: Write debug log entries
    Logs-->>Logs: Masked request/response bodies
    
    Transport-->>API: Return response
    API-->>Provider: Return result
Loading

Re-trigger cubic

@albertodonato albertodonato left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

@wgrant
wgrant merged commit 5c9d755 into main Oct 22, 2026
4 checks passed
@wgrant
wgrant deleted the wgrant/fix/mask-credentials-in-debug-logs branch October 22, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants