Record authenticated caller in the decision envelope.
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m0s

FLEX-WP-0023-T04: provenance.caller is additive (mode required;
principal/audience/not_after when a token was reviewed). TokenReview
keeps the JWT exp. request_digest is unchanged because the caller is
not binding material.

Assistant: grok
Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267
This commit is contained in:
tegwick 2026-09-14 04:44:07 +02:00
parent e62c0cfc36
commit ca070df32d
15 changed files with 344 additions and 35 deletions

View file

@ -14,6 +14,7 @@ import (
"sync"
"time"
"github.com/netkingdom/flex-auth/internal/callerauth"
"github.com/netkingdom/flex-auth/internal/policy"
"github.com/netkingdom/flex-auth/internal/registry"
"github.com/netkingdom/flex-auth/pkg/api"
@ -112,7 +113,7 @@ func (e *Engine) Check(ctx context.Context, request api.CheckRequest) (api.Decis
return api.DecisionEnvelope{}, err
}
decision := e.envelope(normalized, request, expectation, facts)
decision := e.envelope(ctx, normalized, request, expectation, facts)
if err := e.recordDecision(decision); err != nil {
return api.DecisionEnvelope{}, err
}
@ -345,7 +346,7 @@ func enrichResourceRef(ref api.ResourceRef, resource api.Resource, overridden *[
return out
}
func (e *Engine) envelope(request, submitted api.CheckRequest, expectation api.DecisionExpectation, facts registryFacts) api.DecisionEnvelope {
func (e *Engine) envelope(ctx context.Context, request, submitted api.CheckRequest, expectation api.DecisionExpectation, facts registryFacts) api.DecisionEnvelope {
envelope := api.DecisionEnvelope{
RequestID: request.ID,
Effect: expectation.Effect,
@ -372,6 +373,7 @@ func (e *Engine) envelope(request, submitted api.CheckRequest, expectation api.D
PolicyVersion: e.policy.Metadata.Version,
PolicyPackageDigest: e.policy.Digest(),
RegistrySnapshotDigest: e.store.Digest(),
Caller: callerProvenance(ctx),
},
Caring: e.caringDecisionMetadata(facts.descriptor, expectation.ConformanceFindings),
}
@ -383,6 +385,22 @@ func (e *Engine) envelope(request, submitted api.CheckRequest, expectation api.D
return envelope
}
func callerProvenance(ctx context.Context) *api.CallerProvenance {
record, ok := callerauth.RecordFromContext(ctx)
if !ok {
record = callerauth.Record{Mode: callerauth.ModeDisabled}
}
out := &api.CallerProvenance{Mode: string(record.Mode)}
if record.Principal != "" {
out.Principal = record.Principal
out.Audience = record.Audience
if !record.NotAfter.IsZero() {
out.NotAfter = record.NotAfter.UTC().Format(time.RFC3339)
}
}
return out
}
func (e *Engine) recordDecision(decision api.DecisionEnvelope) error {
e.mu.Lock()
defer e.mu.Unlock()