TAP version 13
# Subtest: verifyGateIdentityToken
    # Subtest: returns the identity for a valid token
    ok 1 - returns the identity for a valid token
      ---
      duration_ms: 11.112017
      type: 'test'
      ...
    # Subtest: omits optional claims as nulls
    ok 2 - omits optional claims as nulls
      ---
      duration_ms: 2.560639
      type: 'test'
      ...
    # Subtest: rejects a wrong audience
    ok 3 - rejects a wrong audience
      ---
      duration_ms: 4.916703
      type: 'test'
      ...
    # Subtest: rejects a wrong issuer
    ok 4 - rejects a wrong issuer
      ---
      duration_ms: 1.601333
      type: 'test'
      ...
    # Subtest: rejects an expired token
    ok 5 - rejects an expired token
      ---
      duration_ms: 11.28094
      type: 'test'
      ...
    # Subtest: rejects a token without exp
    ok 6 - rejects a token without exp
      ---
      duration_ms: 2.384442
      type: 'test'
      ...
    # Subtest: rejects a token signed by a different key with the same kid
    ok 7 - rejects a token signed by a different key with the same kid
      ---
      duration_ms: 2.762894
      type: 'test'
      ...
    # Subtest: refetches the JWKS when the kid rotates
    ok 8 - refetches the JWKS when the kid rotates
      ---
      duration_ms: 4.060333
      type: 'test'
      ...
    1..8
ok 1 - verifyGateIdentityToken
  ---
  duration_ms: 42.343915
  type: 'suite'
  ...
# Subtest: gateIdentityFromHeaders
    # Subtest: verifies the header token end to end and fails closed without it
    ok 1 - verifies the header token end to end and fails closed without it
      ---
      duration_ms: 20.46475
      type: 'test'
      ...
    # Subtest: activates on a deployed-shaped request without GROK_GATE_ORIGIN
    ok 2 - activates on a deployed-shaped request without GROK_GATE_ORIGIN
      ---
      duration_ms: 3.489428
      type: 'test'
      ...
    # Subtest: verifies a preview-audience token with no gate env vars via the loopback default
    ok 3 - verifies a preview-audience token with no gate env vars via the loopback default
      ---
      duration_ms: 2.968839
      type: 'test'
      ...
    # Subtest: rejects a wrong-issuer token in the loopback default mode
    ok 4 - rejects a wrong-issuer token in the loopback default mode
      ---
      duration_ms: 2.253496
      type: 'test'
      ...
    # Subtest: verifies a preview-audience token when only GROK_GATE_ORIGIN is set
    ok 5 - verifies a preview-audience token when only GROK_GATE_ORIGIN is set
      ---
      duration_ms: 1.898686
      type: 'test'
      ...
    # Subtest: rejects a preview-audience token when GROK_PROJECT_ID is set
    ok 6 - rejects a preview-audience token when GROK_PROJECT_ID is set
      ---
      duration_ms: 2.33634
      type: 'test'
      ...
    # Subtest: rejects an app-audience token in preview mode
    ok 7 - rejects an app-audience token in preview mode
      ---
      duration_ms: 2.358189
      type: 'test'
      ...
    1..7
ok 2 - gateIdentityFromHeaders
  ---
  duration_ms: 36.426141
  type: 'suite'
  ...
# Subtest: gateIdentityEnabled
    # Subtest: is enabled by default with no gate env vars
    ok 1 - is enabled by default with no gate env vars
      ---
      duration_ms: 0.14143
      type: 'test'
      ...
    # Subtest: is disabled when VITE_AUTH_ENABLED is false
    ok 2 - is disabled when VITE_AUTH_ENABLED is false
      ---
      duration_ms: 0.129889
      type: 'test'
      ...
    1..2
ok 3 - gateIdentityEnabled
  ---
  duration_ms: 0.374855
  type: 'suite'
  ...
# Subtest: gateTokenAudience
    # Subtest: pins app:<id> when GROK_PROJECT_ID is set, even alongside GROK_GATE_ORIGIN
    ok 1 - pins app:<id> when GROK_PROJECT_ID is set, even alongside GROK_GATE_ORIGIN
      ---
      duration_ms: 0.224033
      type: 'test'
      ...
    # Subtest: pins preview when GROK_PROJECT_ID is unset
    ok 2 - pins preview when GROK_PROJECT_ID is unset
      ---
      duration_ms: 0.150199
      type: 'test'
      ...
    1..2
ok 4 - gateTokenAudience
  ---
  duration_ms: 0.468023
  type: 'suite'
  ...
# Subtest: gateIdentityUserInfo
    # Subtest: falls back to a synthetic email and name for sub-only claims
    ok 1 - falls back to a synthetic email and name for sub-only claims
      ---
      duration_ms: 0.15976
      type: 'test'
      ...
    # Subtest: keeps real claims, lowercasing the email and marking it verified
    ok 2 - keeps real claims, lowercasing the email and marking it verified
      ---
      duration_ms: 0.139089
      type: 'test'
      ...
    1..2
ok 5 - gateIdentityUserInfo
  ---
  duration_ms: 0.426204
  type: 'suite'
  ...
# Subtest: sessionBoundToGateIdentity
    # Subtest: keeps the session when it is bound to the same gate sub
    ok 1 - keeps the session when it is bound to the same gate sub
      ---
      duration_ms: 0.143425
      type: 'test'
      ...
    # Subtest: rotates when the session belongs to a different gate sub
    ok 2 - rotates when the session belongs to a different gate sub
      ---
      duration_ms: 0.065763
      type: 'test'
      ...
    # Subtest: rotates when the session user has no gate-bound account
    ok 3 - rotates when the session user has no gate-bound account
      ---
      duration_ms: 0.063193
      type: 'test'
      ...
    1..3
ok 6 - sessionBoundToGateIdentity
  ---
  duration_ms: 0.381132
  type: 'suite'
  ...
# Subtest: resolveSignInGateState
    # Subtest: is pending while the session check is in flight, user or not
    ok 1 - is pending while the session check is in flight, user or not
      ---
      duration_ms: 0.682491
      type: 'test'
      ...
    # Subtest: is signed_in once a user is present
    ok 2 - is signed_in once a user is present
      ---
      duration_ms: 0.13503
      type: 'test'
      ...
    # Subtest: is signed_out only after the check resolved with no user
    ok 3 - is signed_out only after the check resolved with no user
      ---
      duration_ms: 0.102568
      type: 'test'
      ...
    1..3
ok 7 - resolveSignInGateState
  ---
  duration_ms: 1.876152
  type: 'suite'
  ...
1..7
# tests 27
# suites 7
# pass 27
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 329.425446
