TraxSensitive

Marks a property, field or record parameter of a train's input or output, or of anything reachable from them, whose value must not appear in the copies Trax keeps. The train runs with the real value; only the written copy is masked.

Signature

namespace Trax.Effect.Attributes;
 
[AttributeUsage(
    AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
    AllowMultiple = false,
    Inherited = true
)]
public sealed class TraxSensitiveAttribute : Attribute
{
    public TraxSensitiveAttribute();
}

What is masked

A marked value is written as {"_redacted": true} under the same JSON name in:

CopyWritten by
The stored input and output of a runSaveTrainParameters
A junction's logged outputAddJunctionLogger
The output handed to lifecycle hooksAddLifecycleHook, the broadcaster, GraphQL subscriptions

and so everywhere those copies travel: the dashboard, the API's execution detail, logs and subscriptions.

Rules

  • Opt-in. Nothing is masked because of its name.
  • A marked member hides its whole value. An object under it is not walked; a collection is replaced whole.
  • An unmarked member is walked. A marked property on a nested object, or on each element of a collection, is masked where it sits.
  • Records. On a positional record, write the attribute on the parameter, with or without property:.
  • Inheritance. A mark on a base property, or on an interface property, applies to the override or implementation.
  • Dictionaries are not masked. Keys and values have no member to mark.

What it does not cover

The copy a train is run from keeps the real value, because the train needs it: a queued entry's input (work_queue.input) and a manifest's properties. Those are JSON strings the mark cannot reach into, so Trax keeps them out of its logs instead: a model's ToString(), the JSON effect and the junction logger write each as {"_omitted": true}. They are still readable wherever those columns are. Keep a secret out of an input where you can, and pass a reference to it instead.

Example

using Trax.Effect.Attributes;
 
public record ConnectAccountInput(
    string AccountId,
    [property: TraxSensitive] string ApiToken
) : IManifestProperties;

The run's stored input holds {"_redacted": true} where the token would be; the junctions receive the token.

Package

dotnet add package Trax.Effect