Bind service task HTTP input to authenticated caller before evaluation
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
parent
919ce25a37
commit
4f6946bbb3
8 changed files with 590 additions and 9 deletions
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/netkingdom/access-engine/internal/policy"
|
||||
"github.com/netkingdom/access-engine/internal/registry"
|
||||
"github.com/netkingdom/access-engine/internal/sign"
|
||||
"github.com/netkingdom/access-engine/internal/taskexecution"
|
||||
"github.com/netkingdom/access-engine/pkg/api"
|
||||
)
|
||||
|
||||
|
|
@ -153,9 +154,44 @@ func (e *Engine) decide(ctx context.Context, request api.CheckRequest) (api.Deci
|
|||
return envelope, nil
|
||||
}
|
||||
|
||||
// IsServicePilot selects the existing exact source package, never a request flag.
|
||||
func (e *Engine) IsServicePilot() bool {
|
||||
return e.policy.Metadata.ID == taskexecution.ServicePilotPackageID && e.policy.Metadata.Version == taskexecution.ServicePilotPackageVersion
|
||||
}
|
||||
|
||||
// ErrServicePilotUnavailable withholds any result that is not this B1 slice's
|
||||
// signed DENY. Provider joins and executable eligibility remain unimplemented.
|
||||
var ErrServicePilotUnavailable = errors.New("service pilot source path unavailable")
|
||||
|
||||
// CheckServicePilot records only a signed DENY after authenticating the exact
|
||||
// immutable service input. It does not validate Approval facts or grant an act.
|
||||
func (e *Engine) CheckServicePilot(ctx context.Context, input taskexecution.ServiceInput) (api.DecisionEnvelope, error) {
|
||||
if !e.IsServicePilot() {
|
||||
return api.DecisionEnvelope{}, ErrServicePilotUnavailable
|
||||
}
|
||||
request, err := input.RequestAt(e.now())
|
||||
if err != nil {
|
||||
return api.DecisionEnvelope{}, err
|
||||
}
|
||||
envelope, err := e.decide(callerauth.WithRecord(ctx, input.Caller()), request)
|
||||
if err != nil {
|
||||
return api.DecisionEnvelope{}, err
|
||||
}
|
||||
if envelope.Effect != api.DecisionEffectDeny || envelope.Signature == nil || envelope.Signature.Mode != api.EnvelopeSignatureSigned {
|
||||
return api.DecisionEnvelope{}, ErrServicePilotUnavailable
|
||||
}
|
||||
if err := e.recordDecisions([]api.DecisionEnvelope{envelope}); err != nil {
|
||||
return api.DecisionEnvelope{}, err
|
||||
}
|
||||
return envelope, nil
|
||||
}
|
||||
|
||||
// Check evaluates one subject/action/resource request. The decision is
|
||||
// released only after its required record commits (GH-DEC-2026-024).
|
||||
func (e *Engine) Check(ctx context.Context, request api.CheckRequest) (api.DecisionEnvelope, error) {
|
||||
if e.IsServicePilot() || request.Action == "execute-ccr" {
|
||||
return api.DecisionEnvelope{}, ErrServicePilotUnavailable
|
||||
}
|
||||
decision, err := e.decide(ctx, request)
|
||||
if err != nil {
|
||||
return api.DecisionEnvelope{}, err
|
||||
|
|
@ -169,6 +205,9 @@ func (e *Engine) Check(ctx context.Context, request api.CheckRequest) (api.Decis
|
|||
// BatchCheck evaluates one subject/action/context tuple against resources in
|
||||
// request order, and commits the whole batch in one durable write.
|
||||
func (e *Engine) BatchCheck(ctx context.Context, request api.BatchCheckRequest) ([]api.DecisionEnvelope, error) {
|
||||
if e.IsServicePilot() || request.Action == "execute-ccr" {
|
||||
return nil, ErrServicePilotUnavailable
|
||||
}
|
||||
decisions := make([]api.DecisionEnvelope, 0, len(request.Resources))
|
||||
for _, resource := range request.Resources {
|
||||
decision, err := e.decide(ctx, api.CheckRequest{
|
||||
|
|
@ -193,6 +232,9 @@ func (e *Engine) BatchCheck(ctx context.Context, request api.BatchCheckRequest)
|
|||
|
||||
// ListAllowed evaluates candidate resources and returns only allow decisions.
|
||||
func (e *Engine) ListAllowed(ctx context.Context, request ListAllowedRequest) ([]api.DecisionEnvelope, error) {
|
||||
if e.IsServicePilot() || request.Action == "execute-ccr" {
|
||||
return nil, ErrServicePilotUnavailable
|
||||
}
|
||||
candidates := e.store.ResourceRefs(request.System, request.ResourceType)
|
||||
decisions := make([]api.DecisionEnvelope, 0, len(candidates))
|
||||
for _, resource := range candidates {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue