Bind trusted task approval to exact producer facts and lifetime
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Failing after 1m10s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
tegwick 2026-10-16 17:27:30 +02:00
parent 4f6946bbb3
commit 2b064eee51
31 changed files with 2170 additions and 30 deletions

View file

@ -333,6 +333,7 @@ func runServe(args []string, stdout, stderr io.Writer) int {
logPath := fs.String("log", "", "optional JSONL decision log path")
signingKeyFile := fs.String("envelope-signing-key-file", "", "owner-mounted base64url Ed25519 seed file")
signingKID := fs.String("envelope-signing-kid", "", "independently admitted envelope signing key id")
approvalSourceFile := fs.String("approval-source-file", "", "owner fixed Approval HTTPS reader configuration file")
outboxDir := fs.String("outbox-dir", "", "durable emission outbox directory (FLEX-WP-0031); exclusive with --log")
emissionSource := fs.String("emission-source", "", "audit-core source name for emitted decision events, e.g. flex-auth.tenant-engine")
auditURL := fs.String("audit-url", "", "admitted audit-core /v1/events endpoint; empty disables drain and heartbeats")
@ -402,7 +403,19 @@ func runServe(args []string, stdout, stderr io.Writer) int {
if err != nil {
return fail(stderr, err)
}
mux := newServeMuxWithServicePilotInputs(engine, authenticator, serviceInputs)
var approvalReader *taskexecution.ApprovalReader
if engine.IsTrustedServicePilot() {
if *signingKeyFile == "" || *approvalSourceFile == "" {
return fail(stderr, fmt.Errorf("trusted task source requires signing and fixed Approval reader configuration"))
}
approvalReader, err = taskexecution.LoadApprovalReader(*approvalSourceFile)
if err != nil {
return fail(stderr, err)
}
} else if *approvalSourceFile != "" {
return fail(stderr, fmt.Errorf("Approval reader requires exact trusted task source package"))
}
mux := newServeMuxWithTaskFacts(engine, authenticator, serviceInputs, approvalReader)
if outbox != nil {
mountEmission(mux, outbox)
}
@ -457,6 +470,9 @@ func newServeMuxWithCallerAuth(engine *decisioncore.Engine, authenticator *calle
}
func newServeMuxWithServicePilotInputs(engine *decisioncore.Engine, authenticator *callerauth.Authenticator, serviceInputs *taskexecution.ServicePilotInputs) *http.ServeMux {
return newServeMuxWithTaskFacts(engine, authenticator, serviceInputs, nil)
}
func newServeMuxWithTaskFacts(engine *decisioncore.Engine, authenticator *callerauth.Authenticator, serviceInputs *taskexecution.ServicePilotInputs, approvalReader *taskexecution.ApprovalReader) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("content-type", "application/json")
@ -467,12 +483,16 @@ func newServeMuxWithServicePilotInputs(engine *decisioncore.Engine, authenticato
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
if engine.IsServicePilot() {
if engine.IsTaskPin() {
if serviceInputs == nil {
http.Error(w, "service input unavailable", http.StatusServiceUnavailable)
return
}
request, err := taskexecution.DecodeServiceRequest(r.Body)
decode := taskexecution.DecodeServiceRequest
if engine.IsTrustedServicePilot() {
decode = taskexecution.DecodeTrustedServiceRequest
}
request, err := decode(r.Body)
if err != nil || request.Purpose != "" {
http.Error(w, "invalid service task request", http.StatusBadRequest)
return
@ -482,7 +502,12 @@ func newServeMuxWithServicePilotInputs(engine *decisioncore.Engine, authenticato
http.Error(w, "service task input refused", http.StatusForbidden)
return
}
decision, err := engine.CheckServicePilot(r.Context(), input)
var decision api.DecisionEnvelope
if engine.IsTrustedServicePilot() {
decision, err = engine.CheckTrustedService(r.Context(), input, approvalReader)
} else {
decision, err = engine.CheckServicePilot(r.Context(), input)
}
writeHTTP(w, decision, err)
return
}
@ -506,7 +531,7 @@ func newServeMuxWithServicePilotInputs(engine *decisioncore.Engine, authenticato
writeHTTP(w, decision, err)
})
mux.HandleFunc("/v1/batch_check", func(w http.ResponseWriter, r *http.Request) {
if engine.IsServicePilot() {
if engine.IsTaskPin() {
http.Error(w, "service task batch unavailable", http.StatusForbidden)
return
}
@ -537,7 +562,7 @@ func newServeMuxWithServicePilotInputs(engine *decisioncore.Engine, authenticato
// Only the existing exact service pilot package selects this source path.
// This is not an eligibility toggle; successful preparation still only DENYs.
func buildServicePilotInputs(engine *decisioncore.Engine, mode callerauth.Mode, audience, kubernetesURL, reviewerTokenFile, caFile string, bindings map[string]string) (*taskexecution.ServicePilotInputs, error) {
if !engine.IsServicePilot() {
if !engine.IsTaskPin() {
return nil, nil
}
if mode != callerauth.ModeEnforce || audience != "flex-auth" || len(bindings) != 1 || bindings["secrets-engine"] != taskexecution.ServicePilotPrincipal {
@ -547,6 +572,9 @@ func buildServicePilotInputs(engine *decisioncore.Engine, mode callerauth.Mode,
if err != nil {
return nil, err
}
if engine.IsTrustedServicePilot() {
return taskexecution.NewTrustedServiceInputs(reviewer)
}
return taskexecution.NewServicePilotInputs(reviewer)
}
@ -575,11 +603,15 @@ func writeCallerAuthError(w http.ResponseWriter, err error) {
}
func buildEngine(ctx context.Context, registryPath, policyPath, logPath string) (*decisioncore.Engine, error) {
store, err := registry.LoadFile(registryPath)
pkg, err := policy.LoadAndValidateFile(ctx, policyPath)
if err != nil {
return nil, err
}
pkg, err := policy.LoadAndValidateFile(ctx, policyPath)
load := registry.LoadFile
if pkg.Metadata.ID == taskexecution.ServicePilotPackageID && pkg.Metadata.Version == taskexecution.TrustedServicePilotPackageVersion {
load = registry.LoadFilePreservingNumbers
}
store, err := load(registryPath)
if err != nil {
return nil, err
}

View file

@ -0,0 +1,430 @@
package main
import (
"bytes"
"context"
"crypto/ed25519"
"encoding/base64"
"encoding/json"
"encoding/pem"
"io"
"net"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
"github.com/netkingdom/access-engine/internal/audit"
"github.com/netkingdom/access-engine/internal/callerauth"
"github.com/netkingdom/access-engine/internal/decision"
"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"
"github.com/netkingdom/approval-engine/adapters/go/approvalfact"
)
func trustedRequest(t *testing.T, now time.Time) api.CheckRequest {
t.Helper()
r := pilotRequest(now)
r.Context["execution_contract"].(map[string]any)["operation_deadline"] = now.Add(60 * time.Second).UTC().Truncate(time.Second).Format(time.RFC3339)
r.Subject.Tenant = r.Tenant
r.Resource.Tenant = r.Tenant
r.Resource.Attributes["numeric_fixture"] = json.Number("1.0")
c := r.Context["execution_contract"].(map[string]any)
c["operation_id"] = "11111111-2222-4333-8444-555555555555"
c["ccr_id"] = "synthetic-change"
c["execution_grant_ccr_id"] = "synthetic-grant"
hash := "sha256:" + strings.Repeat("1", 64)
for _, key := range []string{"ccr_immutable_sha256", "grant_immutable_sha256", "catalog_sha256", "expected_before", "expected_after"} {
c[key] = hash
}
c["backend_budget"] = map[string]any{"ttl_seconds": json.Number("30"), "uses": json.Number("12")}
var ops []any
for i, method := range []string{"GET", "PUT", "GET", "GET", "PUT", "GET"} {
path := "sys/policies/acl/synthetic"
if i >= 3 {
path = "auth/synthetic/role/synthetic"
}
ops = append(ops, map[string]any{"method": method, "path": path, "payload_sha256": hash})
}
c["operations"] = ops
delete(r.Context, "approval")
raw, _ := json.Marshal(map[string]any{"action": r.Action, "actor": r.Subject.ID, "principal": "secrets-engine", "purpose": "synthetic source-only proof", "target": r.Resource})
r.Context["purpose"] = "synthetic source-only proof"
_, digest, err := approvalfact.CanonicalBinding(raw)
if err != nil {
t.Fatal(err)
}
bindingValue, err := approvalfact.DecodeJSON(raw)
if err != nil {
t.Fatal(err)
}
binding := bindingValue.(map[string]any)
// PDP profile intentionally retains the published legacy numeric projection.
encoded, _ := json.Marshal(r)
var legacy api.CheckRequest
json.Unmarshal(encoded, &legacy)
binding["digest"] = digest
binding["pdp_digest"] = api.ApprovalBindingDigest(legacy)
binding["pdp_path"] = true
binding["human_control"] = true
r.Context["approval"] = map[string]any{"schema_version": "0.1", "kind": "approval-claim", "issuer": "approval-engine", "approval_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", "state": "valid", "valid_now": true, "consumed": false, "reason_code": "ok", "binding": binding, "freshness": map[string]any{"observed_at": now.Add(-time.Second).Format(time.RFC3339Nano), "ttl_seconds": json.Number("120"), "not_after": now.Add(119 * time.Second).Format(time.RFC3339Nano)}, "validity": map[string]any{"not_before": now.Add(-time.Hour).Format(time.RFC3339Nano), "expires_at": now.Add(time.Hour).Format(time.RFC3339Nano)}}
return r
}
func TestTrustedServiceActualHTTPPositiveAndRefusals(t *testing.T) { testTrustedServiceHTTP(t, false) }
func TestTrustedServiceRetainedRegistryPreapprovalAndRefusals(t *testing.T) {
testTrustedServiceHTTP(t, true)
}
func testTrustedServiceHTTP(t *testing.T, retained bool) {
now := time.Now().UTC()
folder := t.TempDir()
reviewer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/apis/authentication.k8s.io/v1/tokenreviews" || r.Header.Get("Authorization") != "Bearer synthetic-reviewer" {
w.WriteHeader(403)
return
}
json.NewEncoder(w).Encode(map[string]any{"status": map[string]any{"authenticated": true, "audiences": []string{"flex-auth"}, "user": map[string]any{"username": taskexecution.ServicePilotPrincipal}}})
}))
defer reviewer.Close()
ca := filepath.Join(folder, "review-ca")
token := filepath.Join(folder, "review-token")
os.WriteFile(ca, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: reviewer.Certificate().Raw}), 0600)
os.WriteFile(token, []byte("synthetic-reviewer"), 0600)
original := trustedRequest(t, now)
if retained {
delete(original.Context, "approval")
}
claimRaw, _ := json.Marshal(original.Context["approval"])
mode := "ok"
reads := 0
provider := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reads++
if r.URL.Path != "/v1/approvals/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/claim" || r.Header.Get("Authorization") != "Bearer synthetic-approval-reader" {
w.WriteHeader(403)
return
}
if mode == "redirect" {
http.Redirect(w, r, reviewer.URL, 302)
return
}
w.Header().Set("Content-Type", "application/json")
switch mode {
case "duplicate":
io.WriteString(w, `{"state":"valid","state":"invalid"}`)
case "changed":
v, _ := approvalfact.DecodeJSON(claimRaw)
v.(map[string]any)["consumed"] = true
json.NewEncoder(w).Encode(v)
case "short-fresh":
v, _ := approvalfact.DecodeJSON(claimRaw)
fresh := v.(map[string]any)["freshness"].(map[string]any)
fresh["ttl_seconds"] = json.Number("20")
fresh["not_after"] = now.Add(19 * time.Second).Format(time.RFC3339Nano)
json.NewEncoder(w).Encode(v)
case "expired":
v, _ := approvalfact.DecodeJSON(claimRaw)
v.(map[string]any)["freshness"].(map[string]any)["not_after"] = now.Add(-time.Second).Format(time.RFC3339Nano)
json.NewEncoder(w).Encode(v)
default:
w.Write(claimRaw)
}
}))
defer provider.Close()
pca := filepath.Join(folder, "approval-ca")
ptoken := filepath.Join(folder, "approval-token")
os.WriteFile(pca, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: provider.Certificate().Raw}), 0600)
os.WriteFile(ptoken, []byte("synthetic-approval-reader"), 0440)
source, err := taskexecution.NewApprovalReader(taskexecution.ApprovalSourceConfig{SourceID: "synthetic-approval", SourceRevision: "test-source-revision", Origin: provider.URL, StoreTenant: "tenant:platform", CAFile: pca, TokenFile: ptoken})
if err != nil {
t.Fatal(err)
}
pkg, err := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "examples", "secrets-engine-service-task-execution-v2", "policy_package.md"))
if err != nil {
t.Fatal(err)
}
store := registry.NewStore()
if retained {
store, err = registry.LoadFilePreservingNumbers(filepath.Join("..", "..", "examples", "secrets-engine", "registry_snapshot.json"))
if err != nil {
t.Fatal(err)
}
}
engine, err := decision.NewEngine(store, pkg)
if err != nil {
t.Fatal(err)
}
key := ed25519.NewKeyFromSeed(bytes.Repeat([]byte{19}, 32))
engine.SetEnvelopeSigningKey(key, "synthetic-v2")
record := filepath.Join(folder, "record.jsonl")
engine.SetDecisionLog(audit.NewJSONLDecisionLog(record))
inputs, err := buildServicePilotInputs(engine, callerauth.ModeEnforce, "flex-auth", reviewer.URL, token, ca, map[string]string{"secrets-engine": taskexecution.ServicePilotPrincipal})
if err != nil {
t.Fatal(err)
}
server := httptest.NewServer(newServeMuxWithTaskFacts(engine, callerauth.Disabled(), inputs, source))
defer server.Close()
post := func(request api.CheckRequest) (int, []byte) {
t.Helper()
raw, _ := json.Marshal(request)
req, _ := http.NewRequest("POST", server.URL+"/v1/check", bytes.NewReader(raw))
req.Header.Set("Authorization", "Bearer "+pilotToken("valid", now))
response, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
return response.StatusCode, body
}
var pre api.DecisionEnvelope
if retained {
preStatus, preRaw := post(original)
if preStatus != 200 {
t.Fatalf("preapproval status%d", preStatus)
}
pre, err = sign.DecodeEnvelope(preRaw)
if err != nil || sign.Verify(pre, map[string]ed25519.PublicKey{"synthetic-v2": key.Public().(ed25519.PublicKey)}) != nil {
t.Fatal("preapproval not authenticated")
}
if pre.Effect != api.DecisionEffectDeny || pre.Lifetime != nil || pre.Binding.ApprovalBindingDigest == "" || pre.Binding.ApprovalBindingDigest != pre.Binding.RequestDigest {
t.Fatal("preapproval receipt is execution authority or lacks exactclaimfree digest")
}
if pre.Diagnostics["registry_subject"] != true || pre.Provenance.RegistrySnapshotDigest != store.Digest() {
t.Fatal("retained registry not applied")
}
rawOriginal, _ := json.Marshal(original)
var legacyPre api.CheckRequest
json.Unmarshal(rawOriginal, &legacyPre)
if pre.Binding.SubmittedRequestDigest != api.RequestDigest(legacyPre) || pre.Binding.RequestDigest == api.RequestDigest(legacyPre) {
t.Fatal("original/evaluated retained registry distinction lost")
}
carried := trustedRequest(t, now).Context["approval"].(map[string]any)
native := map[string]any{"action": pre.Binding.Action, "actor": pre.Binding.Subject.ID, "principal": "secrets-engine", "purpose": pre.Binding.Context["purpose"], "target": pre.Binding.Resource}
nativeRaw, _ := json.Marshal(native)
_, nativeDigest, err := approvalfact.CanonicalBinding(nativeRaw)
if err != nil {
t.Fatal(err)
}
native["digest"] = nativeDigest
native["pdp_digest"] = pre.Binding.ApprovalBindingDigest
native["pdp_path"] = true
native["human_control"] = true
carried["binding"] = native
original.Context["approval"] = carried
claimRaw, _ = json.Marshal(carried)
originalBytes, _ := json.Marshal(original)
original, err = taskexecution.DecodeTrustedServiceRequest(bytes.NewReader(originalBytes))
if err != nil {
t.Fatal(err)
}
}
status, body := post(original)
if status != 200 {
t.Fatalf("positive status %d: %s", status, body)
}
envelope, err := sign.DecodeEnvelope(body)
if err != nil {
t.Fatal(err)
}
t.Logf("actual HTTP source policy pin: %s %s %s", pkg.Metadata.ID, pkg.Metadata.Version, pkg.Digest())
if envelope.Effect != api.DecisionEffectAllow || sign.Verify(envelope, map[string]ed25519.PublicKey{"synthetic-v2": key.Public().(ed25519.PublicKey)}) != nil {
t.Fatalf("not signed ALLOW: %s", body)
}
if envelope.Provenance.ApprovalObservation == nil || envelope.Provenance.ApprovalObservation.SourceID != "synthetic-approval" || reads != 1 {
t.Fatal("missing authenticated observation provenance")
}
legacyRaw, _ := json.Marshal(original)
var legacyRequest api.CheckRequest
json.Unmarshal(legacyRaw, &legacyRequest)
if envelope.Binding.SubmittedRequestDigest != api.RequestDigest(legacyRequest) {
t.Fatal("original submitted digest changed")
}
if retained {
if envelope.Binding.RequestDigest == api.RequestDigest(legacyRequest) || envelope.Binding.ApprovalBindingDigest != pre.Binding.ApprovalBindingDigest {
t.Fatal("normalized approval correspondence changed")
}
} else if envelope.Binding.RequestDigest != api.RequestDigest(legacyRequest) || envelope.Binding.ApprovalBindingDigest != api.ApprovalBindingDigest(legacyRequest) {
t.Fatal("published digest profile changed")
}
if !reflect.DeepEqual(envelope.Binding.Context, original.Context) {
t.Fatal("original context changed")
}
if envelope.Lifetime.ExpiresAt != original.Context["execution_contract"].(map[string]any)["operation_deadline"] {
t.Fatal("decision does not bound entire exact operation")
}
if envelope.Binding.Resource.Attributes["numeric_fixture"] != json.Number("1.0") {
t.Fatal("native numeric kind lost")
}
recorded, err := os.ReadFile(record)
if err != nil {
t.Fatal(err)
}
records, err := audit.NewJSONLDecisionLog(record).ReadAll()
expectedCount := 1
if retained {
expectedCount = 2
}
if err != nil || len(records) != expectedCount || !reflect.DeepEqual(records[len(records)-1], envelope) {
t.Fatal("returned record parity")
}
if retained && !reflect.DeepEqual(records[0], pre) {
t.Fatal("preapproval record parity")
}
for _, failure := range []string{"redirect", "duplicate", "changed", "expired", "short-fresh"} {
t.Run(failure, func(t *testing.T) {
mode = failure
status, _ := post(original)
if status == 200 {
t.Fatal("bad source admitted")
}
})
}
mode = "ok"
if retained {
t.Run("registry-drift-cannot-rebind-approved-act", func(t *testing.T) {
subject, _ := store.Subject("secrets-engine")
originalSubject := subject
subject.Roles = append(append([]api.CanonicalRole{}, subject.Roles...), api.CanonicalRole("synthetic-owner-drift"))
if err := store.PutSubject(subject); err != nil {
t.Fatal(err)
}
defer store.PutSubject(originalSubject)
if status, _ := post(original); status == 200 {
t.Fatal("changed registry silently rebound original/fresh claim")
}
})
}
t.Run("original-stale", func(t *testing.T) {
raw, _ := json.Marshal(original)
r, err := taskexecution.DecodeTrustedServiceRequest(bytes.NewReader(raw))
if err != nil {
t.Fatal(err)
}
fresh := r.Context["approval"].(map[string]any)["freshness"].(map[string]any)
fresh["observed_at"] = now.Add(-121 * time.Second).Format(time.RFC3339Nano)
fresh["not_after"] = now.Add(-time.Second).Format(time.RFC3339Nano)
status, _ := post(r)
if status == 200 {
t.Fatal("fresh provider rescued stale original")
}
})
t.Run("native-number-kind", func(t *testing.T) {
raw, _ := json.Marshal(original)
r, _ := taskexecution.DecodeTrustedServiceRequest(bytes.NewReader(raw))
r.Resource.Attributes["numeric_fixture"] = json.Number("1")
status, _ := post(r)
if status == 200 {
t.Fatal("changed native integer/float authority accepted")
}
})
after, _ := os.ReadFile(record)
if !bytes.Equal(after, recorded) {
t.Fatal("refused calls recorded executable envelopes")
}
// Exercise actual production CLI configuration with no ambient credentials.
seedPath := filepath.Join(folder, "cli-seed")
os.WriteFile(seedPath, []byte(base64.RawURLEncoding.EncodeToString(bytes.Repeat([]byte{19}, 32))), 0440)
sourcePath := filepath.Join(folder, "approval-source.json")
sourceJSON, _ := json.Marshal(taskexecution.ApprovalSourceConfig{SourceID: "synthetic-approval", SourceRevision: "test-source-revision", Origin: provider.URL, StoreTenant: "tenant:platform", CAFile: pca, TokenFile: ptoken})
os.WriteFile(sourcePath, sourceJSON, 0600)
registryPath := filepath.Join(folder, "registry.json")
registryBytes := []byte(`{}`)
if retained {
registryBytes, err = os.ReadFile(filepath.Join("..", "..", "examples", "secrets-engine", "registry_snapshot.json"))
if err != nil {
t.Fatal(err)
}
}
os.WriteFile(registryPath, registryBytes, 0600)
policyPath, _ := filepath.Abs(filepath.Join("..", "..", "examples", "secrets-engine-service-task-execution-v2", "policy_package.md"))
cliRecord := filepath.Join(folder, "cli-record.jsonl")
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
address := listener.Addr().String()
listener.Close()
args := []string{"serve", "--addr", address, "--registry", registryPath, "--policy", policyPath, "--log", cliRecord, "--caller-auth-mode", "enforce", "--caller-audience", "flex-auth", "--caller-kubernetes-url", reviewer.URL, "--caller-reviewer-token-file", token, "--caller-ca-file", ca, "--caller-binding", "secrets-engine=" + taskexecution.ServicePilotPrincipal, "--envelope-signing-key-file", seedPath, "--envelope-signing-kid", "synthetic-v2", "--approval-source-file", sourcePath}
argsJSON, _ := json.Marshal(args)
child := exec.Command(os.Args[0], "-test.run=^TestServicePilotChildCLI$")
child.Env = []string{"ACCESS_B1_SERVER_ARGS=" + string(argsJSON)}
child.Stdout = io.Discard
child.Stderr = io.Discard
if err := child.Start(); err != nil {
t.Fatal(err)
}
defer func() { child.Process.Kill(); child.Wait() }()
ready := false
for attempt := 0; attempt < 100; attempt++ {
response, err := http.Get("http://" + address + "/healthz")
if err == nil {
response.Body.Close()
ready = true
break
}
time.Sleep(20 * time.Millisecond)
}
if !ready {
t.Fatal("trusted CLI not ready")
}
raw, _ := json.Marshal(original)
req, _ := http.NewRequest("POST", "http://"+address+"/v1/check", bytes.NewReader(raw))
req.Header.Set("Authorization", "Bearer "+pilotToken("valid", now))
response, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer response.Body.Close()
wire, _ := io.ReadAll(response.Body)
cliEnvelope, err := sign.DecodeEnvelope(wire)
if response.StatusCode != 200 || err != nil || cliEnvelope.Effect != api.DecisionEffectAllow || sign.Verify(cliEnvelope, map[string]ed25519.PublicKey{"synthetic-v2": key.Public().(ed25519.PublicKey)}) != nil {
t.Fatalf("CLI did not return signed trusted ALLOW: %s", wire)
}
cliRecords, err := audit.NewJSONLDecisionLog(cliRecord).ReadAll()
if err != nil || len(cliRecords) != 1 || !reflect.DeepEqual(cliRecords[0], cliEnvelope) {
t.Fatal("CLI response/readback record mismatch")
}
if !reflect.DeepEqual(cliEnvelope.Binding.Context, original.Context) {
t.Fatal("CLI changed original numeric context")
}
}
func TestTrustedServiceMissingAndGenericAdmissionRefuse(t *testing.T) {
pkg, err := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "examples", "secrets-engine-service-task-execution-v2", "policy_package.md"))
if err != nil {
t.Fatal(err)
}
engine, err := decision.NewEngine(registry.NewStore(), pkg)
if err != nil {
t.Fatal(err)
}
request := trustedRequest(t, time.Now().UTC())
if _, err := engine.Check(context.Background(), request); err == nil {
t.Fatal("generic check bypass")
}
if _, err := engine.BatchCheck(context.Background(), api.BatchCheckRequest{Action: "execute-ccr"}); err == nil {
t.Fatal("generic batch bypass")
}
if _, err := engine.ListAllowed(context.Background(), decision.ListAllowedRequest{Action: "execute-ccr"}); err == nil {
t.Fatal("generic list bypass")
}
if _, err := engine.CheckTrustedService(context.Background(), taskexecution.ServiceInput{}, nil); err == nil {
t.Fatal("missing typed input and fixed source accepted")
}
recorder := httptest.NewRecorder()
raw, _ := json.Marshal(request)
newServeMux(engine).ServeHTTP(recorder, httptest.NewRequest("POST", "/v1/check", bytes.NewReader(raw)))
if recorder.Code != 503 {
t.Fatal("unwired typed path accepted")
}
}