Portal Community

Allowed Telemetry Categories

CategoryAllowedConditionsExamples
Aggregated metricsYesNo individual record data in labels; no payload values in countersworkflow execution count, node duration histogram, error rate
Sanitized structured logsYesNo form field values, no computation results, no user data in message or attributesworkflow started/completed/failed, node started/completed, step count
Trace identifiersYesTraceId and SpanId only — not span names, span attributes, or span eventsTraceId for correlation; SpanId for parent linkage
Attestation reportsYesCryptographic proof only — contains measurement (code hash), not runtime dataPCR values, attestation certificate
Health check statusYesBinary healthy/unhealthy only; no detail about computation state"processengine: healthy", "db: healthy"
Error codes (not messages)YesNumeric codes or short enum-style codes without interpolated valuesE_OVERFLOW, E_TIMEOUT, E_AUTH_FAILED

Allowed Metrics: Correct Emission Pattern

// TEE-safe metric emission in BizFirstGO process engine
// CORRECT: Aggregated counts and durations — no payload data

// Workflow execution counter — labels: tenant (hashed), outcome, node_type
// NOT: tenant=acme-corp (company name is sensitive in TEE context)
// YES: tenant=t_8f3a2b1c (deterministic hash of tenant ID)
_workflowExecutionsCounter.Add(1,
    new KeyValuePair<string, object?>("tenant_hash", HashTenantId(tenantId)),
    new KeyValuePair<string, object?>("outcome", "completed"),
    new KeyValuePair<string, object?>("workflow_type", workflowType));  // enum, not user data

// Duration histogram — no payload reference in any attribute
_nodeDurationHistogram.Record(elapsedMs,
    new KeyValuePair<string, object?>("node_type", "calculation"),
    new KeyValuePair<string, object?>("outcome", "success"));
// NOT: new KeyValuePair("input_range", "0-1000000")  — reveals computation class

// HIL pending count — tenant-scoped gauge
_hilPendingGauge.Set(pendingCount,
    new KeyValuePair<string, object?>("tenant_hash", HashTenantId(tenantId)));

// FORBIDDEN metric label patterns in TEE:
// "amount_bucket" = "100k-500k"    — reveals financial data class
// "applicant_id" = "usr-12345"     — individual identifier
// "form_field" = "income"          — reveals what was computed
// "result" = "approved"            — reveals computation outcome (if sensitive)

Allowed Logs: Correct Sanitization Pattern

// TEE-safe log emission
// CORRECT: Operational context only — no payload data

// Workflow lifecycle events
_logger.LogInformation("Workflow started. executionId={ExecutionId} workflowType={WorkflowType} tenantHash={TenantHash}",
    executionId,      // GUID — no payload encoded
    workflowType,     // enum string — not user-supplied data
    HashTenantId(tenantId));  // hashed — not the actual tenant name

_logger.LogInformation("Node completed. executionId={ExecutionId} nodeType={NodeType} durationMs={DurationMs}",
    executionId,
    nodeType,
    elapsedMs);   // duration — operational, not payload

_logger.LogError("Node failed. executionId={ExecutionId} nodeType={NodeType} errorCode={ErrorCode}",
    executionId,
    nodeType,
    "E_CALCULATION_OVERFLOW");  // error code — not the values that caused it

// FORBIDDEN log patterns in TEE:
// "Processing income={Income} for applicant={ApplicantName}"   — payload data
// "Calculation result: {Result} for form field {FieldName}"    — computation output
// "Exception: System.OverflowException: value 1500000 > max"  // value revealed in exception
// "Retrying after {StatusCode} from {ExternalServiceUrl}"     // if URL reveals data class

Allowed Trace Context: Identifiers Only

// TEE trace context: pass TraceId across boundary, keep span content inside TEE

// ALLOWED: TraceId and SpanId in log correlation fields
_logger.LogInformation("Workflow step completed. executionId={ExecutionId} traceId={TraceId} spanId={SpanId}",
    executionId,
    Activity.Current?.TraceId.ToString(),
    Activity.Current?.SpanId.ToString());

// ALLOWED: TraceId in sanitized log for correlation to in-TEE span store
// The TraceId allows: "when did this workflow run?" (correlated via in-TEE span store)
// The TraceId does NOT reveal: what the workflow computed

// FORBIDDEN: Full span data crossing the TEE boundary
// span.SetTag("income", calculationInput.Income);          // payload in span attribute
// span.SetTag("result", calculationOutput.Decision);       // computation result
// span.SetTag("applicant.name", applicant.DisplayName);    // PII

// TEE trace strategy:
// 1. Emit TraceId + SpanId in sanitized logs (allowed to cross boundary)
// 2. Store full span details in in-TEE Tempo (stays inside TEE)
// 3. External Tempo only receives: trace context propagation (W3C TraceContext header)
//    — not the span content itself

Telemetry Contract Definition Template

# TEE Observability Contract — define before first deployment
# Changes to this contract require code modification + re-attestation

ALLOWED_METRICS:
  - name: bizfirst_workflow_executions_total
    labels: [tenant_hash, workflow_type, outcome]
    forbidden_labels: [tenant_name, applicant_id, form_type, amount_range]

  - name: bizfirst_node_execution_duration_seconds
    labels: [tenant_hash, node_type, outcome]
    forbidden_labels: [input_class, result_category]

  - name: bizfirst_hil_pending_count
    labels: [tenant_hash]
    forbidden_labels: [approval_type, approver_id]

ALLOWED_LOG_FIELDS:
  - executionId        # GUID — no payload encoded
  - workflowType       # enum — not user-supplied
  - nodeType           # enum — not user-supplied
  - tenantHash         # SHA256(tenantId) — not the actual tenant identifier
  - durationMs         # operational timing — not payload
  - errorCode          # enum error code — not interpolated values
  - traceId            # GUID — correlation only
  - spanId             # GUID — correlation only
  - stepCount          # integer count — not payload values

FORBIDDEN_LOG_FIELDS:
  - Any form field name or value
  - Any computation input or output value
  - Any user identifier (name, email, ID)
  - Exception messages containing data values
  - External service responses containing data
The Telemetry Contract Is a Security Boundary

Every field that crosses the TEE boundary is a potential exfiltration vector. Define the allowed telemetry contract as a formal list before deployment. When reviewing code changes to BizFirstGO running inside a TEE, check every logging statement and metric emission point against this contract — not just by convention, but as a security review gate.