FLEX-WP-0035-T04: application-readback pin values; lifecycle pin to v2 image
- values/application-readback.yaml: serve-readback, enforce, readback caller user-engine, ingress from user-engine only - chart: readback.enabled renders --readback-caller instead of --caller-binding - lifecycle pin to e8c57c18 (main-b5da745, lifecycle v2); previous bdac62bc - TestReadbackPinMatchesParticipantPins: same image digest and package path Founder go 2026-10-10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 735967@bnt-lap001 Assistant-Session: 5971967f-77f8-4ced-9e02-c6ef67040ffc
This commit is contained in:
parent
cb48d0702c
commit
bb14ec679c
5 changed files with 126 additions and 2 deletions
|
|
@ -45,11 +45,19 @@ spec:
|
||||||
- {{ required "outbox.source is required when outbox.enabled=true" .Values.outbox.source | quote }}
|
- {{ required "outbox.source is required when outbox.enabled=true" .Values.outbox.source | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
|
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
|
||||||
{{- $binding := required "callerAuth.binding is required when callerAuth.mode is warn or enforce" .Values.callerAuth.binding }}
|
{{- $binding := "" }}
|
||||||
|
{{- if not (and .Values.readback .Values.readback.enabled) }}
|
||||||
|
{{- $binding = required "callerAuth.binding is required when callerAuth.mode is warn or enforce" .Values.callerAuth.binding }}
|
||||||
|
{{- end }}
|
||||||
- --caller-auth-mode
|
- --caller-auth-mode
|
||||||
- {{ include "flex-auth.callerAuth.mode" . | quote }}
|
- {{ include "flex-auth.callerAuth.mode" . | quote }}
|
||||||
- --caller-kubernetes-url
|
- --caller-kubernetes-url
|
||||||
- {{ required "callerAuth.kubernetesURL is required when callerAuth.mode is warn or enforce" .Values.callerAuth.kubernetesURL | quote }}
|
- {{ required "callerAuth.kubernetesURL is required when callerAuth.mode is warn or enforce" .Values.callerAuth.kubernetesURL | quote }}
|
||||||
|
{{- if and .Values.readback .Values.readback.enabled }}
|
||||||
|
{{- /* serve-readback admits one readback caller and no /v1/check binding (FLEX-DEC-2026-019). */}}
|
||||||
|
- --readback-caller
|
||||||
|
- {{ required "readback.caller is required when readback.enabled=true" .Values.readback.caller | quote }}
|
||||||
|
{{- else }}
|
||||||
- --caller-binding
|
- --caller-binding
|
||||||
- {{ $binding | quote }}
|
- {{ $binding | quote }}
|
||||||
{{- range .Values.callerAuth.extraBindings }}
|
{{- range .Values.callerAuth.extraBindings }}
|
||||||
|
|
@ -57,6 +65,7 @@ spec:
|
||||||
- {{ . | quote }}
|
- {{ . | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
containerPort: {{ .Values.service.port }}
|
containerPort: {{ .Values.service.port }}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,12 @@ consumer:
|
||||||
|
|
||||||
# disabled keeps the image bootable without TokenReview (isolated canary).
|
# disabled keeps the image bootable without TokenReview (isolated canary).
|
||||||
# Production pins set warn, then enforce, independently per consumer.
|
# Production pins set warn, then enforce, independently per consumer.
|
||||||
|
# serve-readback pins (FLEX-WP-0035) admit one readback caller via
|
||||||
|
# --readback-caller instead of --caller-binding.
|
||||||
|
readback:
|
||||||
|
enabled: false
|
||||||
|
caller: ""
|
||||||
|
|
||||||
callerAuth:
|
callerAuth:
|
||||||
mode: disabled
|
mode: disabled
|
||||||
audience: flex-auth
|
audience: flex-auth
|
||||||
|
|
|
||||||
72
cmd/flex-auth/readback_pin_test.go
Normal file
72
cmd/flex-auth/readback_pin_test.go
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pinValues struct {
|
||||||
|
Image struct {
|
||||||
|
Digest string `yaml:"digest"`
|
||||||
|
} `yaml:"image"`
|
||||||
|
Args []string `yaml:"args"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadPinValues(t *testing.T, name string) pinValues {
|
||||||
|
t.Helper()
|
||||||
|
raw, err := os.ReadFile(filepath.Join("..", "..", "values", name))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var v pinValues
|
||||||
|
if err := yaml.Unmarshal(raw, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func argAfter(args []string, flag string) []string {
|
||||||
|
var out []string
|
||||||
|
for i := 0; i+1 < len(args); i++ {
|
||||||
|
if args[i] == flag {
|
||||||
|
out = append(out, args[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// FLEX-WP-0035-T04, contract §4: the readback pin runs each participant's
|
||||||
|
// package at the same digest its own pin runs. The package is baked into the
|
||||||
|
// image, so same image digest and same path is the same package digest.
|
||||||
|
func TestReadbackPinMatchesParticipantPins(t *testing.T) {
|
||||||
|
readback := loadPinValues(t, "application-readback.yaml")
|
||||||
|
if len(readback.Args) == 0 || readback.Args[0] != "serve-readback" {
|
||||||
|
t.Fatal("readback pin must run serve-readback, which mounts no /v1/check")
|
||||||
|
}
|
||||||
|
participants := map[string]string{"informed-decision": "informed-decision-lifecycle.yaml"}
|
||||||
|
packages := argAfter(readback.Args, "--package")
|
||||||
|
if len(packages) != len(participants) {
|
||||||
|
t.Fatalf("readback packages %v, want one per participant %v", packages, participants)
|
||||||
|
}
|
||||||
|
for _, pkg := range packages {
|
||||||
|
system, path, _ := strings.Cut(pkg, "=")
|
||||||
|
file, ok := participants[system]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("readback package for %q has no participant pin", system)
|
||||||
|
}
|
||||||
|
own := loadPinValues(t, file)
|
||||||
|
if own.Image.Digest != readback.Image.Digest {
|
||||||
|
t.Errorf("%s: readback image %s, own pin %s", system, readback.Image.Digest, own.Image.Digest)
|
||||||
|
}
|
||||||
|
if policies := argAfter(own.Args, "--policy"); len(policies) != 1 || policies[0] != path {
|
||||||
|
t.Errorf("%s: readback package %s, own pin %v", system, path, policies)
|
||||||
|
}
|
||||||
|
if !strings.Contains(strings.Join(argAfter(readback.Args, "--registry"), " "), strings.Join(argAfter(own.Args, "--registry"), " ")) {
|
||||||
|
t.Errorf("%s: readback pin does not load its registry", system)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
values/application-readback.yaml
Normal file
35
values/application-readback.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# FLEX-WP-0035-T04: advisory application access readback for user-engine.
|
||||||
|
# Founder-approved 2026-10-10. Runs each participant's package from the same
|
||||||
|
# image digest and path as that participant's own pin (contract §4); the test
|
||||||
|
# TestReadbackPinMatchesParticipantPins enforces it.
|
||||||
|
name: flex-auth-application-readback
|
||||||
|
image:
|
||||||
|
repository: forgejo.coulomb.social/coulomb/flex-auth
|
||||||
|
digest: sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229
|
||||||
|
args:
|
||||||
|
- serve-readback
|
||||||
|
- --addr
|
||||||
|
- 0.0.0.0:8080
|
||||||
|
- --registry
|
||||||
|
- /opt/flex-auth/examples/application-readback/registry_snapshot.json
|
||||||
|
- --registry
|
||||||
|
- /opt/flex-auth/examples/informed-decision-lifecycle/registry.json
|
||||||
|
- --package
|
||||||
|
- informed-decision=/opt/flex-auth/examples/informed-decision-lifecycle/policy.md
|
||||||
|
callerAuth:
|
||||||
|
mode: enforce
|
||||||
|
kubernetesURL: https://10.43.0.1
|
||||||
|
readback:
|
||||||
|
enabled: true
|
||||||
|
caller: system:serviceaccount:user-engine:user-engine
|
||||||
|
consumer:
|
||||||
|
isolated: false
|
||||||
|
namespace: user-engine
|
||||||
|
podName: user-engine
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 5m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 300m
|
||||||
|
memory: 192Mi
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
# Founder-approved INFD-WP-0007 / FLEX-WP-0033 cutover, 2026-10-04.
|
# Founder-approved INFD-WP-0007 / FLEX-WP-0033 cutover, 2026-10-04.
|
||||||
|
# Lifecycle v2 (application.access), founder-approved FLEX-WP-0035-T04, 2026-10-10.
|
||||||
|
# Previous stable: sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99
|
||||||
name: flex-auth-informed-decision-lifecycle
|
name: flex-auth-informed-decision-lifecycle
|
||||||
image:
|
image:
|
||||||
repository: forgejo.coulomb.social/coulomb/flex-auth
|
repository: forgejo.coulomb.social/coulomb/flex-auth
|
||||||
digest: sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99
|
digest: sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229
|
||||||
args:
|
args:
|
||||||
- serve
|
- serve
|
||||||
- --addr
|
- --addr
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue