Skip to content

openshell: Layer 1 strict-mode should skip rules with unavailable PolicyContext fields #885

@IngmarVG-IB

Description

@IngmarVG-IB

Background

Spun off from PR #469 review (round 2). The Guard's Check method evaluates published policy documents as Layer 1 (caller-side, pre-connection). At that layer, PolicyContext can only be populated with CallerID, CallerDomain, and Protocol. Connection-state fields — AuthType, HasMutualTLS, TLSVersion, DNSSECValidated, CallerTrustScore, Method, Intent, GeoCountry, ConsentToken — cannot be filled in until the connection actually exists.

In ModePermissive (the default) this is fine: rules dependent on those fields produce warnings only.

In ModeStrict, however, any policy that publishes required_auth_types, require_dnssec, require_mutual_tls, min_tls_version, required_caller_trust_score, allowed_methods, allowed_intents, geo_restrictions, or consent_required will unconditionally deny because the zero value never satisfies the rule.

PR #469 documents this prominently in the Guard doc comment but stops short of the code fix.

Proposal

In pkg/openshell/evaluator.go::Evaluate, when a rule applies at the current layer but the corresponding PolicyContext field is at its zero value (i.e., we genuinely don't know the answer yet), emit a warning instead of a violation. Concretely:

  • required_auth_types with pctx.AuthType == \"\" → warning (not violation)
  • require_dnssec with !pctx.DNSSECValidated AND layer == LayerCaller → warning
  • require_mutual_tls with !pctx.HasMutualTLS AND layer == LayerCaller → warning
  • min_tls_version with empty TLSVersion → warning
  • required_caller_trust_score with nil score → warning
  • allowed_methods / allowed_intents with empty value → warning
  • geo_restrictions with empty GeoCountry → warning
  • consent_required with empty ConsentToken AND layer == LayerCaller → warning

The signal flips back to violation when (a) we're at Layer 2 with the value populated, or (b) the field is set at Layer 1 and the comparison fails for real.

Acceptance criteria

  • ModeStrict at Layer 1 against a policy that requires DNSSEC + mutual TLS no longer denies a connection that hasn't been initiated yet
  • ModeStrict at Layer 2 against the same policy still denies if the connection comes back without DNSSEC / mTLS
  • Doc-comment limitation note on Guard can be downgraded or removed
  • Table-driven test covering each rule's "unavailable field at Layer 1" path

Out of scope

  • Cap-doc fetch / DNSSEC/DANE validation / Phase 6 policy enforcement (separate roadmap items in the integration README)

Context

PR #469 review thread (round 2 follow-up by @mchmarny): #469 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for Enhancement.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions