docs: preserve reviewed NetKingdom session artifacts
This commit is contained in:
parent
24e9be4f99
commit
be0f891619
50 changed files with 7398 additions and 0 deletions
|
|
@ -0,0 +1,198 @@
|
|||
# T03: protect the earlier cmctl key and reconcile its exact public request
|
||||
|
||||
Source review only under existing RCLUSTER-WP-0018-T03 / NK-WP-0049-T35/T33.
|
||||
No canonical source changed, cmctl installed/executed, key generated/read,
|
||||
CertificateRequest created, cluster mutation or residual implementation occurred.
|
||||
Frozen TLS disposition and all native-runtime R1–R3 receipts stay untouched.
|
||||
|
||||
The missing behavior is small but real: cmctl writes its local private key
|
||||
before its CertificateRequest Create. The existing NetKingdom session registers
|
||||
its own later archive/Docker workdir and reaper; it does not cover those earlier
|
||||
key bytes or a Kubernetes request accepted after a lost client response.
|
||||
|
||||
## Existing source and exact reuse
|
||||
|
||||
- NetKingdom isolated-keycape-session.py: register_workdir and cleanup_workdir
|
||||
already bind /dev/shm/nk49-keycape-{run_id}-{eight_random_chars}, UID/mode0700,
|
||||
device/inode and refuse replacement, symlink, hardlink, cross-device/special
|
||||
objects. Its dirfd-based recursive cleanup can remain unchanged.
|
||||
- Its isolate_execution / process_facts / pidfd_dead / quiesce_execution show
|
||||
the existing fresh-session and pidfd contract. Its start_reaper/reaper_main
|
||||
are specifically Docker/session-bound and must not be called with an invented
|
||||
empty Docker session for issuance. Group-only membership also does not prove
|
||||
removal of session-escaped credential-plugin descendants.
|
||||
- Its persist_receipt/checkpoint seam records obligations before archive
|
||||
plaintext. T03 must similarly register *before cmctl*, not after output exists.
|
||||
- NetKingdom capture-identity.delete_created and Platform
|
||||
native_factory_acceptance use Kubernetes raw DELETE with DeleteOptions UID
|
||||
preconditions (the latter also Foreground propagation). Reuse that exact API
|
||||
idiom in the TLS owner helper; do not broaden identity-capture's Pod/NP whitelist.
|
||||
- The locally tested native-runtime R3 supervisor demonstrates subreaper/pidfd
|
||||
descendant cleanup, including dead-orphan reaping and live-leftover refusal.
|
||||
That is relevant source evidence, not an admitted TLS utility or native cause
|
||||
proof. Do not import a Custodian packet at runtime or silently copy its grant.
|
||||
|
||||
## Minimal owner source delta, before any key
|
||||
|
||||
Implement one bounded T03 orchestration helper through the existing Cluster /
|
||||
NetKingdom ownership boundary; retain the six-argument original recovery launcher.
|
||||
No new broker, CA provider, auth method, TLS policy enum or approval field.
|
||||
The reviewable interfaces are:
|
||||
|
||||
1. `register_tls_staging(run_id, caller_binding, deadline)` creates only the
|
||||
existing guard-compatible fresh0700 directory. Before creation/key access,
|
||||
verify the actual selected /dev/shm mount is writable tmpfs, bind mount ID /
|
||||
device, owner UID, no aliases, and available bounded space. Then call existing
|
||||
register_workdir and checkpoint only public path/device/inode/run facts.
|
||||
The existing register_workdir alone does NOT check tmpfs before use; current
|
||||
cleanup_workdir checks it only at deletion. Move that check earlier in this
|
||||
new caller; no disk /tmp fallback. This sandbox's /dev/shm is actually ro,
|
||||
so no usable private staging or local tmpfs lifecycle proof is claimed here.
|
||||
2. `start_tls_reaper(staging, execution, request_intent)` starts an independent
|
||||
surviving observer and waits for its registration acknowledgment BEFORE
|
||||
spawning cmctl. Bind controller pidfd/start/UID and a single monotonic deadline.
|
||||
The observer owns/reaps the exact cmctl and subsequent original-launcher
|
||||
process trees as a subreaper; pidfd-bound actual descendants cover setsid
|
||||
escapes. Preserve existing fresh-session guard and avoid inherited/shared
|
||||
process-group kills. On timeout/parent loss stop/wait those exact descendants
|
||||
before cleanup. A missing mapping/observer or survivor means cleanup unverified,
|
||||
never an inferred success. Reap already-dead adopted direct-child zombies
|
||||
without stealing managed leader exit status; retain the R3 local counterexample.
|
||||
3. `run_issuance(binding, staging, run_id)` uses the admitted exact cmctl binary,
|
||||
unchanged R1 flags and original Certificate spec, but puts one unique run label
|
||||
and source/proposal annotation in its *local template*. The pinned cmctl source
|
||||
copies those labels/annotations into the CertificateRequest. Pre-register
|
||||
exact target/ns/name, template/spec hash, expected issuer and an unresolved
|
||||
submit obligation before spawn. Output key/cert paths must be absent, under
|
||||
the held private directory, with umask077. Discard raw stdout/stderr; no private
|
||||
path/content/diagnostic dump enters shared receipts. The binary source uses
|
||||
os.WriteFile0600 without O_EXCL/O_NOFOLLOW, so it relies on this previously
|
||||
verified private directory/absent-output boundary; it is not a safe arbitrary
|
||||
output-path primitive by itself.
|
||||
4. `observe_request(intent, private_custody)` uses only the bound owner API,
|
||||
exact name and bounded public field projection. Require same cluster identity,
|
||||
namespace/name, fresh run marker, fixed issuer/usages/SAN/CSR semantics and
|
||||
the admitted API caller. Inside future approved private custody, derive only
|
||||
the held key's public SPKI commitment and compare it with the actual signed
|
||||
CSR; expose only public commitment/CSR hash and pairing boolean. Check the
|
||||
CSR signature/SANs. Checkpoint the actual UID/resourceVersion and expected
|
||||
public spec hash before any remote delete or private-directory cleanup.
|
||||
The run marker alone is not proof of key/caller ownership.
|
||||
5. `delete_request_uid(bound)` uses the exact contract in delete-request-contract.json,
|
||||
then independently verifies that UID's absence and the actual owner-UID
|
||||
descendant chain. Normal cert-manager garbage collection is preferred; explicit
|
||||
cleanup of a stuck child needs its recorded UID/owner chain and scoped owner
|
||||
review. Do not delete by label, prefix, wildcard or name alone.
|
||||
6. `finish_or_abort(...)` persists an immutable bounded public checkpoint BEFORE
|
||||
private deletion: tool/source/target/run, process exits/public facts,
|
||||
certificate/trust hashes, request UID/spec/CSR commitments, descendant cleanup
|
||||
dispositions, pending API/daemon duties. Reuse cleanup_workdir only after exact
|
||||
local child quiescence and verified staging identity. If public remote cleanup
|
||||
is uncertain, local key/plaintext cleanup can still proceed after quiescence,
|
||||
PROVIDED the exact public request obligations/commitments have been durably
|
||||
retained; report separate local and remote cleanup results, not global success.
|
||||
If required commitments cannot be retained, fail closed and leave the exact
|
||||
protected staging for attended custody recovery, rather than losing ownership
|
||||
proof or broadly deleting unknown resources. No blind retry after uncertainty.
|
||||
|
||||
`staging-reaper-contract.json` fixes the proposed nonrenewable bounds: issuance
|
||||
330 seconds including cmctl's inner300-second fetch wait; existing recovery
|
||||
child at most1800 seconds; one total private execution deadline2130 seconds,
|
||||
then at most60 seconds of clipped cleanup (2190 total). TERM0.5, KILL/reap3,
|
||||
watchdog wait8; each API request at most30 seconds clipped to cleanup remainder.
|
||||
Set umask077, disable core dumps, and bound each cmctl output to1MiB with the
|
||||
same bounded child runner before generation. Tmpfs is
|
||||
not claimed unswappable or isolated from host root/hypervisor/crash custody.
|
||||
These exact proposed bounds need source lifecycle proof before use; they are
|
||||
not a statement that today's helper already enforces them.
|
||||
|
||||
The cmctl child gets DEVNULL input/output/error and no custody fd. Do not copy
|
||||
that IO policy onto the original six-argument launcher: it explicitly requires
|
||||
an attended TTY and invokes the existing hidden age prompt / sealed-fd custody
|
||||
helper. Preserve that original owner terminal path and its existing custody
|
||||
contract, without a new PTY proxy, prompt capture or key passage to the observer.
|
||||
The observer gets only pidfds/public metadata and must close every unrelated fd;
|
||||
its deadline also bounds a stalled attended prompt. Prove this exact distinction
|
||||
with a synthetic terminal fixture before integration; the runtime R3 runner's
|
||||
DEVNULL default is not an admitted drop-in for the attended recovery launcher.
|
||||
|
||||
The independent observer must outlive the creator, not rely on a shell trap or
|
||||
SIGTERM-only child wait. It must not receive a newly fetched kube credential or
|
||||
private key in argv/environment/receipt. Exact use of the existing bound owner
|
||||
API caller remains in that owner's attended execution scope. If that caller
|
||||
uses an exec auth plugin, its actual descendants are covered by the same reaper;
|
||||
there is no implicit admission for unrelated credential helpers or new routes.
|
||||
|
||||
## One custody host and explicit Kubernetes binding
|
||||
|
||||
R1's candidate /home/worsch cmctl path and --context default do not establish
|
||||
where the private key and original local-Docker recovery run will live. R1's
|
||||
observed default context was on railiance01. Current environment orientation says
|
||||
workstation kubeconfig was repaired in September but still requires explicit
|
||||
node-IP verification and node-local mutation practice; a context name alone is
|
||||
not a cluster binding. This is an unverified command binding, not proof that
|
||||
workstation/default presently targets a different cluster.
|
||||
|
||||
Keep cmctl, tmpfs/reaper and the original six-argument launcher on ONE actually
|
||||
admitted custody host. Do not move only cmctl to railiance01 and invent a private
|
||||
key SCP/download. The existing T33/T35 exact action review must bind that host,
|
||||
account, cmctl absolute path/hash, API server/CA public identity and actual node
|
||||
92.205.62.239 through the existing owner profile. If the actual launcher is
|
||||
workstation-local, direct networked issuance needs that explicit owner/founder
|
||||
execution disposition under the existing change gate; if all run node-local,
|
||||
first demonstrate the existing launcher/Docker/independent-owner interfaces there.
|
||||
No host choice, kube credential read or private transfer is assumed by this packet.
|
||||
This is why the source delta is reviewable while a native argv cannot yet be
|
||||
honestly called executable.
|
||||
|
||||
## Exact lifecycle/counterexamples to require from T03 implementation
|
||||
|
||||
- Observer/mount/target/source refusal: zero cmctl spawn and zero key output.
|
||||
- Success: fake network child writes a synthetic PRIVATE_SENTINEL under actual
|
||||
guarded tmpfs, public fixture API returns the exact UID, original launcher
|
||||
consumer reads through the same custody boundary, UID-delete body matches,
|
||||
held inode removed after positive process proof. No real admin canary/key.
|
||||
- Failure before API, key-only failure, timeout, controller SIGKILL, setsid child,
|
||||
dead adopted zombie, uninterruptible/unknown child and output bound. Verify
|
||||
no leaked sentinel and no unrelated sibling signaled. Replaced inode,
|
||||
symlink/hardlink or wrong mount must refuse deletion/use.
|
||||
- API accepted but reply lost: preserve submit uncertainty, later exact-name
|
||||
reconciliation accepts only held SPKI/run/spec/caller binding and actual UID.
|
||||
A single NotFound after killed client does not establish no late Create.
|
||||
- Wrong cluster/ns/name/run/SPKI/spec or swapped UID: no delete. UID-precondition
|
||||
conflict leaves replacement untouched. GC/finalizer timeout and unreachable
|
||||
API retain outstanding request/child UIDs, not successful cleanup.
|
||||
- Independent immutable public receipt exists before private cleanup; receipt
|
||||
write failure leaves protected staging. Real issuance and cluster cleanup
|
||||
remain separate supervised native tests after source proof/review.
|
||||
|
||||
These are requested meaningful generated lifecycle tests, not tests run by this
|
||||
source-only packet. Existing native session/daemon cleanup facts and R3 process
|
||||
fixtures are reused with their limits; no broad dummy rerun was performed.
|
||||
|
||||
## Safe source-only owner publication now
|
||||
|
||||
The one-file owner-doc.patch is ready for source-owner review against its captured
|
||||
preimage. It clarifies renewable transport versus archived signing identity,
|
||||
retains per-attempt TLS/trust hashes and all existing T02–T04/native duties, records
|
||||
the already-located guide, and names the concrete T03 delta above. It makes no
|
||||
owner/founder assent or native compatibility claim. No task status/UUID change or
|
||||
new T06 is needed for this clarification; do not publish the old R1 task addition
|
||||
as completed native/staging work. Root may review/publish that doc alone using
|
||||
normal owner publication while canonical code and frozen packets remain unchanged.
|
||||
|
||||
The original disaster guide is already located: publication commit
|
||||
31f483966cdfca4df1d326dee3ec0b6d33ea0e5e, Backup account,
|
||||
railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md.
|
||||
The recorded three-object readback is historical; this source work does not
|
||||
re-read StorageShare or request another original TLS backup. The guide is
|
||||
identity-only and does not establish ingress TLS-key coverage.
|
||||
|
||||
Renewed trusted leaf material remains compatible with the existing per-attempt
|
||||
admission; no historical leaf-byte equality or extra TLS mode is introduced.
|
||||
Archived original OIDC issuer/signing keys/JWKS and registration/policy checks
|
||||
remain unchanged. HTTP-01 still depends on a surviving Kubernetes/cert-manager/
|
||||
Traefik/DNS/domain-routing/port80/ACME path. It neither causes nor proves recovery
|
||||
from cluster loss, and today's Ready/public-chain observations do not establish
|
||||
original TLS custody, a future issuance result or an external-vantage HTTP01 test.
|
||||
Independent cluster-loss recovery/provider/domain-control remains T02–T04 scope.
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
Copyright 2020 The cert-manager Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package certificaterequest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/cert-manager/cert-manager/pkg/api/util"
|
||||
cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
|
||||
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
|
||||
"github.com/cert-manager/cert-manager/pkg/util/pki"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
|
||||
"github.com/cert-manager/cmctl/v2/pkg/build"
|
||||
"github.com/cert-manager/cmctl/v2/pkg/convert"
|
||||
"github.com/cert-manager/cmctl/v2/pkg/factory"
|
||||
)
|
||||
|
||||
var (
|
||||
// Dedicated scheme used by the ctl tool that has the internal cert-manager types,
|
||||
// and their conversion functions registered
|
||||
scheme = convert.Scheme
|
||||
)
|
||||
|
||||
// Options is a struct to support create certificaterequest command
|
||||
type Options struct {
|
||||
// Name of file that the generated private key will be stored in
|
||||
// If not specified, the private key will be written to <NameOfCR>.key
|
||||
KeyFilename string
|
||||
// If true, will wait for CertificateRequest to be ready to store the x509 certificate in a file
|
||||
// Command will block until CertificateRequest is ready or timeout as specified by Timeout happens
|
||||
FetchCert bool
|
||||
// Name of file that the generated x509 certificate will be stored in if --fetch-certificate flag is set
|
||||
// If not specified, the private key will be written to <NameOfCR>.crt
|
||||
CertFileName string
|
||||
// Path to a file containing a Certificate resource used as a template
|
||||
// when generating the CertificateRequest resource
|
||||
// Required
|
||||
InputFilename string
|
||||
// Length of time the command blocks to wait on CertificateRequest to be ready if --fetch-certificate flag is set
|
||||
// If not specified, default value is 5 minutes
|
||||
Timeout time.Duration
|
||||
|
||||
genericclioptions.IOStreams
|
||||
*factory.Factory
|
||||
}
|
||||
|
||||
// NewOptions returns initialized Options
|
||||
func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
|
||||
return &Options{
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdCreateCR returns a cobra command for create CertificateRequest
|
||||
func NewCmdCreateCR(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "certificaterequest",
|
||||
Aliases: []string{"cr"},
|
||||
Short: "Create a cert-manager CertificateRequest resource, using a Certificate resource as a template",
|
||||
Long: templates.LongDesc(`
|
||||
Create a new CertificateRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`),
|
||||
Example: templates.Examples(build.WithTemplate(setupCtx, `
|
||||
# Create a CertificateRequest with the name 'my-cr', saving the private key in a file named 'my-cr.key'.
|
||||
{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml
|
||||
|
||||
# Create a CertificateRequest in namespace default, provided no conflict with namespace defined in file.
|
||||
{{.BuildName}} create certificaterequest my-cr --namespace default --from-certificate-file my-certificate.yaml
|
||||
|
||||
# Create a CertificateRequest and store private key in file 'new.key'.
|
||||
{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --output-key-file new.key
|
||||
|
||||
# Create a CertificateRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'.
|
||||
{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --output-cert-file new.crt
|
||||
|
||||
# Create a CertificateRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'.
|
||||
{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m
|
||||
`)),
|
||||
ValidArgsFunction: factory.ValidArgsListCertificateRequests(&o.Factory),
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return o.Validate(args)
|
||||
},
|
||||
//nolint:contextcheck // False positive
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return o.Run(cmd.Context(), args)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(&o.InputFilename, "from-certificate-file", o.InputFilename,
|
||||
"Path to a file containing a Certificate resource used as a template when generating the CertificateRequest resource")
|
||||
cmd.Flags().StringVar(&o.KeyFilename, "output-key-file", o.KeyFilename,
|
||||
"Name of file that the generated private key will be written to")
|
||||
cmd.Flags().StringVar(&o.CertFileName, "output-certificate-file", o.CertFileName,
|
||||
"Name of the file the certificate is to be stored in")
|
||||
cmd.Flags().BoolVar(&o.FetchCert, "fetch-certificate", o.FetchCert,
|
||||
"If set to true, command will wait for CertificateRequest to be signed to store x509 certificate in a file")
|
||||
cmd.Flags().DurationVar(&o.Timeout, "timeout", 5*time.Minute,
|
||||
"Time before timeout when waiting for CertificateRequest to be signed, must include unit, e.g. 10m or 1h")
|
||||
|
||||
o.Factory = factory.New(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Validate validates the provided options
|
||||
func (o *Options) Validate(args []string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("the name of the CertificateRequest to be created has to be provided as argument")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.New("only one argument can be passed in: the name of the CertificateRequest")
|
||||
}
|
||||
|
||||
if o.InputFilename == "" {
|
||||
return errors.New("the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file flag")
|
||||
}
|
||||
|
||||
if o.KeyFilename != "" && o.CertFileName != "" && o.KeyFilename == o.CertFileName {
|
||||
return errors.New("the file to store private key cannot be the same as the file to store certificate")
|
||||
}
|
||||
|
||||
if !o.FetchCert && o.CertFileName != "" {
|
||||
return errors.New("cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate flag")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run executes create certificaterequest command
|
||||
func (o *Options) Run(ctx context.Context, args []string) error {
|
||||
builder := new(resource.Builder)
|
||||
|
||||
// Read file as internal API version
|
||||
r := builder.
|
||||
WithScheme(scheme, schema.GroupVersion{Group: cmapi.SchemeGroupVersion.Group, Version: runtime.APIVersionInternal}).
|
||||
LocalParam(true).ContinueOnError().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &resource.FilenameOptions{Filenames: []string{o.InputFilename}}).Flatten().Do()
|
||||
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
singleItemImplied := false
|
||||
infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure only one object per command
|
||||
if len(infos) == 0 {
|
||||
return fmt.Errorf("no objects found in manifest file %q. Expected one Certificate object", o.InputFilename)
|
||||
}
|
||||
if len(infos) > 1 {
|
||||
return fmt.Errorf("multiple objects found in manifest file %q. Expected only one Certificate object", o.InputFilename)
|
||||
}
|
||||
info := infos[0]
|
||||
// Convert to v1 because that version is needed for functions that follow
|
||||
crtObj, err := scheme.ConvertToVersion(info.Object, cmapi.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert object into version v1: %w", err)
|
||||
}
|
||||
|
||||
// Cast Object into Certificate
|
||||
crt, ok := crtObj.(*cmapi.Certificate)
|
||||
if !ok {
|
||||
return errors.New("decoded object is not a v1 Certificate")
|
||||
}
|
||||
|
||||
crt = crt.DeepCopy()
|
||||
if crt.Spec.PrivateKey == nil {
|
||||
crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{}
|
||||
}
|
||||
|
||||
signer, err := pki.GeneratePrivateKeyForCertificate(crt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when generating new private key for CertificateRequest: %w", err)
|
||||
}
|
||||
|
||||
keyData, err := pki.EncodePrivateKey(signer, crt.Spec.PrivateKey.Encoding)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encode new private key for CertificateRequest: %w", err)
|
||||
}
|
||||
|
||||
crName := args[0]
|
||||
|
||||
// Storing private key to file
|
||||
keyFileName := crName + ".key"
|
||||
if o.KeyFilename != "" {
|
||||
keyFileName = o.KeyFilename
|
||||
}
|
||||
if err := os.WriteFile(keyFileName, keyData, 0600); err != nil {
|
||||
return fmt.Errorf("error when writing private key to file: %w", err)
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "Private key written to file %s\n", keyFileName)
|
||||
|
||||
// Build CertificateRequest with name as specified by argument
|
||||
req, err := buildCertificateRequest(crt, keyData, crName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when building CertificateRequest: %w", err)
|
||||
}
|
||||
|
||||
ns := crt.Namespace
|
||||
if ns == "" {
|
||||
ns = o.Namespace
|
||||
}
|
||||
req, err = o.CMClient.CertmanagerV1().CertificateRequests(ns).Create(ctx, req, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating CertificateRequest: %w", err)
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "CertificateRequest %s has been created in namespace %s\n", req.Name, req.Namespace)
|
||||
|
||||
if o.FetchCert {
|
||||
fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has not been signed yet. Wait until it is signed...\n",
|
||||
req.Name, req.Namespace)
|
||||
err = wait.PollUntilContextTimeout(ctx, time.Second, o.Timeout, false, func(ctx context.Context) (done bool, err error) {
|
||||
req, err = o.CMClient.CertmanagerV1().CertificateRequests(req.Namespace).Get(ctx, req.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil //nolint: nilerr // Retry and keep polling until context is cancelled
|
||||
}
|
||||
return apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{
|
||||
Type: cmapi.CertificateRequestConditionReady,
|
||||
Status: cmmeta.ConditionTrue,
|
||||
}) && len(req.Status.Certificate) > 0, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when waiting for CertificateRequest to be signed: %w", err)
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has been signed\n", req.Name, req.Namespace)
|
||||
|
||||
// Fetch x509 certificate and store to file
|
||||
actualCertFileName := req.Name + ".crt"
|
||||
if o.CertFileName != "" {
|
||||
actualCertFileName = o.CertFileName
|
||||
}
|
||||
err = fetchCertificateFromCR(req, actualCertFileName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when writing certificate to file: %w", err)
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "Certificate written to file %s\n", actualCertFileName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Builds a CertificateRequest
|
||||
func buildCertificateRequest(crt *cmapi.Certificate, pk []byte, crName string) (*cmapi.CertificateRequest, error) {
|
||||
csrPEM, err := generateCSR(crt, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cr := &cmapi.CertificateRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: crName,
|
||||
Annotations: crt.Annotations,
|
||||
Labels: crt.Labels,
|
||||
},
|
||||
Spec: cmapi.CertificateRequestSpec{
|
||||
Request: csrPEM,
|
||||
Duration: crt.Spec.Duration,
|
||||
IssuerRef: crt.Spec.IssuerRef,
|
||||
IsCA: crt.Spec.IsCA,
|
||||
Usages: crt.Spec.Usages,
|
||||
},
|
||||
}
|
||||
|
||||
return cr, nil
|
||||
}
|
||||
|
||||
func generateCSR(crt *cmapi.Certificate, pk []byte) ([]byte, error) {
|
||||
csr, err := pki.GenerateCSR(crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signer, err := pki.DecodePrivateKeyBytes(pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
csrDER, err := pki.EncodeCSR(csr, signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
csrPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE REQUEST", Bytes: csrDER,
|
||||
})
|
||||
|
||||
return csrPEM, nil
|
||||
}
|
||||
|
||||
// fetchCertificateFromCR fetches the x509 certificate from a CR and stores the
|
||||
// certificate in file specified by certFilename. Assumes CR is ready,
|
||||
// otherwise returns error.
|
||||
func fetchCertificateFromCR(req *cmapi.CertificateRequest, certFileName string) error {
|
||||
// If CR not ready yet, error
|
||||
if !apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{
|
||||
Type: cmapi.CertificateRequestConditionReady,
|
||||
Status: cmmeta.ConditionTrue,
|
||||
}) || len(req.Status.Certificate) == 0 {
|
||||
return errors.New("CertificateRequest is not ready yet, unable to fetch certificate")
|
||||
}
|
||||
|
||||
// Store certificate to file
|
||||
err := os.WriteFile(certFileName, req.Status.Certificate, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when writing certificate to file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"schema": "custodian.keycape-tls-request-cleanup-source-proposal.v1",
|
||||
"status": "not executed; no actual request UID exists",
|
||||
"target": {
|
||||
"node_ip": "92.205.62.239",
|
||||
"namespace": "sso",
|
||||
"name": "nk49-kc-drill-20261017-r1",
|
||||
"group_version": "cert-manager.io/v1",
|
||||
"resource": "certificaterequests"
|
||||
},
|
||||
"create_binding": {
|
||||
"run_label": "net-kingdom/recovery-run=<bound run_uuid before key output>",
|
||||
"source_annotation": "net-kingdom/tls-reissue-source=<reviewed source sha256>",
|
||||
"expected_issuer": {
|
||||
"group": "cert-manager.io",
|
||||
"kind": "ClusterIssuer",
|
||||
"name": "letsencrypt-prod"
|
||||
},
|
||||
"public_spki_and_csr_hash": "derived/verified inside separately approved private custody; no key exposed",
|
||||
"caller_and_template_spec_hash": "exact admitted owner caller plus frozen public input"
|
||||
},
|
||||
"delete_argv_template": [
|
||||
"<same admitted owner kubectl>",
|
||||
"--request-timeout=30s",
|
||||
"delete",
|
||||
"--raw",
|
||||
"/apis/cert-manager.io/v1/namespaces/sso/certificaterequests/nk49-kc-drill-20261017-r1",
|
||||
"-f",
|
||||
"-"
|
||||
],
|
||||
"stdin_payload_template": {
|
||||
"apiVersion": "v1",
|
||||
"kind": "DeleteOptions",
|
||||
"preconditions": {
|
||||
"uid": "<actual observed and custody-bound CertificateRequest UID>"
|
||||
},
|
||||
"propagationPolicy": "Foreground"
|
||||
},
|
||||
"required_before_delete": [
|
||||
"fresh cluster/account binding",
|
||||
"exact observed UID plus held run/spec/SPKI/CSR/caller commitments",
|
||||
"durable public request and descendant obligations; local writer quiescent if submission was uncertain"
|
||||
],
|
||||
"required_after_delete": [
|
||||
"same recorded UID is absent or deletion remains uncertain",
|
||||
"different UID at same name remains untouched; record collision",
|
||||
"actual Order->CertificateRequest, Challenge->Order and solver->Challenge ownerReference UID chains are reconciled; do not infer from name/label",
|
||||
"controller/API/finalizer timeout remains unresolved; no wildcard cleanup"
|
||||
],
|
||||
"forbidden": [
|
||||
"kubectl delete certificaterequest NAME without UID preconditions",
|
||||
"production Certificate/Secret/Ingress mutation",
|
||||
"broad Order/Challenge/solver deletion",
|
||||
"one post-timeout NotFound treated as proof no late Create"
|
||||
],
|
||||
"unknown_uid": "No delete. Preserve exact name/run/spec/SPKI intent and reconcile actual UID through owner API; unresolved if ownership cannot be established.",
|
||||
"native_api_calls": 0
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"scope": "this source-preparation sandbox only, not an admitted native custody host",
|
||||
"mountinfo": [
|
||||
"945 943 0:65 / /dev/shm ro,nosuid,nodev,noatime master:20 - tmpfs none rw"
|
||||
],
|
||||
"usable_private_staging_claimed": false,
|
||||
"mount_or_tmpfs_write_attempts": 0
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"schema": "custodian.tls-staging-cleanup-source.v1",
|
||||
"status": "source prepared only",
|
||||
"native_execution_authorized": false,
|
||||
"files": {
|
||||
"OWNER-REVIEW.md": "sha256:f2380217eef95148951f00d0a01b634fe9a2af1cda93bca5ed0652f92157e6e6",
|
||||
"cmctl-public-source.go": "sha256:0ba0c2d3d4f8530514c8d864b2a9e056f14f763a0b314aa05998f3169ee5bc32",
|
||||
"delete-request-contract.json": "sha256:8dae54b516d67c2069eeffbf6a3ab9ac391e4f386971cddb4dfbb587143afa86",
|
||||
"local-tmpfs-readonly-observation.json": "sha256:e7cbc7bd1e1d3e4a4282c87da6c689f341a06a74840ee0ed770368ff0c809270",
|
||||
"owner-boundary.preimage.md": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70",
|
||||
"owner-boundary.proposed.md": "sha256:6daec76f0c220e433dcc0bfafbd4bb922a4a19606cbd74e76e50be9883ae796b",
|
||||
"owner-doc.patch": "sha256:df565c58026150cd95833b4472610fc90db1ab5fccc90d2bca36494ca77f3c4f",
|
||||
"review.json": "sha256:5e72c13f4284fe6c4a418a8af93aacbe3ebdce05b3536723f2626354e3fbec6a",
|
||||
"source-pins.json": "sha256:de93f3cc6689fad2ee00e39ea93d135950fa13e9cdc32a4718f4bf2f4e7b00ab",
|
||||
"staging-reaper-contract.json": "sha256:c4d0ce5159708303e1d376ab384a483ac79325b11c85dbd5840891667d65beed"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Original KeyCape TLS recovery boundary
|
||||
|
||||
Source disposition, 2026-10-17, scoped to railiance-cluster INTENT: cluster runtime,
|
||||
ingress/certificate plumbing and backup posture. This is source preparation only.
|
||||
It is not native acceptance, an issuer/key custody assent, a reissue decision or
|
||||
permission to mutate the cluster.
|
||||
|
||||
NetKingdom's ingress source names `kc.coulomb.social`, `sso/kc-tls`,
|
||||
`ClusterIssuer/letsencrypt-prod` and Traefik termination before KeyCape8080.
|
||||
NetKingdom owns that namespace intent; railiance-cluster owns cert-manager,
|
||||
ingress controller and cluster backup posture. No inspected source establishes
|
||||
who independently holds the original private TLS recovery material when the
|
||||
ordinary issuer/cluster is unavailable. A missing exact routing-catalog entry
|
||||
cannot prove absence of an owning subsystem.
|
||||
|
||||
The identity archive excludes `kc-tls`. Current S2 backup source encrypts SQLite
|
||||
state, Helm values and kubeconfig to the same host's `/opt/backup/railiance/cluster`
|
||||
and retains seven versions. No inspected source proves an actually fresh,
|
||||
independent offsite object or original certificate/key/trust recovery. Archived
|
||||
RAIL-BS-WP-0004 is historical local-backup delivery; backlog RCLUSTER-WP-0007-T05
|
||||
is gated HA issuance/renewal; active RCLUSTER-WP-0017 is signer runtime/storage.
|
||||
None is an existing live task for this original TLS recovery demand.
|
||||
|
||||
`railiance-backup-s2` also stages raw state/Helm output in named `/tmp` paths
|
||||
without early hard-loss cleanup; `railiance-restore-s2` prints whole-state restore
|
||||
instructions. Do not use either as an isolated TLS extraction path. RCLUSTER-WP-0018
|
||||
tracks exact inventory, safe private staging/extraction preparation where required,
|
||||
independent outage proof and future archive-boundary disposition. No original
|
||||
ciphertext or historical outcome is rewritten by that work.
|
||||
|
||||
`tools/public-tls-metadata.py` is an offline public-only step. After the source
|
||||
owner identifies independent original **public certificate/chain and trust files**:
|
||||
|
||||
```sh
|
||||
python3 tools/public-tls-metadata.py --public-cert ORIGINAL_PUBLIC_CERT_CHAIN.pem --public-trust ORIGINAL_PUBLIC_TRUST.pem
|
||||
```
|
||||
|
||||
It accepts no private-key argument, bounds regular-file reads, refuses symlinks and
|
||||
non-certificate PEM material, and reports public hashes/SANs/validity/counts only.
|
||||
The file names are owner-local placeholders, not a key request. Output establishes
|
||||
public metadata, not originality, hostname/chain acceptance, reissue permission or
|
||||
custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed
|
||||
when original source, trust or exact bindings are missing; no fresh self-signed
|
||||
trust workaround is admitted.
|
||||
|
||||
For FUTURE NetKingdom archives, the source owners must explicitly disposition
|
||||
original TLS coverage or a reviewed reissue contract: producer/custody owner,
|
||||
private artifact boundary, offline recovery independence, original public hashes,
|
||||
scoped capture/read permissions, retention and native verification. Merely adding
|
||||
`kc-tls` to secret_refs would change capture/permission/custody scope and is not
|
||||
authorized by this source review. It cannot repair the current archive retroactively.
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
# Original KeyCape TLS recovery boundary
|
||||
|
||||
Source disposition, 2026-10-17, scoped to railiance-cluster INTENT: cluster runtime,
|
||||
ingress/certificate plumbing and backup posture. This is source preparation only.
|
||||
It is not native acceptance, an issuer/key custody assent, a reissue decision or
|
||||
permission to mutate the cluster.
|
||||
|
||||
NetKingdom's ingress source names `kc.coulomb.social`, `sso/kc-tls`,
|
||||
`ClusterIssuer/letsencrypt-prod` and Traefik termination before KeyCape8080.
|
||||
NetKingdom owns that namespace intent; railiance-cluster owns cert-manager,
|
||||
ingress controller and cluster backup posture. No inspected source establishes
|
||||
who independently holds the original private TLS recovery material when the
|
||||
ordinary issuer/cluster is unavailable. A missing exact routing-catalog entry
|
||||
cannot prove absence of an owning subsystem.
|
||||
|
||||
The identity archive excludes `kc-tls`. Current S2 backup source encrypts SQLite
|
||||
state, Helm values and kubeconfig to the same host's `/opt/backup/railiance/cluster`
|
||||
and retains seven versions. No inspected source proves an actually fresh,
|
||||
independent offsite object or original certificate/key/trust recovery. Archived
|
||||
RAIL-BS-WP-0004 is historical local-backup delivery; backlog RCLUSTER-WP-0007-T05
|
||||
is gated HA issuance/renewal; active RCLUSTER-WP-0017 is signer runtime/storage.
|
||||
None is an existing live task for this original TLS recovery demand.
|
||||
|
||||
`railiance-backup-s2` also stages raw state/Helm output in named `/tmp` paths
|
||||
without early hard-loss cleanup; `railiance-restore-s2` prints whole-state restore
|
||||
instructions. Do not use either as an isolated TLS extraction path. RCLUSTER-WP-0018
|
||||
tracks exact inventory, safe private staging/extraction preparation where required,
|
||||
independent outage proof and future archive-boundary disposition. No original
|
||||
ciphertext or historical outcome is rewritten by that work.
|
||||
|
||||
`tools/public-tls-metadata.py` is an offline public-only step. After the source
|
||||
owner supplies the **selected public certificate/chain and independent trust files**:
|
||||
|
||||
```sh
|
||||
python3 tools/public-tls-metadata.py --public-cert SELECTED_PUBLIC_CERT_CHAIN.pem --public-trust SELECTED_PUBLIC_TRUST.pem
|
||||
```
|
||||
|
||||
It accepts no private-key argument, bounds regular-file reads, refuses symlinks and
|
||||
non-certificate PEM material, and reports public hashes/SANs/validity/counts only.
|
||||
The file names are owner-local placeholders, not a key request. Output establishes
|
||||
public metadata, not originality, hostname/chain acceptance, reissue permission or
|
||||
custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed
|
||||
when selected source, independent trust or exact attempt bindings are missing;
|
||||
no fresh self-signed trust workaround is admitted. This utility does not require
|
||||
historical ingress leaf/key bytes when a trusted renewed leaf is selected under
|
||||
the existing reviewed attempt.
|
||||
|
||||
For FUTURE NetKingdom archives, the source owners must explicitly disposition
|
||||
original TLS coverage or a reviewed reissue contract: producer/custody owner,
|
||||
private artifact boundary, offline recovery independence, original public hashes,
|
||||
scoped capture/read permissions, retention and native verification. Merely adding
|
||||
`kc-tls` to secret_refs would change capture/permission/custody scope and is not
|
||||
authorized by this source review. It cannot repair the current archive retroactively.
|
||||
|
||||
## Renewable TLS leaf and original OIDC signing identity
|
||||
|
||||
The archived KeyCape RS256 signing key, issuer URL, service registrations and
|
||||
policy state are distinct from the public HTTPS leaf and its TLS private key.
|
||||
The current identity archive has no ingress TLS leaf to compare. A separately
|
||||
reviewed trusted reissue can preserve kc.coulomb.social and the archived OIDC
|
||||
signing identity without reproducing historical TLS leaf/key bytes. This is an
|
||||
explicit owner continuity disposition under NK49-T35, not implicit permission
|
||||
to replace custody, trust or an outage claim.
|
||||
|
||||
The existing isolated admission pins the exact certificate-chain and trust PEM
|
||||
bytes selected for that attempt; it does not compare them with an archived leaf
|
||||
fingerprint. Those hashes, certificate/key pairing, hostname/CA/validity checks,
|
||||
archived issuer equality and original signer/JWKS verification remain required.
|
||||
The receipt's original HTTPS issuer/trust wording does not assert original leaf
|
||||
byte equality.
|
||||
Current source and public resource inventory establish a concrete standard path:
|
||||
ClusterIssuer/letsencrypt-prod uses ACME HTTP-01 with Traefik. Upstream cmctl
|
||||
create certificaterequest can generate a dedicated TLS key locally, send only a
|
||||
public CSR to that existing issuer and return the signed certificate locally,
|
||||
without reading or replacing sso/kc-tls. This creates a new public request and
|
||||
normal temporary ACME resources and requires separate actual owner/founder
|
||||
live authority. A Certificate YAML used as cmctl input is a local template, not
|
||||
an apply of a Certificate or Secret. No issuance occurred in this source work.
|
||||
|
||||
The reviewed candidate is cmctl v2.6.1 Linux amd64, published checksum
|
||||
sha256:0af054c26a2b64ce286fa868d029164867695a93c3eb893662ce16f35e708db0,
|
||||
source commit 7e56321dbec4f62ea5428b8656c871c6dc0cc112. It is not installed or
|
||||
admitted by this document; signature-bundle verification remains unperformed.
|
||||
Its key file is written before API submission, so protected tmpfs staging and
|
||||
independent cleanup must precede invocation. T03 must admit the existing session
|
||||
staging/reaper adaptation for that earlier networked child, with success,
|
||||
refusal, timeout and parent-loss proof; a shell trap alone is insufficient.
|
||||
|
||||
This is a supported candidate for a standalone drill while the cluster, DNS,
|
||||
external HTTP-01 port 80, Traefik, cert-manager and ACME provider are available.
|
||||
It proves no independence during cluster loss. Do not switch to DNS-01 or a new
|
||||
provider, read an account key, delete the production Secret or call a surviving-
|
||||
cluster reissue an independent cluster-loss recovery. T02/T03/T04 retain that
|
||||
actual independent custody/provider/domain-control and native acceptance scope.
|
||||
|
||||
Timestamped current public Certificate/issuer/controller/solver metadata, public
|
||||
CA/hostname observation, source hashes, upstream contract and exact unexecuted
|
||||
command/lifecycle proposal are retained in Custodian
|
||||
`docs/changes/netkingdom-target-2026-10-17/tls-recovery-disposition-r1/`.
|
||||
This source inventory is neither historical original-key custody nor owner
|
||||
acceptance of reissue; T35 requires the explicit reviewed disposition before
|
||||
T33 can bind the selected TLS material to an actual owner-held attempt.
|
||||
|
||||
## Earlier private staging and exact public request cleanup
|
||||
|
||||
T03 source preparation must register the original guard-compatible private0700
|
||||
/dev/shm directory and independently surviving pidfd/descendant reaper before
|
||||
cmctl can write a key. Verify actual writable tmpfs/mount/device/inode before
|
||||
use; the existing later session reaper is Docker-bound and is not already an
|
||||
issuance guard. Preserve exact child quiescence and an immutable public checkpoint
|
||||
before inode-guarded deletion. Reap dead adopted zombies; still refuse live or
|
||||
unmapped descendants. A shell trap or immediate-child timeout is insufficient.
|
||||
|
||||
Keep cmctl, TLS staging and the original six-argument local recovery launcher on
|
||||
one admitted custody host. A workstation context name is not cluster identity;
|
||||
bind the existing owner API profile to verified node92.205.62.239. Moving only
|
||||
cmctl to another host would introduce a separate private-key transfer and is not
|
||||
part of this source disposition. The existing T33/T35 native review binds the
|
||||
actual host/tool/target; this paragraph creates no new TLS mode or policy gate.
|
||||
|
||||
The source copies local template run labels/annotations to its CertificateRequest.
|
||||
Record exact public request namespace/name, run/spec/CSR/public-key commitments,
|
||||
admitted caller and actual UID. Cleanup uses the existing Kubernetes raw DELETE
|
||||
idiom with DeleteOptions.preconditions.uid and Foreground propagation, then checks
|
||||
that UID and its actual owner-UID descendants. Never delete by prefix/label/name
|
||||
alone or touch production kc-tls. A killed client or one NotFound cannot prove
|
||||
no late accepted Create; preserve the exact unresolved obligation and reconcile
|
||||
through the owner API. Local plaintext cleanup and remote resource cleanup have
|
||||
separate verified/uncertain outcomes, with no blind retry or false global success.
|
||||
|
||||
The concrete T03 source delta, UID-delete contract and required generated lifecycle
|
||||
counterexamples are in Custodian
|
||||
`docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/`.
|
||||
It is a source proposal, not implemented/native cleanup proof. Existing T02–T04
|
||||
and NK49T35/T33 gates/statuses remain unchanged; no new task or UUID is needed.
|
||||
|
||||
The original disaster guide is already located in publication commit
|
||||
31f483966cdfca4df1d326dee3ec0b6d33ea0e5e at Backup account path
|
||||
`railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md`.
|
||||
Historical readback does not establish current remote visibility or ingress TLS
|
||||
coverage. No renewed request for an unspecified original TLS backup is needed
|
||||
to prepare this separate trusted-leaf path; genuine cluster-loss independence
|
||||
and actual provider/domain-control/custody proof remain existing owner work.
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
--- a/docs/keycape-tls-recovery-boundary.md
|
||||
+++ b/docs/keycape-tls-recovery-boundary.md
|
||||
@@ -29,10 +29,10 @@
|
||||
ciphertext or historical outcome is rewritten by that work.
|
||||
|
||||
`tools/public-tls-metadata.py` is an offline public-only step. After the source
|
||||
-owner identifies independent original **public certificate/chain and trust files**:
|
||||
+owner supplies the **selected public certificate/chain and independent trust files**:
|
||||
|
||||
```sh
|
||||
-python3 tools/public-tls-metadata.py --public-cert ORIGINAL_PUBLIC_CERT_CHAIN.pem --public-trust ORIGINAL_PUBLIC_TRUST.pem
|
||||
+python3 tools/public-tls-metadata.py --public-cert SELECTED_PUBLIC_CERT_CHAIN.pem --public-trust SELECTED_PUBLIC_TRUST.pem
|
||||
```
|
||||
|
||||
It accepts no private-key argument, bounds regular-file reads, refuses symlinks and
|
||||
@@ -40,8 +40,10 @@
|
||||
The file names are owner-local placeholders, not a key request. Output establishes
|
||||
public metadata, not originality, hostname/chain acceptance, reissue permission or
|
||||
custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed
|
||||
-when original source, trust or exact bindings are missing; no fresh self-signed
|
||||
-trust workaround is admitted.
|
||||
+when selected source, independent trust or exact attempt bindings are missing;
|
||||
+no fresh self-signed trust workaround is admitted. This utility does not require
|
||||
+historical ingress leaf/key bytes when a trusted renewed leaf is selected under
|
||||
+the existing reviewed attempt.
|
||||
|
||||
For FUTURE NetKingdom archives, the source owners must explicitly disposition
|
||||
original TLS coverage or a reviewed reissue contract: producer/custody owner,
|
||||
@@ -49,3 +51,93 @@
|
||||
scoped capture/read permissions, retention and native verification. Merely adding
|
||||
`kc-tls` to secret_refs would change capture/permission/custody scope and is not
|
||||
authorized by this source review. It cannot repair the current archive retroactively.
|
||||
+
|
||||
+## Renewable TLS leaf and original OIDC signing identity
|
||||
+
|
||||
+The archived KeyCape RS256 signing key, issuer URL, service registrations and
|
||||
+policy state are distinct from the public HTTPS leaf and its TLS private key.
|
||||
+The current identity archive has no ingress TLS leaf to compare. A separately
|
||||
+reviewed trusted reissue can preserve kc.coulomb.social and the archived OIDC
|
||||
+signing identity without reproducing historical TLS leaf/key bytes. This is an
|
||||
+explicit owner continuity disposition under NK49-T35, not implicit permission
|
||||
+to replace custody, trust or an outage claim.
|
||||
+
|
||||
+The existing isolated admission pins the exact certificate-chain and trust PEM
|
||||
+bytes selected for that attempt; it does not compare them with an archived leaf
|
||||
+fingerprint. Those hashes, certificate/key pairing, hostname/CA/validity checks,
|
||||
+archived issuer equality and original signer/JWKS verification remain required.
|
||||
+The receipt's original HTTPS issuer/trust wording does not assert original leaf
|
||||
+byte equality.
|
||||
+Current source and public resource inventory establish a concrete standard path:
|
||||
+ClusterIssuer/letsencrypt-prod uses ACME HTTP-01 with Traefik. Upstream cmctl
|
||||
+create certificaterequest can generate a dedicated TLS key locally, send only a
|
||||
+public CSR to that existing issuer and return the signed certificate locally,
|
||||
+without reading or replacing sso/kc-tls. This creates a new public request and
|
||||
+normal temporary ACME resources and requires separate actual owner/founder
|
||||
+live authority. A Certificate YAML used as cmctl input is a local template, not
|
||||
+an apply of a Certificate or Secret. No issuance occurred in this source work.
|
||||
+
|
||||
+The reviewed candidate is cmctl v2.6.1 Linux amd64, published checksum
|
||||
+sha256:0af054c26a2b64ce286fa868d029164867695a93c3eb893662ce16f35e708db0,
|
||||
+source commit 7e56321dbec4f62ea5428b8656c871c6dc0cc112. It is not installed or
|
||||
+admitted by this document; signature-bundle verification remains unperformed.
|
||||
+Its key file is written before API submission, so protected tmpfs staging and
|
||||
+independent cleanup must precede invocation. T03 must admit the existing session
|
||||
+staging/reaper adaptation for that earlier networked child, with success,
|
||||
+refusal, timeout and parent-loss proof; a shell trap alone is insufficient.
|
||||
+
|
||||
+This is a supported candidate for a standalone drill while the cluster, DNS,
|
||||
+external HTTP-01 port 80, Traefik, cert-manager and ACME provider are available.
|
||||
+It proves no independence during cluster loss. Do not switch to DNS-01 or a new
|
||||
+provider, read an account key, delete the production Secret or call a surviving-
|
||||
+cluster reissue an independent cluster-loss recovery. T02/T03/T04 retain that
|
||||
+actual independent custody/provider/domain-control and native acceptance scope.
|
||||
+
|
||||
+Timestamped current public Certificate/issuer/controller/solver metadata, public
|
||||
+CA/hostname observation, source hashes, upstream contract and exact unexecuted
|
||||
+command/lifecycle proposal are retained in Custodian
|
||||
+`docs/changes/netkingdom-target-2026-10-17/tls-recovery-disposition-r1/`.
|
||||
+This source inventory is neither historical original-key custody nor owner
|
||||
+acceptance of reissue; T35 requires the explicit reviewed disposition before
|
||||
+T33 can bind the selected TLS material to an actual owner-held attempt.
|
||||
+
|
||||
+## Earlier private staging and exact public request cleanup
|
||||
+
|
||||
+T03 source preparation must register the original guard-compatible private0700
|
||||
+/dev/shm directory and independently surviving pidfd/descendant reaper before
|
||||
+cmctl can write a key. Verify actual writable tmpfs/mount/device/inode before
|
||||
+use; the existing later session reaper is Docker-bound and is not already an
|
||||
+issuance guard. Preserve exact child quiescence and an immutable public checkpoint
|
||||
+before inode-guarded deletion. Reap dead adopted zombies; still refuse live or
|
||||
+unmapped descendants. A shell trap or immediate-child timeout is insufficient.
|
||||
+
|
||||
+Keep cmctl, TLS staging and the original six-argument local recovery launcher on
|
||||
+one admitted custody host. A workstation context name is not cluster identity;
|
||||
+bind the existing owner API profile to verified node92.205.62.239. Moving only
|
||||
+cmctl to another host would introduce a separate private-key transfer and is not
|
||||
+part of this source disposition. The existing T33/T35 native review binds the
|
||||
+actual host/tool/target; this paragraph creates no new TLS mode or policy gate.
|
||||
+
|
||||
+The source copies local template run labels/annotations to its CertificateRequest.
|
||||
+Record exact public request namespace/name, run/spec/CSR/public-key commitments,
|
||||
+admitted caller and actual UID. Cleanup uses the existing Kubernetes raw DELETE
|
||||
+idiom with DeleteOptions.preconditions.uid and Foreground propagation, then checks
|
||||
+that UID and its actual owner-UID descendants. Never delete by prefix/label/name
|
||||
+alone or touch production kc-tls. A killed client or one NotFound cannot prove
|
||||
+no late accepted Create; preserve the exact unresolved obligation and reconcile
|
||||
+through the owner API. Local plaintext cleanup and remote resource cleanup have
|
||||
+separate verified/uncertain outcomes, with no blind retry or false global success.
|
||||
+
|
||||
+The concrete T03 source delta, UID-delete contract and required generated lifecycle
|
||||
+counterexamples are in Custodian
|
||||
+`docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/`.
|
||||
+It is a source proposal, not implemented/native cleanup proof. Existing T02–T04
|
||||
+and NK49T35/T33 gates/statuses remain unchanged; no new task or UUID is needed.
|
||||
+
|
||||
+The original disaster guide is already located in publication commit
|
||||
+31f483966cdfca4df1d326dee3ec0b6d33ea0e5e at Backup account path
|
||||
+`railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md`.
|
||||
+Historical readback does not establish current remote visibility or ingress TLS
|
||||
+coverage. No renewed request for an unspecified original TLS backup is needed
|
||||
+to prepare this separate trusted-leaf path; genuine cluster-loss independence
|
||||
+and actual provider/domain-control/custody proof remain existing owner work.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"status": "exact source delta ready for owner review; no staging implementation or native proof claimed",
|
||||
"canonical_source_edits": false,
|
||||
"runtime_private_or_cluster_calls": 0,
|
||||
"native_certificate_request_download_install_or_credential_reads": false,
|
||||
"redundant_tls_mode_or_policy_gate_added": false,
|
||||
"original_archive_oidc_signing_key_and_issuer_invariants_preserved": true,
|
||||
"source_only_publication_recommendation": "One existing Cluster boundary doc can be reviewed/published now after actual source-owner review; captured preimage/postimage/patch only. No WP status/UUID/T06 addition needed.",
|
||||
"concrete_gaps": [
|
||||
"pre-key actual rw tmpfs registration and observer acknowledgment",
|
||||
"Docker-specific existing reaper cannot supervise earlier networked CSR child; exact descendant adoption/parent-loss cleanup needed",
|
||||
"cmctl output-file writes require protected absent-name boundary",
|
||||
"CertificateRequest lost-create response / exact run-SPKI-spec-caller UID ownership / Foreground delete and actual descendant cleanup",
|
||||
"one admitted custody host and bound API target; no invented private-key transfer",
|
||||
"preserve original attended TTY / hidden prompt / sealed-fd launcher contract, not DEVNULL wrapper"
|
||||
],
|
||||
"actual_native_cause_limit": "source and prior local process fixture evidence only; no native TLS issuance/recovery cause diagnosed",
|
||||
"cluster_loss_limit": "existing surviving-cluster HTTP01 route unavailable during cluster loss; independent custody/provider/domain-control remains existing T02\u2013T04 work",
|
||||
"guide_source_located": {
|
||||
"commit": "31f483966cdfca4df1d326dee3ec0b6d33ea0e5e",
|
||||
"path": "Backup/railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md",
|
||||
"remote_reread": false,
|
||||
"another_original_tls_backup_request": false
|
||||
},
|
||||
"tests": "No new permanent or dummy tests; exact generated lifecycle/TTY/UID-negative proof is an explicit T03 implementation deliverable, not claimed here.",
|
||||
"next_owner_source_scope": "existing T03 bounded issuance custody adapter using existing NetKingdom inode cleanup and owner Kubernetes UID-delete idiom; original T33 launcher interface unchanged",
|
||||
"authority": "fresh actual owner/founder approval remains required for any native issuance/action; this packet grants none"
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"observed_at": "2026-10-17T10:47:12.320878+00:00",
|
||||
"references": [
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/AGENTS.md",
|
||||
"sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/isolated-keycape-session.py",
|
||||
"sha256": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/isolated-keycape.py",
|
||||
"sha256": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/prepare-isolated-keycape.py",
|
||||
"sha256": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/run-isolated-keycape.sh",
|
||||
"sha256": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/capture-identity.py",
|
||||
"sha256": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/railiance-platform/scripts/native_factory_acceptance.py",
|
||||
"sha256": "sha256:291646308a2a749f858638f9f4fa0db33cf545e8b4a0c09c30e884a7be8e4bc0"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/railiance-cluster/AGENTS.md",
|
||||
"sha256": "sha256:5cc7808a6d0e5cdebc7b3f13a0d7dce9cee5441ed6de4703b67cf3fe1800d45b"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/railiance-cluster/docs/keycape-tls-recovery-boundary.md",
|
||||
"sha256": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md",
|
||||
"sha256": "sha256:96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/the-custodian/docs/agent-environment-orientation.md",
|
||||
"sha256": "sha256:6eb712593adaeb2efd8c69edb22b02662e6c9b155f84f1559e7bdaeb76730439"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/storage-share-tls-r1/source-history-followthrough-r2.json",
|
||||
"sha256": "sha256:51a6cf3547f0b9aac1620c472c933bd3eb7213200d78397bf8d851ea4f3f861a"
|
||||
},
|
||||
{
|
||||
"path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r3/local-fixture-results.json",
|
||||
"sha256": "sha256:339b2fcfd8d407e09874592b681830c605a463a88841351eed494a182d677219"
|
||||
}
|
||||
],
|
||||
"upstream_cmctl_source_url": "https://raw.githubusercontent.com/cert-manager/cmctl/7e56321dbec4f62ea5428b8656c871c6dc0cc112/pkg/create/certificaterequest/certificaterequest.go",
|
||||
"public_source_sha256": "sha256:0ba0c2d3d4f8530514c8d864b2a9e056f14f763a0b314aa05998f3169ee5bc32",
|
||||
"matches_frozen_upstream_pin": true,
|
||||
"tls_r1_all_frozen_entries_unchanged": true,
|
||||
"owner_boundary_canonical_equals_preimage": true
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
"schema": "custodian.tls-staging-reaper-source-boundary.v1",
|
||||
"status": "owner source proposal; no implementation/native lifecycle proof claimed",
|
||||
"existing_tasks": [
|
||||
"RCLUSTER-WP-0018-T03",
|
||||
"NK-WP-0049-T35",
|
||||
"NK-WP-0049-T33"
|
||||
],
|
||||
"execution_locus": "one admitted host for cmctl/tmpfs/original launcher; exact host/account/tool/API profile unresolved, no private transfer assumed",
|
||||
"staging": {
|
||||
"root": "/dev/shm",
|
||||
"name_pattern": "nk49-keycape-{run_uuid}-{eight_random_chars}",
|
||||
"mode": "0700",
|
||||
"key_mode": "0600",
|
||||
"mount_checks_before_key": [
|
||||
"actual writable tmpfs",
|
||||
"mount ID/device and owner UID bound",
|
||||
"no parent alias/replacement",
|
||||
"bounded free space"
|
||||
],
|
||||
"file_rules": "absent output names; regular owner-only single-link; 1MiB per-file child RLIMIT_FSIZE; disable core dumps before private output",
|
||||
"read_limit_bytes": 1048576,
|
||||
"receipt": "bounded immutable public-only metadata checkpoint before private cleanup; no private material"
|
||||
},
|
||||
"states": [
|
||||
"public_source_and_owner_target_bound",
|
||||
"tmpfs_inode_registered",
|
||||
"observer_acknowledged",
|
||||
"submit_intent_durable",
|
||||
"cmctl_started",
|
||||
"request_uid_observed_or_submit_uncertain",
|
||||
"certificate_verified_or_failed",
|
||||
"original_launcher_consumed_or_not_started",
|
||||
"exact_local_children_quiescent",
|
||||
"public_commitments_and_outstanding_duties_durable",
|
||||
"registered_private_inode_removed_or_cleanup_unverified",
|
||||
"request_and_owned_children_absent_or_remote_cleanup_uncertain"
|
||||
],
|
||||
"absolute_bounds_seconds": {
|
||||
"issuance_total_from_private_staging_start": 330,
|
||||
"cmctl_fetch_flag": 300,
|
||||
"existing_recovery_child_maximum": 1800,
|
||||
"single_private_execution_deadline": 2130,
|
||||
"nonrenewable_cleanup_maximum": 60,
|
||||
"total_including_cleanup": 2190,
|
||||
"term_grace": 0.5,
|
||||
"kill_reap": 3,
|
||||
"watchdog_wait_maximum": 8,
|
||||
"api_request_maximum_clipped_to_cleanup_remaining": 30
|
||||
},
|
||||
"deadline_rules": [
|
||||
"one original monotonic private execution budget, no renewal across phases",
|
||||
"no new child after deadline",
|
||||
"subreaper stops and waits exact trees before local delete",
|
||||
"cleanup operations clipped to same original 60s cleanup remainder; outstanding remote duties survive timeout",
|
||||
"existing original launcher reaper and Docker obligations remain separately receipt-bound"
|
||||
],
|
||||
"readiness": "no observer ack means zero cmctl/key generation",
|
||||
"creation_uncertainty": "kill/client timeout does not cancel accepted API mutation; preserve pending creation obligation if UID not durably reconciled",
|
||||
"authority": "existing T33/T35/RCLUSTER18 source/native owner process; no new TLS mode or approval field",
|
||||
"observed_local_sandbox_tmpfs": "/dev/shm actual mount is ro,nosuid,nodev,noatime; no usable local private staging or tmpfs proof asserted",
|
||||
"limitations": [
|
||||
"local tmpfs does not establish unswappable memory, root/hypervisor isolation or host-loss receipts",
|
||||
"surviving-cluster HTTP01 path only; independent cluster-loss recovery remains open"
|
||||
],
|
||||
"child_io": {
|
||||
"cmctl": "stdin/stdout/stderr DEVNULL; no custody fd",
|
||||
"original_launcher": "existing attended TTY path preserved; original hidden prompt/sealed fd; no PTY proxy/logging",
|
||||
"observer": "pidfds and public metadata only; close unrelated/secret fds"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
WARN: git commit failed for writeback: Generated-only commits rejected: staged
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
"""Read-only fresh comparison against the retained verified-client baseline."""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
BASE = Path(__file__).resolve().parent
|
||||
RECEIVER = BASE / 'receiver-rollout-r4'
|
||||
pod = json.loads((RECEIVER / 'delivered-runtime.json').read_text())['api_pod']
|
||||
|
||||
def owner(args, content=None):
|
||||
r = subprocess.run(['ssh', 'railiance01',
|
||||
'KUBECONFIG=/etc/rancher/k3s/k3s.yaml ' + shlex.join(args)],
|
||||
input=content, capture_output=True, text=True, timeout=45)
|
||||
assert r.returncode == 0, 'private-owner-read-refused'
|
||||
return json.loads(r.stdout)
|
||||
|
||||
actual = owner(['kubectl', '-n', 'state-hub', 'get', 'pod', pod['name'], '-o', 'json'])
|
||||
assert actual['metadata']['uid'] == pod['uid']
|
||||
helper = BASE.parent / 'netkingdom-target-2026-10-16/cluster-historical-publication-r1/postdeployment-verifier-r1/snapshot_full_row_hashes.py'
|
||||
assert hashlib.sha256(helper.read_bytes()).hexdigest() == 'f01e93c0fcb4ca155bdf76813626c33e4343f6a8caec2870ab1d785243c60479'
|
||||
result = owner(['kubectl', '-n', 'state-hub', 'exec', '-i', pod['name'], '-c', 'state-hub', '--', 'python', '-'], helper.read_text())
|
||||
assert result['status'] == 'captured_readonly'
|
||||
baseline = json.loads((RECEIVER / 'after-verified-client.json').read_text())
|
||||
original = json.loads((RECEIVER / 'before-full-row-hashes.json').read_text())
|
||||
result.update(current_verified_baseline_equal=result['tables'] == baseline['tables'],
|
||||
original_rows_equal=result['tables'] == original['tables'],
|
||||
original_failed_comparison_retained=True, original_preimages_restored=False)
|
||||
(BASE / 'rollout-close-current-full-row-hashes.json').write_text(json.dumps(result, indent=2) + '\n')
|
||||
assert result['current_verified_baseline_equal']
|
||||
print(json.dumps({'status': 'verified-current-baseline', 'historical_rows': 18,
|
||||
'original_failed_comparison_retained': True,
|
||||
'original_preimages_restored': False}))
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
# Work Records — ops-warden
|
||||
|
||||
> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record
|
||||
> stage 3). Do not edit by hand — edit the source file/block listed for
|
||||
> each record and re-run fix-consistency to refresh this index. Archived
|
||||
> workplans are omitted; closed decisions/intakes/engagements stay listed
|
||||
> so recently-resolved work is still visible. [auto]
|
||||
|
||||
| Kind | ID | Status | Lane | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-09-08 | finished | — | workplans/ADHOC-2026-09-08.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-10-03 | finished | — | workplans/ADHOC-2026-10-03.md |
|
||||
| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| workplan | WARDEN-WP-0019 | finished | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| workplan | WARDEN-WP-0020 | finished | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| workplan | WARDEN-WP-0021 | finished | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| workplan | WARDEN-WP-0022 | finished | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| workplan | WARDEN-WP-0023 | finished | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| workplan | WARDEN-WP-0024 | finished | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| workplan | WARDEN-WP-0025 | finished | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| workplan | WARDEN-WP-0026 | finished | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| workplan | WARDEN-WP-0027 | blocked | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| workplan | WARDEN-WP-0028 | finished | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| workplan | WARDEN-WP-0029 | finished | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| workplan | WARDEN-WP-0032 | finished | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| workplan | WARDEN-WP-0034 | active | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| workplan | WARDEN-WP-0037 | blocked | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| workplan | WARDEN-WP-0038 | finished | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| workplan | WARDEN-WP-0039 | finished | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| workplan | WARDEN-WP-0040 | active | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| workplan | WARDEN-WP-0041 | finished | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| workplan | WARDEN-WP-0042 | finished | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| workplan | WARDEN-WP-0043 | finished | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| workplan | WARDEN-WP-0044 | active | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T01 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T02 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T03 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T04 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T05 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T06 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-10-03-T01 | done | — | workplans/ADHOC-2026-10-03.md |
|
||||
| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T04 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0017-T01 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0017-T02 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0017-T03 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0018-T01 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0018-T02 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0018-T03 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0019-T01 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| task | WARDEN-WP-0019-T02 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| task | WARDEN-WP-0020-T01 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T02 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T03 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T04 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T05 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0021-T01 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T02 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T03 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T04 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T05 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0022-T01 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T02 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T03 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T04 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0023-T01 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T02 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T03 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T04 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T05 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T06 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T07 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0024-T01 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T02 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T03 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T04 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T05 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T06 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T07 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0025-T01 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T02 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T03 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T04 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T05 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0026-T01 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T02 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T03 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T04 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T05 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T06 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T07 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0027-T01 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0027-T02 | todo | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0027-T03 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0028-T01 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T02 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T03 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T04 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T05 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T06 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T07 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0029-T01 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T02 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T03 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T04 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T05 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0030-T01 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T02 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T03 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T04 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T05 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0031-T01 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T02 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T03 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T04 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T05 | cancel | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0032-T01 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T02 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T03 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T04 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T05 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T06 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T07 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0034-T01 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T02 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T03 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T04 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T05 | wait | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T06 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-0037-T01 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0037-T02 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0037-T03 | wait | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0038-T01 | done | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| task | WARDEN-WP-0039-T01 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0039-T02 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0039-T03 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0040-T01 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T02 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T03 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T04 | done | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0041-T01 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T02 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T03 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T04 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0042-T01 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| task | WARDEN-WP-0042-T02 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| task | WARDEN-WP-0043-T01 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0043-T02 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0043-T03 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0044-T01 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T02 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T03 | progress | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T04 | wait | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md |
|
||||
| intake | WARDEN-IN-0002 | closed | — | intakes/intakes.md |
|
||||
| intake | WARDEN-IN-0003 | closed | — | intakes/intakes.md |
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
|
||||
# Custodian Brief — ops-warden
|
||||
|
||||
**Domain:** infotech
|
||||
**Last synced:** 2026-10-16 00:05 UTC
|
||||
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
||||
|
||||
## Active Workstreams
|
||||
|
||||
### Adopt unknown -> fail_closed behind signing-target classification coverage
|
||||
Progress: 1/4 done | workplan_id: `c8ee441e-1be1-5219-910c-e79ff23cc9ec`
|
||||
|
||||
**Open tasks:**
|
||||
- ! Tasks `611f0901`
|
||||
*(wait: Warden's own declaration cannot classify the repair-path target workloads; the owner must declare the continuity actor/target and its z2-continuity resolution (see 2026-09-28 review).)*
|
||||
- ! Tasks `54ad4864`
|
||||
*(wait: Owners of agt-codex-interhub-bootstrap (ops-hub) and agt-state-hub-bridge (ops-bridge) must publish authoritative workload identity declarations; atm-backup-daily declared by activity-core and compiled 2026-10-09 (z2-protected, admission unsatisfied: M1 below M2 floor).)*
|
||||
- ! Tasks `93eaf1f2`
|
||||
*(wait: Gated on T01 and on layer model v0.8 (or successor) reaching accepted; never convert against a proposed standard.)*
|
||||
|
||||
### Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule
|
||||
Progress: 5/6 done | workplan_id: `ae3ff76f-883d-5e2f-b6aa-144d61e8fdef`
|
||||
|
||||
**Open tasks:**
|
||||
- ! Tasks `7d1b3c82`
|
||||
*(wait: Two items to route, not absorb: ops-mason has published no stance map; the second is another repository's to own.)*
|
||||
|
||||
### Follow through on KnownSecurityCases along their type's route
|
||||
Progress: 2/4 done | workplan_id: `f7e81013-6868-5d99-8528-ba75a442eca9`
|
||||
|
||||
**Open tasks:**
|
||||
- ! T03 — Run and verify a case `4a0fa4a7`
|
||||
*(wait: Catalog integration follows a proven run.)*
|
||||
- ► T02 — Plan a case run `bcbf6c91`
|
||||
|
||||
### Tamper-resistant credential governance + mass rotation/lockdown (Strand B)
|
||||
Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf`
|
||||
|
||||
**Open tasks:**
|
||||
- · Task: Graded lockdown / break-glass with explicit trust-root `cae498ee`
|
||||
|
||||
### Repoint the whynot-design npm lane to Forgejo
|
||||
Progress: 2/3 done | workplan_id: `42a097db-1c24-558e-a724-030bb2b4443e`
|
||||
|
||||
**Open tasks:**
|
||||
- ! Prove routing and publication `a8b1b855`
|
||||
*(wait: Hold kept by D3 until SECRETS-WP-0006-T06 moves publishing off the legacy whynot-design npm path; then rotate and prove a fresh publish.)*
|
||||
|
||||
## Inbox Hygiene
|
||||
|
||||
**Stale unread:** 2 message(s) older than 3 day(s) — triage at session start.
|
||||
**Missing thread_id:** 3 unread message(s) lack supersession chains.
|
||||
|
||||
---
|
||||
## MCP Orientation (when available)
|
||||
|
||||
If the state-hub MCP server is reachable, call:
|
||||
`get_domain_summary("infotech")`
|
||||
This provides richer cross-domain context.
|
||||
If the MCP call fails, use this file as your orientation source.
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
# Work Records — ops-warden
|
||||
|
||||
> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record
|
||||
> stage 3). Do not edit by hand — edit the source file/block listed for
|
||||
> each record and re-run fix-consistency to refresh this index. Archived
|
||||
> workplans are omitted; closed decisions/intakes/engagements stay listed
|
||||
> so recently-resolved work is still visible. [auto]
|
||||
|
||||
| Kind | ID | Status | Lane | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-09-08 | finished | — | workplans/ADHOC-2026-09-08.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-10-03 | finished | — | workplans/ADHOC-2026-10-03.md |
|
||||
| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| workplan | WARDEN-WP-0019 | finished | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| workplan | WARDEN-WP-0020 | finished | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| workplan | WARDEN-WP-0021 | finished | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| workplan | WARDEN-WP-0022 | finished | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| workplan | WARDEN-WP-0023 | finished | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| workplan | WARDEN-WP-0024 | finished | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| workplan | WARDEN-WP-0025 | finished | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| workplan | WARDEN-WP-0026 | finished | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| workplan | WARDEN-WP-0027 | blocked | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| workplan | WARDEN-WP-0028 | finished | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| workplan | WARDEN-WP-0029 | finished | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| workplan | WARDEN-WP-0032 | finished | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| workplan | WARDEN-WP-0034 | active | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| workplan | WARDEN-WP-0037 | blocked | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| workplan | WARDEN-WP-0038 | finished | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| workplan | WARDEN-WP-0039 | finished | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| workplan | WARDEN-WP-0040 | active | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| workplan | WARDEN-WP-0041 | finished | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| workplan | WARDEN-WP-0042 | finished | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| workplan | WARDEN-WP-0043 | finished | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| workplan | WARDEN-WP-0044 | active | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T01 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T02 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T03 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T04 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T05 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-09-08-T06 | done | — | workplans/ADHOC-2026-09-08.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-10-03-T01 | done | — | workplans/ADHOC-2026-10-03.md |
|
||||
| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T04 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0017-T01 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0017-T02 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0017-T03 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| task | WARDEN-WP-0018-T01 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0018-T02 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0018-T03 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
| task | WARDEN-WP-0019-T01 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| task | WARDEN-WP-0019-T02 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md |
|
||||
| task | WARDEN-WP-0020-T01 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T02 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T03 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T04 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0020-T05 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md |
|
||||
| task | WARDEN-WP-0021-T01 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T02 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T03 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T04 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0021-T05 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md |
|
||||
| task | WARDEN-WP-0022-T01 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T02 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T03 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0022-T04 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md |
|
||||
| task | WARDEN-WP-0023-T01 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T02 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T03 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T04 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T05 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T06 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0023-T07 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md |
|
||||
| task | WARDEN-WP-0024-T01 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T02 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T03 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T04 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T05 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T06 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0024-T07 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md |
|
||||
| task | WARDEN-WP-0025-T01 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T02 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T03 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T04 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0025-T05 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md |
|
||||
| task | WARDEN-WP-0026-T01 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T02 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T03 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T04 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T05 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T06 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0026-T07 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md |
|
||||
| task | WARDEN-WP-0027-T01 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0027-T02 | todo | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0027-T03 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md |
|
||||
| task | WARDEN-WP-0028-T01 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T02 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T03 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T04 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T05 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T06 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0028-T07 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md |
|
||||
| task | WARDEN-WP-0029-T01 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T02 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T03 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T04 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0029-T05 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md |
|
||||
| task | WARDEN-WP-0030-T01 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T02 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T03 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T04 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0030-T05 | done | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| task | WARDEN-WP-0031-T01 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T02 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T03 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T04 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0031-T05 | cancel | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| task | WARDEN-WP-0032-T01 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T02 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T03 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T04 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T05 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T06 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T07 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0034-T01 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T02 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T03 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T04 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T05 | wait | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T06 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-0037-T01 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0037-T02 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0037-T03 | wait | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md |
|
||||
| task | WARDEN-WP-0038-T01 | done | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md |
|
||||
| task | WARDEN-WP-0039-T01 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0039-T02 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0039-T03 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md |
|
||||
| task | WARDEN-WP-0040-T01 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T02 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T03 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0040-T04 | done | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md |
|
||||
| task | WARDEN-WP-0041-T01 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T02 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T03 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0041-T04 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md |
|
||||
| task | WARDEN-WP-0042-T01 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| task | WARDEN-WP-0042-T02 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md |
|
||||
| task | WARDEN-WP-0043-T01 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0043-T02 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0043-T03 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md |
|
||||
| task | WARDEN-WP-0044-T01 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T02 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T03 | progress | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| task | WARDEN-WP-0044-T04 | wait | — | workplans/WARDEN-WP-0044-security-case-follow-through.md |
|
||||
| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md |
|
||||
| intake | WARDEN-IN-0002 | closed | — | intakes/intakes.md |
|
||||
| intake | WARDEN-IN-0003 | closed | — | intakes/intakes.md |
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-06-27
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-06-27"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
created: "2026-06-27"
|
||||
updated: "2026-06-27"
|
||||
state_hub_workstream_id: "a222c91f-3bb5-58a4-b6b2-f0fb18cdd5c3"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-06-27
|
||||
|
||||
Low-risk opportunistic fixes completed directly during the consolidation session.
|
||||
|
||||
### T01 — Fix stale `warden` CLI install + make it usable outside the repo
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-06-27-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "9176b560-8ca5-5143-888d-479857fe60f0"
|
||||
```
|
||||
|
||||
issue-core reported (msg `70bcf238`) that the `warden` CLI on `~/.local/bin` lacked
|
||||
the `route` subcommand, forcing a `uv run warden` fallback.
|
||||
|
||||
- [x] Root cause: `uv tool install` had reused a **cached wheel** (version stayed
|
||||
`0.1.0`), so the installed `warden.cli` predated the `route`/`access`/`policy`
|
||||
subcommands. `uv cache clean ops-warden` + `uv tool install . --reinstall` fixed it.
|
||||
- [x] Deeper cause: even rebuilt, `warden route`/`policy` failed outside a checkout
|
||||
because the catalog + posture descriptors live in `registry/` at repo root,
|
||||
outside the package. Bundled `registry/` into the wheel via hatch
|
||||
`force-include` → `warden/_registry`, and added a packaged-data fallback in
|
||||
`find_catalog_path` / `find_posture_path` (after the repo walk, so source runs
|
||||
still prefer the repo's `registry/` as the single source of truth).
|
||||
- [x] Verified `warden route list` / `warden policy list` work from `/tmp`; 200 tests
|
||||
pass, lint clean.
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-06-29
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-06-29"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
created: "2026-06-29"
|
||||
updated: "2026-06-29"
|
||||
state_hub_workstream_id: "13fa845f-852e-55ec-a2a5-2296996e0216"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-06-29
|
||||
|
||||
### T01 — Joint-smoke mode for the deployed flex-auth (assist FLEX-WP-0007 T4)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-06-29-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "62540533-f4ca-5176-9237-32adbeb292ee"
|
||||
```
|
||||
|
||||
flex-auth (msg `ea00620b`) asked ops-warden to help close FLEX-WP-0007 T4 (joint OpenBao
|
||||
+ policy-gate production smoke). Their deployed runtime is reachable on CoulombCore via
|
||||
the flex-auth-coulombcore tunnel at `127.0.0.1:18090`, but `policy_gate_production_smoke.sh`
|
||||
spawned its **own** local flex-auth binary — so it never exercised the deployed runtime.
|
||||
|
||||
- [x] Added `FLEX_AUTH_EXTERNAL=1` mode to `scripts/policy_gate_production_smoke.sh`: skips
|
||||
the local `serve`/`load-registry` and runs the allow/deny/vault paths against the
|
||||
already-running deployed flex-auth, with a `/healthz` precheck that fails fast with a
|
||||
"is the flex-auth-coulombcore tunnel up?" hint (verified: clean exit 2 when down).
|
||||
- [x] Verified the committed `production_registry_snapshot.json` is **current** (rebuilt
|
||||
from `~/.config/warden/inventory.yaml`, diff-clean; 4 actors).
|
||||
- [x] Answered flex-auth's three questions and handed the operator the exact CoulombCore
|
||||
runbook (see reply). Remaining T4 steps are operator-gated and cannot run from the
|
||||
workstation: mint a scoped `VAULT_TOKEN` (ops-warden holds no standing token by
|
||||
design), run the joint smoke on CoulombCore, then flip `policy.enabled: true`.
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-08-11
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-08-11"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-15"
|
||||
state_hub_workstream_id: "9f99cc64-4682-5f20-b13e-89af2b6f7c70"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-08-11
|
||||
|
||||
### T01 — Repair stale `rapp-qonto-keycape-client` wiki anchor (restore green routing suite)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "0771d121-278c-556e-9509-841cf6e657c3"
|
||||
```
|
||||
|
||||
rapp-postgres (msg `96907986`, residual from RAPP-POSTGRES-WP-0002-T04) reported the
|
||||
focused routing suite at 60/61: `test_every_wiki_ref_anchor_resolves` failed because
|
||||
`rapp-qonto-keycape-client` pointed at `wiki/CredentialRouting.md#credential-routing-catalog`,
|
||||
an anchor that does not exist. The intended heading is `## Routing catalog index`.
|
||||
|
||||
- [x] Repointed `rapp-qonto-keycape-client.wiki_ref` to
|
||||
`wiki/CredentialRouting.md#routing-catalog-index` (the live heading). No other
|
||||
entry used the stale anchor.
|
||||
- [x] `uv run pytest tests/test_routing.py -q` → **61 passed**.
|
||||
- [x] `warden route find "database credential"` still returns the active
|
||||
`database-dynamic-credentials` rapp-postgres entry; that T04 route is untouched —
|
||||
still `warden_executes: false` with no `steps:` block (pointer, not procedure).
|
||||
|
||||
### T02 — Triage the stale ops-warden inbox (11 unread, C-28/C-29)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "0ed58145-732f-5102-b6a8-b931d9b6ba08"
|
||||
```
|
||||
|
||||
`fix-consistency` flagged 11 unread messages older than 3 days, two of them as possible
|
||||
work requests (C-29). All eleven triaged, answered where an answer was owed, and marked
|
||||
read. Inbox is now empty.
|
||||
|
||||
- [x] **railiance-platform front-door thread** (`72d3ee84`, `cb50ea3c`, `6b058584`,
|
||||
`5d47caaa`, `78c1c075`) — confirmed both lanes active and placeholder-free
|
||||
(`issue-core-ingestion-api-key` catalog.yaml:219, `openrouter-llm-connect`
|
||||
catalog.yaml:283, promoted in 364eb7d), closing RAILIANCE-WP-0009-T06 and
|
||||
RAILIANCE-WP-0010-T06. Answered their open question: the stable ops-warden
|
||||
selector is **`openrouter-llm-connect`**, not `llm-connect-openrouter-api-key`;
|
||||
asked them to cross-reference the id in CCR-2026-0003 rather than have ops-warden
|
||||
rename an active, test-referenced lane.
|
||||
- [x] **railiance01 / activity-core** (`467153f3`, `3b9c6a77`, `fe796249`, `674f02e0`) —
|
||||
superseded. STATE-WP-0071 finished; the `.git/FETCH_HEAD` blocker was filesystem
|
||||
ownership, not SSH, and no `warden sign` was needed. Nothing was ever open for
|
||||
ops-warden. Pointed activity-core at `warden plan` / `warden route find` instead of
|
||||
hub round-trips for access questions.
|
||||
- [x] **llm-connect LLM-WP-0006** (`f5975211`) — superseded: `OPENROUTER_API_KEY` was
|
||||
provisioned through OpenBao custody 2026-07-02 (CCR-2026-0003), ES synced,
|
||||
llm-connect rolled out. Restated the boundary — ops-warden does not populate
|
||||
Secrets — and pointed at the now-active catalog lane. `LLM_CONNECT_URL` wiring
|
||||
remains activity-core's.
|
||||
- [x] **secrets-engine warden-sign** (`80456912`) — see T03; replied with status and
|
||||
referred the live-apply question to the owner.
|
||||
|
||||
### T03 — warden-sign AppRole: PARKED pending WP-0027 break-glass + ops-bridge cutover
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "337ae793-c6b0-59e9-8a07-3a7ccba237aa"
|
||||
```
|
||||
|
||||
secrets-engine (msg `80456912`, 2026-06-29) is holding a validated non-mutating dry-run
|
||||
for policy + AppRole `warden-sign` (exact `update` grants on `ssh/sign/{agt,adm,atm}-role`).
|
||||
It is blocked on two **operator** actions: recording/approving the SECRETS-WP-0004
|
||||
decision, and providing the mode-0600 lane bootstrap token
|
||||
(`~/.secrets-engine/bootstrap/prod-warden-sign.token`). secrets-engine correctly refused
|
||||
to substitute the broader platform-admin token.
|
||||
|
||||
**The request has been overtaken by events.** Since 2026-07-01 the scoped `VAULT_TOKEN`
|
||||
need is served by the railiance-platform credential broker
|
||||
(`ops-warden-warden-sign-token`, active; `credential.py exec --grant ops-warden/warden-sign`,
|
||||
proven via `make credential-exec-ops-warden-smoke`) — no AppRole involved.
|
||||
|
||||
**Resolved 2026-08-11: parked** — neither withdrawn nor proceeding. Founder decision
|
||||
after reviewing the mechanics. Communicated to secrets-engine (msg `863c7b57`) with an
|
||||
explicit instruction to stop holding apply readiness.
|
||||
|
||||
An initial recommendation to **withdraw** was revised on inspection:
|
||||
|
||||
- `warden sign` reads `VAULT_TOKEN` from the environment and has no AppRole login path
|
||||
(`src/warden/vault.py:24-27`). The AppRole is a way for a *host* to obtain a token,
|
||||
not an ops-warden code path — withdrawing costs no code and removes no working
|
||||
capability. For the workstation, the broker plus attended operator OIDC is sufficient.
|
||||
- The uncovered case is **unattended signing on a remote host** — the pending ops-bridge
|
||||
cert_command cutover. `wiki/playbooks/ops-bridge-tunnel-cert.md:61` still falls back to
|
||||
a manually exported `VAULT_TOKEN` there.
|
||||
- Running the broker on that host means placing the railiance-platform checkout *and its
|
||||
issuer token* (`credential-broker-warden-sign-issuer` — authority to mint warden-sign
|
||||
tokens repeatedly) on it. The AppRole exchanges for a `warden-sign`-only token
|
||||
(`update` on `ssh/sign/{agt,adm,atm}-role`). Both are standing credentials on a remote
|
||||
host; **the AppRole is the narrower one**, and is the established NetKingdom pattern
|
||||
for this shape (`rein-openweights-openrouter-approle`,
|
||||
`agent-harness-binky-mail-approle`).
|
||||
|
||||
No circular dependency exists today: OpenBao is a public endpoint
|
||||
(`https://bao.coulomb.social`), so obtaining a cert never requires already holding one.
|
||||
|
||||
**Un-park triggers** (either one re-opens the question):
|
||||
|
||||
1. **WARDEN-WP-0027** (backlog) designs the graded lockdown / break-glass path and its
|
||||
explicit trust-root — a second autonomous path to signing is an input to that design,
|
||||
not an isolated decision.
|
||||
2. **ops-bridge cert_command live cutover** reaches unattended signing on a remote host.
|
||||
|
||||
Cheap to reverse: the secrets-engine dry-run plan is validated, re-runnable, and correct
|
||||
as drafted. The two operator gates (SECRETS-WP-0004 decision, mode-0600 lane bootstrap
|
||||
token) are deliberately *not* being satisfied while parked.
|
||||
|
||||
**Closed 2026-08-15.** Neither un-park trigger has fired:
|
||||
|
||||
1. `WARDEN-WP-0027` is still `backlog`; T02 (graded lockdown / break-glass) stays
|
||||
`cancel` with the workplan. The parked AppRole remains an input on that task.
|
||||
2. ops-bridge live cert_command cutover has not reached unattended signing on a
|
||||
remote host. WP-0016 is finished as *pilot-ready and handed off*, not migrated.
|
||||
|
||||
This ad-hoc's job was the operator question (withdraw vs keep). The 2026-08-11
|
||||
answer stands: **neither — park and hand off**. Applying or withdrawing the
|
||||
AppRole is out of scope here and would re-open the operator gates that were
|
||||
deliberately left unsatisfied. Long-term ownership is `WARDEN-WP-0027-T02`
|
||||
(and the ops-bridge cutover if that arrives first). secrets-engine already has
|
||||
the park instruction (msg `863c7b57`); no new apply/withdraw ask.
|
||||
|
||||
- [x] Park decision recorded and communicated (2026-08-11)
|
||||
- [x] Ownership transferred to `WARDEN-WP-0027` T02; playbook pointer updated
|
||||
- [x] Ad-hoc closed so a `wait` item does not linger past the handoff
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-08-17
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-08-17"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
created: "2026-08-17"
|
||||
updated: "2026-08-17"
|
||||
state_hub_workstream_id: "5c6c2bbb-b944-5afd-b89c-20d865518849"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-08-17
|
||||
|
||||
Inbox triage session. Three unread messages, all follow-on from the WP-0030 delegation
|
||||
register plus one new design question that lands on ops-warden as the estate's
|
||||
workload-identity owner.
|
||||
|
||||
### T01 — Answer flex-auth: how should `/v1/check` authenticate its callers?
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "04a2f8f9-e70b-5eed-ad87-343c8f9ef501"
|
||||
```
|
||||
|
||||
flex-auth (msg `130a148c`, FLEX-WP-0015 T02) reported that `POST /v1/check` and
|
||||
`/v1/batch_check` authenticate no caller — any workload with cluster network reach can
|
||||
assert any subject/tenant and receive an authoritative allow. It lands on ops-warden
|
||||
because ops-warden owns how workloads prove identity in this estate, and because the
|
||||
ops-warden pre-sign gate is a flex-auth PEP that would implement the calling side.
|
||||
|
||||
Their four questions answered in `wiki/NetKingdomSecurityMap.md`
|
||||
§ *Service-to-service caller authentication (in-cluster)*:
|
||||
|
||||
- [x] **Q1 — is there an existing estate pattern to adopt?** No. Surveyed what exists:
|
||||
ops-warden SSH certs (host reachability, not pod→pod HTTP), KeyCape
|
||||
`client_credentials` (`rapp-qonto-keycape-client` — a custodied client secret per
|
||||
caller), OpenBao AppRole (host-standing; the WP-0030 register already flags it as
|
||||
having no owner front door). None covers in-cluster service→service HTTP, so
|
||||
flex-auth is not growing a parallel mechanism by adopting one.
|
||||
- [x] **Q2 — which mechanism?** Confirmed their instinct: **(a) Kubernetes
|
||||
ServiceAccount TokenReview**, with a *projected* token carrying an explicit
|
||||
`audience`, keeping `automountServiceAccountToken: false` and adding the volume
|
||||
per Deployment. Rejected (c) shared-secret header — it manufactures a `risk: high`
|
||||
credential lane with a rotation owner per caller, on the authorization path, which
|
||||
is exactly the interim-proxy debt WP-0030 exists to stop growing, and ops-warden
|
||||
would end up fronting it. Deferred (b) mTLS as the stronger end state that first
|
||||
needs an answer to *who owns the workload X.509 CA* — nobody does; ops-warden
|
||||
issues SSH certs, not workload X.509.
|
||||
- [x] **Q3 — authenticate only, or also constrain?** Both, but split: bind the asserted
|
||||
`system` to the authenticated ServiceAccount and reject a mismatch (identity
|
||||
binding, no per-consumer operational cost). Keep the *resource-type* allowlist
|
||||
("only ops-warden may ask about `ssh-certificate`") in the policy package, not in
|
||||
the auth middleware — flex-auth is the policy engine, and encoding it in its own
|
||||
admission layer puts authorization in two places where only one is versioned.
|
||||
- [x] **Q4 — rollout shape?** Warn-only first, as they proposed; ops-warden adopts the
|
||||
calling side on its own schedule. Binding condition is sequencing, not a date:
|
||||
`policy.enabled` must not flip anywhere while `/v1/check` still answers
|
||||
unauthenticated callers.
|
||||
- [x] Recorded as a **pattern**, not a catalog entry — `registry/routing/catalog.yaml`
|
||||
indexes credential needs and their owners; caller authentication is neither.
|
||||
- [x] Noted the division of the call: mechanism is ops-warden's/architectural; accepting
|
||||
the pod-spec change and rollout timing are the operator's.
|
||||
|
||||
### T02 — user-engine: USER_ENGINE_PROXY_SECRET stays railiance-apps; record consumer-only
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "0e815282-2fad-5c8d-be34-398e492737d0"
|
||||
```
|
||||
|
||||
user-engine (msg `2af4a124`) answered the open confirm question on
|
||||
`coulomb-social-runtime-env`. Decided by Bernd 2026-08-16, State Hub decision
|
||||
`8fe22037-5bbb-4487-bb86-e4beccee454b` against USER-WP-0021: the secret is
|
||||
infrastructure trust between ingress and workload, not a user-domain fact; user-engine
|
||||
consumes it and has no authority over custody, rotation, or issuance.
|
||||
|
||||
- [x] `intended_owner` stays `railiance-apps`; dropped the now-answered
|
||||
"confirm whether user-engine should front USER_ENGINE_PROXY_SECRET" clause from
|
||||
`blocked_on`, which now names only the real remaining blocker (CCR not applied).
|
||||
- [x] Recorded the positive signal they asked for: `consumers: [user-engine]` on the
|
||||
lane, with the decision id in a comment.
|
||||
- [x] Their second point — `USER_ENGINE_EVENT_TOKEN`, `USER_ENGINE_MAIL_TOKEN`, and the
|
||||
transactional SMTP lane gating public registration — checked against the catalog:
|
||||
`audit-core-senders` (native → ops-mason) and `email-connect-transactional`
|
||||
(interim → secrets-engine) already cover the event and mail token custody. No new
|
||||
lane opened; told them which ids to watch.
|
||||
|
||||
### T03 — key-cape: `rapp-qonto-keycape-client` interim accepted; refresh the blocker
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e21781d9-a35d-5916-b335-d12131f97a22"
|
||||
```
|
||||
|
||||
key-cape (msg `099b7cba`) acknowledged the lane staying interim on ops-warden.
|
||||
KEY-WP-0008 is finished and its closeout does **not** include a key-cape-native
|
||||
`client_secret_basic` exchange/rotation command; that is a separate, not-yet-opened
|
||||
workplan.
|
||||
|
||||
- [x] Refreshed `blocked_on` so it names the current reality rather than implying an
|
||||
in-flight KEY-WP-0008 dependency: the native command is unopened work, and
|
||||
key-cape has acked the interim hold.
|
||||
- [x] `key-cape-oidc-login` left pointing at `secrets-engine` — key-cape explicitly did
|
||||
not claim the generic-vs-per-lane custody split, and that lane's blocker is the
|
||||
same unanswered secrets-engine question as the other six.
|
||||
- [x] `reviewed` bumped to 2026-08-17 on both touched lanes so `warden route gaps`
|
||||
staleness reflects a real re-check.
|
||||
|
||||
### T04 — Session hygiene
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T04
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "b15724e0-c27a-5260-a810-4dd25bff2228"
|
||||
```
|
||||
|
||||
- [x] `uv run pytest -q` → 338 passed, 4 deselected (routing anchor + no-double-source
|
||||
checks green after the catalog edits).
|
||||
- [x] All three messages replied to and marked read; inbox empty.
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-09-08
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-09-08"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: netkingdom
|
||||
created: "2026-09-08"
|
||||
updated: "2026-09-08"
|
||||
state_hub_workstream_id: "182f3aff-8c8a-5766-8a68-5fe35f423f7a"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-09-08
|
||||
|
||||
Four key-cape messages, all follow-on from `WARDEN-WP-0033`. Two carry answers
|
||||
ops-warden's catalog was waiting for; both make a recorded blocker less true than
|
||||
it reads. This is the T05 mechanism paying out — and this time the owner ran it
|
||||
against us rather than us running it against them.
|
||||
|
||||
### T01 — Narrow the `rapp-qonto-keycape-client` blocker (msg `08d42f47`)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "29cef28a-d93b-5318-bfdb-69dbe11fa3ba"
|
||||
```
|
||||
|
||||
The blocker recorded "still no key-cape-native exchange/rotation command",
|
||||
`verified: source-read` against key-cape source on 2026-08-28. Accurate then;
|
||||
two things landed after that read:
|
||||
|
||||
- `keycape service-token` (2026-09-05, KEY-WP-0014-T03) — the client_secret_basic
|
||||
exchange the blocker records as absent.
|
||||
- `keycape verify-client` (2026-09-08) — rotation step 3 as one command,
|
||||
including predecessor rejection and identical-secret detection.
|
||||
|
||||
**Narrowed, not cleared**, as key-cape asked. What remains genuinely blocked is
|
||||
steps 1-2: successor generation and the CAS write to both custodians. Those are
|
||||
custody and deployment acts, key-cape deliberately ships no command for them, and
|
||||
no admitted ops-warden lane authorizes them either (T03).
|
||||
|
||||
`verified` moved to `owner-confirmed` — the correction came from the owner.
|
||||
|
||||
`rotation.automatable` flipped `true` → `false`, which key-cape explicitly asked
|
||||
us not to do "either way" without precision. Done with the precision they wanted,
|
||||
in the only place the schema has room for it: the flag is a single hint consumed
|
||||
by a future executable driver (`WARDEN-WP-0027` Strand B), and a driver told
|
||||
`true` would attempt custody acts with no admitted transport — the dangerous
|
||||
direction. So the flag fails safe and the *steps* now carry the per-step truth,
|
||||
each naming whether it is automatable and why. Offered them a schema change if a
|
||||
per-step field would serve better; not built on speculation.
|
||||
|
||||
### T02 — Record key-cape's acceptance of `key-cape-oidc-login` (msg `12f1bdfa`)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8efb8013-7b90-52ef-a17c-d63f5ce3752c"
|
||||
```
|
||||
|
||||
key-cape **accepted** ownership: interactive login, OIDC identity-token issuance
|
||||
and MFA. This confirms the 2026-08-28 correction of `intended_owner` from
|
||||
secrets-engine to key-cape, and confirms secrets-engine's 2026-08-21 refusal was
|
||||
right. `verified: asked-and-waiting` → `owner-confirmed`.
|
||||
|
||||
**The lane stays `interim`.** Acceptance covers the identity half only. The
|
||||
`fetch_command` yields an *OpenBao* token — the `netkingdom` mount, the
|
||||
`role=<domain>` mapping, the token store and its enforcement are OpenBao's, with
|
||||
role and policy definition railiance-platform's. `keycape login` yields a
|
||||
key-cape issuer JWT to a private file: different credential type, different
|
||||
verifier, different enforcement owner. Accepting an owner is not the same as the
|
||||
owner fronting the lane, and `ADR-0003` says the interim cover is retired when
|
||||
the front door exists, not when ownership is agreed. Retirement condition is now
|
||||
recorded on the entry.
|
||||
|
||||
Their reading of the risk is right and we confirmed it: `warden_executes: false`
|
||||
with a `wiki_ref` pointer, so per `ADR-0001` this is a pointer layer, not a code
|
||||
path with programmatic consumers. `risk: standard` and
|
||||
`workload_ref: not-applicable` are correct — a human identity act with no KV
|
||||
path, consistent with how `ADR-0008` treats the other non-KV lanes.
|
||||
|
||||
### T03 — Answer "who executes Qonto rotation steps 1-2" (msg `0a6c9d88`)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "bd621821-2116-51c9-a09a-a3660b5e5557"
|
||||
```
|
||||
|
||||
Answer: **nobody, admittedly, today** — and ops-warden must not invent one.
|
||||
|
||||
Steps 1-2 mutate custody on `platform/workloads/rapp-qonto/keycape-client` and
|
||||
`sso/keycape-rapp-qonto-client`. Custody of platform workload paths is
|
||||
railiance-platform's; the admitted execution front door for provisioned
|
||||
secret-exec is `secrets-engine exec`. ops-warden owns neither and absorbing it
|
||||
would be `ADR-0002` and `ADR-0005` violated in one act. Routed to
|
||||
railiance-platform, with secrets-engine named as the transport owner — and
|
||||
secrets-engine independently confirmed the same boundary three days earlier
|
||||
(msg `15f0c0ca`): they will not rewrite a production lane's custody state from a
|
||||
coordination message without owner confirmation.
|
||||
|
||||
key-cape was right not to treat a generic `warden route` match as authorization.
|
||||
See T04 for what our own tool did when asked.
|
||||
|
||||
### T04 — `warden plan` returned `autonomous` for a custody *write* (defect)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9ada01d2-b14b-579e-921c-275820f255db"
|
||||
```
|
||||
|
||||
Verifying T03 against our own front door:
|
||||
|
||||
```
|
||||
warden plan "generate a successor client secret ... and CAS-write it to
|
||||
OpenBao platform/workloads/... and sso/..." --json
|
||||
verdict: autonomous
|
||||
lane_id: rapp-qonto-keycape-client
|
||||
commands: warden access ... --exec / --out / --wrap
|
||||
```
|
||||
|
||||
A need that says *generate* and *CAS-write* resolved to `autonomous` and was
|
||||
answered with three **read** transports. This is the `WARDEN-WP-0033-T06` shape
|
||||
recurring — a generic keyword match producing a confident wrong act — except T06
|
||||
fixed one route by adding an exact lane, and the defect is in the classifier.
|
||||
`warden plan` has no notion of read versus mutate intent, so every write need
|
||||
matches the lane that *reads* the same path and comes back `autonomous`.
|
||||
|
||||
Not fixed here: a classifier is design work with an approval-semantics blast
|
||||
radius, which the convention says is a workplan, not an adhoc.
|
||||
Promoted to **`WARDEN-WP-0038`** (`proposed`).
|
||||
|
||||
Worth stating plainly: key-cape distrusted this output on principle and was right
|
||||
to. Had they trusted it, our tool would have told them to proceed autonomously on
|
||||
an unadmitted custody mutation.
|
||||
|
||||
### T05 — Acknowledge the KEY-WP-0009 handoff (msg `5bc58847`)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T05
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "06bf8508-d1a2-51b4-b951-02539524ebb9"
|
||||
```
|
||||
|
||||
Informational; no route retired or changed. Their routing note matches ours:
|
||||
"login / OIDC / MFA" → key-cape means **issuance only**, and secret *values*
|
||||
route to OpenBao custody. Nothing to change in `wiki/CredentialRouting.md`.
|
||||
|
||||
Also records that the KEY-WP-0009 reply ops-warden reported never arriving indeed
|
||||
never existed (KEY-WP-0014-T02, audited 2026-09-05). Our 2026-08-28 finding was
|
||||
right, and the correction is theirs, recorded.
|
||||
|
||||
### T06 — Unpin two tests from a transient catalog state
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-09-08-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "a0b88db9-2886-54dd-a925-9e0521044aa0"
|
||||
```
|
||||
|
||||
`test_stale_gaps_flags_unverified_even_when_the_date_is_today` and
|
||||
`test_cli_route_gaps_fail_on_stale_exits_3` both asserted that
|
||||
`key-cape-oidc-login` specifically sat `asked-and-waiting`. T02 answering that
|
||||
question broke them — **the tests failed on good news**, not on a defect, and a
|
||||
test that fails when a counterparty replies will get suppressed rather than read.
|
||||
|
||||
Both now assert the property they were always about: any lane whose blocker was
|
||||
never re-established is stale regardless of its date, over whatever lanes are in
|
||||
that state. The named-lane version of the claim already exists as a unit test on
|
||||
`Delegation.is_verified`, which is where a fixture belongs.
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
id: WARDEN-WP-ADHOC-2026-10-03
|
||||
type: workplan
|
||||
title: "Documentary feedback on Emergent Security repository pilot"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: ops-warden
|
||||
created: "2026-10-03"
|
||||
updated: "2026-10-03"
|
||||
state_hub_workstream_id: "246dc069-0f9b-516b-9db4-9914323da16f"
|
||||
---
|
||||
|
||||
## Review retained pilot evidence against owner boundaries
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-ADHOC-2026-10-03-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "c532cd72-88c4-543b-b6db-caf1bcb74a3d"
|
||||
```
|
||||
|
||||
Evidence: docs/evidence/2026-10-03-emergent-pilot-owner-feedback.md.
|
||||
Completed authorized documentary feedback on the retained read-only 0.2.0
|
||||
Claude scenario; preserved original version and evidence limits, qualified
|
||||
owner boundary wording and identified bounded 0.2.2 follow-up scenarios.
|
||||
No provider session, runtime control, deployment, credential or institutional
|
||||
adoption was performed. Next pilot/adoption gates remain existing
|
||||
EMERGENT-WP-0002-T08/T09 and decision d20a9750-2b29-534e-8227-fb866581a6ca.
|
||||
No new operational residual was created.
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
id: WARDEN-WP-0016
|
||||
type: workplan
|
||||
title: "ops-bridge cert_command pilot — readiness gate + handoff"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 16
|
||||
created: "2026-06-27"
|
||||
updated: "2026-06-27"
|
||||
state_hub_workstream_id: "a56da8db-38bc-4bbe-8671-823360ec9245"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0016 — ops-bridge cert_command pilot (readiness gate + handoff)
|
||||
|
||||
**Scope:** Close ops-warden's side of the last **Partial** INTENT criterion — *"ops-bridge
|
||||
integrates via a stable `cert_command`"*. The migration playbook
|
||||
(`wiki/playbooks/ops-bridge-tunnel-cert.md`, WP-0013) and the `cert_command` contract
|
||||
(`wiki/CertCommandInterface.md`) already exist, but the pilot has never been run because
|
||||
the readiness checks are scattered manual checkboxes across three owners (ops-warden,
|
||||
ops-bridge, railiance-infra). This WP ships the **automated readiness gate** an operator
|
||||
runs *before* touching tunnel config, plus an offline `cert_command` contract smoke, and
|
||||
hands the verified pilot to ops-bridge.
|
||||
|
||||
**Boundary (unchanged):** ops-warden issues certs and verifies its own side is ready.
|
||||
The **live tunnel cutover is ops-bridge's to execute** — this WP does not (cannot) flip a
|
||||
running tunnel. "Done" here means *pilot-ready and handed off*, not *tunnel migrated*.
|
||||
|
||||
**Out of scope:** editing `~/.config/bridge/tunnels.yaml` (ops-bridge owns it); deploying
|
||||
host principals (railiance-infra); requiring a live OpenBao token for the contract smoke
|
||||
(use the local backend).
|
||||
|
||||
**Depends on:** WP-0013 (playbook + contract), the SSH lane (prod-verified).
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Read-only `cert_command` readiness preflight
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0016-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "fea84495-dbec-480a-b42b-90e39f414b78"
|
||||
```
|
||||
|
||||
- [x] `scripts/check_tunnel_cert_readiness.py` — given `--actor`, `--pubkey`, `--config`
|
||||
(warden.yaml) and optional `--infra` (ssh_principals.yaml), asserts the cert_command
|
||||
path is ready **without signing anything**: config loads + backend known; actor in
|
||||
inventory with a valid type + TTL within the type max; pubkey file exists, parses,
|
||||
and is not a private key; actor principals present; (optional) principals deployed
|
||||
in the infra file (mirrors `check_principals_drift._infra_principals`). Exit 0/1/2.
|
||||
- [x] Checklist-style report (✓/✗/·); never prints a private key or token.
|
||||
- [x] Tests: `tests/test_tunnel_cert_readiness.py` (ready, unknown actor, missing/private
|
||||
pubkey, infra present/missing, TTL-over-max, cert_command string). 9 unit cases.
|
||||
|
||||
### T2 — Offline cert_command contract smoke
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0016-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e34ae1a8-2ba9-4324-8d1a-005d61dae478"
|
||||
```
|
||||
|
||||
- [x] Opt-in `--sign-smoke` mode runs the actual `cert_command` against the **local**
|
||||
backend and validates the emitted cert: identity matches the actor, principals match
|
||||
inventory, validity window within the type's max TTL. Refuses a vault backend (must
|
||||
be offline). Proves the contract end to end with no live OpenBao.
|
||||
- [x] Window measured from the cert's own `valid_from`→`valid_before` (via
|
||||
`parse_cert_metadata`) so it is timezone-robust — fixes a CEST off-by-2h artifact
|
||||
where local-time ssh-keygen output was read as UTC.
|
||||
- [x] `integration`-marked test (needs `ssh-keygen`, skipped in the default suite) plus a
|
||||
non-integration test that `--sign-smoke` refuses a vault backend.
|
||||
|
||||
### T3 — Playbook gate + ops-bridge handoff
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0016-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "330e01f4-4927-4280-b0e0-49d35b4416d6"
|
||||
```
|
||||
|
||||
- [x] `wiki/playbooks/ops-bridge-tunnel-cert.md` now leads with **Step 0 — Readiness gate**
|
||||
(the exact `check_tunnel_cert_readiness.py` invocation + `--sign-smoke` note); the
|
||||
manual checklist remains as the human-readable backing.
|
||||
- [x] Sent ops-bridge the coordination handoff (pilot `agt-state-hub-bridge`, the
|
||||
readiness-gate command, and the cutover steps ops-bridge owns).
|
||||
|
||||
### T4 — INTENT/SCOPE alignment
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0016-T04
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "4726f5bb-4ffd-484f-8674-91ee5658434f"
|
||||
```
|
||||
|
||||
- [x] SCOPE: INTENT gap row moved from "Partial — tunnels still static-key" to
|
||||
"Pilot-ready — readiness gate shipped; live cutover handed to ops-bridge"; known-gaps
|
||||
row updated; readiness script added to the implemented SSH-lane list.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `scripts/check_tunnel_cert_readiness.py` gates the pilot read-only and is tested.
|
||||
- The offline contract smoke validates a real cert against the local backend.
|
||||
- The playbook leads with the automated gate; ops-bridge has the handoff with exact steps.
|
||||
- No secret material in any script, test, doc, or log. ops-warden's boundary is intact:
|
||||
it verifies and hands off; ops-bridge executes the cutover.
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- `wiki/playbooks/ops-bridge-tunnel-cert.md`, `wiki/CertCommandInterface.md`
|
||||
- `scripts/check_principals_drift.py` (reused helpers)
|
||||
- `history/2026-06-24-intent-scope-gap-analysis.md`
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
---
|
||||
id: WARDEN-WP-0017
|
||||
type: workplan
|
||||
title: "Access front-door discoverability — stop reading as SSH-only"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 17
|
||||
created: "2026-06-27"
|
||||
updated: "2026-06-27"
|
||||
state_hub_workstream_id: "cf8b392e-7624-4585-8935-a85e29202935"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0017 — Access front-door discoverability
|
||||
|
||||
**Problem:** WP-0014 made ops-warden the operator **access front door** — for
|
||||
`exec_capable` lanes (OpenBao reads, key-cape login) `warden access <need> --fetch/--exec`
|
||||
proxies the fetch **as the caller** and streams the value to them (ops-warden holds
|
||||
nothing). But every *discovery* surface still tells the pre-WP-0014 story, so agents
|
||||
(e.g. whynot-design needing `NPM_AUTH_TOKEN`) conclude "ops-warden only issues SSH certs
|
||||
and replies with a pointer, not a token" and never find the proxy.
|
||||
|
||||
**Fix:** propagate the WP-0014 conduit charter to the surfaces agents actually read. This
|
||||
is a *messaging/discoverability* change — **no** change to the security model: the conduit
|
||||
stays a conduit (no custody, no standing broker; the responsibility-map boundary holds).
|
||||
|
||||
**Out of scope:** ops-warden holding/brokering token values (that would override the
|
||||
WP-0014 charter); shipping the concrete OpenBao npm KV path (railiance-platform infra —
|
||||
tracked separately); any new fetch capability (the proxy already exists).
|
||||
|
||||
**Depends on:** WP-0014 (the proxy lane being described).
|
||||
|
||||
---
|
||||
|
||||
## Surfaces that mislead today
|
||||
|
||||
| Surface | Says now | Should say |
|
||||
| --- | --- | --- |
|
||||
| `warden route` table `warden` column | binary `issue` / `route` | `issue` / **`assist`** (exec_capable) / `route` |
|
||||
| `warden route` `--json` | no proxyability field | add `warden_role` + `exec_capable` |
|
||||
| `warden access` closing line | "warden advises, the owner vends" | for exec_capable: "ops-warden can fetch this for you as the caller…" |
|
||||
| `.claude/rules/credential-routing.md` | "issues SSH certs **only**… reply is a pointer, not a key" | issues SSH certs **and** is the access front door; exec_capable lanes proxy as you |
|
||||
| Federated capability registry | only "SSH certificate issuance" | also "Operator access front door / caller-identity fetch proxy" |
|
||||
| SCOPE one-liner + capability block | SSH + routing + posture | add the access-assist/proxy front door |
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — CLI discoverability: route role + access framing
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0017-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6e98df42-b5b4-49f8-a444-3c6346c8abd7"
|
||||
```
|
||||
|
||||
- [x] `warden route` table: three-valued `warden` column — `issue` / `assist`
|
||||
(exec_capable) / `route`. `_entry_summary` JSON gains `warden_role` + `exec_capable`;
|
||||
`route show` JSON `next_action` surfaces the proxy for exec_capable lanes.
|
||||
- [x] `warden access` closing line: for `exec_capable` lanes leads with "ops-warden can
|
||||
fetch this for you as the caller (`--fetch`/`--exec`); runs the owner's tool with
|
||||
your identity, value never held/cached/logged." Non-exec lanes keep "advises, owner
|
||||
vends." `_access_json` `next_action` mirrors it.
|
||||
- [x] Tests in `tests/test_routing.py` (warden_role issue/assist) and `tests/test_access.py`
|
||||
(front-door framing for exec lane, owner-vends for route-only lane). 210 pass.
|
||||
|
||||
### T2 — Agent rule + SCOPE reframe
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0017-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6e2a7067-1afc-4f38-8d99-4d5c36a4661c"
|
||||
```
|
||||
|
||||
- [x] `.claude/rules/credential-routing.md`: reframed the lead ("issues SSH certs **and**
|
||||
is the operator access front door…") and the quick routing table (`ops-warden role`
|
||||
column: Issue / Assist / Route). Kept the true anti-pattern: don't POST a State Hub
|
||||
message for a secret *value* — it comes from the CLI front door run as you.
|
||||
- [x] SCOPE one-liner reframed to "steward **and front door**"; added a second `capability`
|
||||
block "Operator access front door (caller-identity fetch proxy)".
|
||||
|
||||
### T3 — Federated capability registration
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0017-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "7199625b-e78e-4495-8ca0-076100ae9f08"
|
||||
```
|
||||
|
||||
- [x] Registered the State Hub capability "Operator access front door (caller-identity
|
||||
fetch proxy)" (id `708e46f6`, repo ops-warden) — the hub had **no** ops-warden
|
||||
security capability before, so the front door was undiscoverable cross-domain.
|
||||
- [x] Sent whynot-design (msg `83a3bb2e`) the corrected path: `warden access "npm auth
|
||||
token" --fetch/--exec`, the CLI refresh, the OpenBao-auth prereq, and the
|
||||
railiance-platform path caveat.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- An agent doing the first-line `warden route find` / `--json` lookup can see ops-warden
|
||||
*assists* (proxies) the OpenBao lane, not merely points.
|
||||
- The credential-routing rule and federated capability registry describe the access
|
||||
front door; none of them say "SSH certificates only".
|
||||
- The conduit boundary is unchanged and explicit: ops-warden fetches *as the caller* and
|
||||
holds nothing — no custody, no broker.
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- `WARDEN-WP-0014` (the proxy lane), `wiki/OperatorAccessAssist.md`
|
||||
- `.claude/rules/credential-routing.md`, `registry/routing/catalog.yaml`
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
id: WARDEN-WP-0018
|
||||
type: workplan
|
||||
title: "Activate whynot-design npm publish lane + resolvable readiness flag"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 18
|
||||
created: "2026-06-29"
|
||||
updated: "2026-06-29"
|
||||
state_hub_workstream_id: "1256aca2-5979-4d21-818e-0de42c5d811b"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0018 — whynot-design npm lane activation + `resolvable` flag
|
||||
|
||||
**Trigger:** railiance-platform completed provisioning the whynot-design npm publish lane
|
||||
(CCR-2026-0001, commit 8f617fc): `status=active`, `access_frontdoor.readiness=ready`,
|
||||
`resolvable=true`, positive fetch passed + negative (non-whynot) login denied. They asked
|
||||
ops-warden to activate the dedicated catalog selector and notify whynot-design. This is the
|
||||
first concrete `warden access --fetch`-resolvable non-SSH lane — the end-to-end proof of the
|
||||
WP-0014 conduit + WP-0017 discoverability work.
|
||||
|
||||
**whynot-design's spec** (msg 2687dc31) drove the shape: zero-placeholder command keyed by a
|
||||
stable id, owner-confirmed concrete path/field/role, a machine-readable readiness flag, and a
|
||||
publish-vs-read scope split.
|
||||
|
||||
**Boundary unchanged:** ops-warden holds no token; the lane proxies the read as the caller.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Concrete catalog entry + playbook
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0018-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "189d0883-22b9-42dc-bda0-89460509a87d"
|
||||
```
|
||||
|
||||
- [x] Added `whynot-design-npm-publish` to `registry/routing/catalog.yaml` (`status: active`,
|
||||
`exec_capable`, `lane: secret`) with the **owner-confirmed, zero-placeholder** handoff:
|
||||
path `platform/workloads/coulomb/whynot-design/npm-publish` (the superseded
|
||||
`whynot-design/whynot-design/…` form is **not** used), field `NPM_AUTH_TOKEN`, OIDC
|
||||
`bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read`, policy
|
||||
`workload-kv-read-whynot-design-npm-publish`, flex-auth `secret.read:whynot-design`.
|
||||
- [x] `wiki/playbooks/whynot-design-npm-publish.md` — worker checklist, scopes, operator
|
||||
go-ahead note (publish is immutable + outward-facing). Catalog `wiki_ref` points to it.
|
||||
- [x] Passes the `_assert_no_secret_material` guard (templates/identifiers only, no value).
|
||||
|
||||
### T2 — `resolvable` readiness flag + stable-id resolution
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0018-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b5dc1013-5334-43ff-afd6-1f99d521358f"
|
||||
```
|
||||
|
||||
- [x] `RouteEntry.resolvable` — true when a lane is active, exec_capable, and its fetch
|
||||
command/path carry **no** unresolved `<…>` placeholder. Surfaced in the route/access
|
||||
`--json` (`_entry_summary`). Generic `openbao-api-key` and the `<domain>` login lane
|
||||
report `false`; `whynot-design-npm-publish` reports `true`.
|
||||
- [x] `Catalog.find` now resolves an **exact catalog-id** match first, so
|
||||
`warden access whynot-design-npm-publish …` is deterministic regardless of keyword
|
||||
collisions (whynot-design's "stable keyed command").
|
||||
- [x] Tests: `tests/test_routing.py` (concrete+resolvable lane, template lanes not
|
||||
resolvable, exact-id wins); fixed a `test_access` no-match query that incidentally
|
||||
substring-collided (`no` ⊂ `whynot`). 213 pass, lint clean.
|
||||
|
||||
### T3 — Close the loop
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0018-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "95b00ef8-477a-4f0d-bd71-6154fba401f5"
|
||||
```
|
||||
|
||||
- [x] Notified whynot-design (reply 744977ae) with the zero-placeholder command
|
||||
`warden access whynot-design-npm-publish --exec -- npm publish`, the `resolvable` gate,
|
||||
the coulomb-tenant path correction, and the operator-go-ahead reminder.
|
||||
- [x] Confirmed activation to railiance-platform (reply f76d3a9e). Sibling lanes
|
||||
(`issue-core-ingestion-api-key`, `openrouter-llm-connect`) stay `draft` per their
|
||||
deferral, pending CCR-2026-0002/0003 provisioning.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `warden access whynot-design-npm-publish` resolves to a concrete, owner-confirmed,
|
||||
zero-placeholder lane; `--json` reports `resolvable: true`.
|
||||
- Template/generic lanes report `resolvable: false`; exact-id lookup is deterministic.
|
||||
- No secret value in catalog, playbook, tests, or logs; ops-warden holds nothing.
|
||||
|
||||
## See also
|
||||
|
||||
- `WARDEN-WP-0014` (proxy lane), `WARDEN-WP-0017` (discoverability)
|
||||
- railiance-platform CCR-2026-0001, `docs/workload-kv-access-lanes.md`
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
id: WARDEN-WP-0019
|
||||
type: workplan
|
||||
title: "Route secret-exec lanes to secrets-engine (route-primary, proxy fallback)"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 19
|
||||
created: "2026-06-29"
|
||||
updated: "2026-06-29"
|
||||
state_hub_workstream_id: "5e49abb6-497f-4640-a484-2da5f39a7c4e"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0019 — Route secret-exec lanes to secrets-engine
|
||||
|
||||
**Trigger:** secrets-engine (SECRETS-WP-0003, msg 765a03f0) shipped a native secret-exec
|
||||
front door — `secrets-engine route <id> --json` and `secrets-engine exec --catalog <id> --
|
||||
<cmd>` with canonical decision ids — and asked ops-warden to **route to it**. This is the
|
||||
owner-native execution lane that ops-warden's `warden access --exec` proxy was filling as a
|
||||
stopgap (WP-0014). whynot-design already published `@whynot/design@0.4.0` through the proxy
|
||||
on this same lane, so both paths resolve today.
|
||||
|
||||
**Decision (Bernd, 2026-06-29): route-primary, proxy-fallback.** For lanes secrets-engine
|
||||
owns, ops-warden surfaces `secrets-engine exec/route` as the **primary** path and keeps its
|
||||
own `warden access --exec` as a documented **transparent fallback**. ops-warden stays the
|
||||
discovery front door; secrets-engine is the exec owner. Boundary unchanged: ops-warden holds
|
||||
or stores no token on either path.
|
||||
|
||||
**Out of scope:** ops-warden invoking `secrets-engine exec` itself (it routes/points, the
|
||||
caller runs it); changing the proxy's security model; the production policy-gate flip.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Catalog + CLI: surface the owner-native exec front door
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0019-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ea153605-7a14-4db7-8bce-d780ea143f8a"
|
||||
```
|
||||
|
||||
- [x] `RouteEntry` gains `exec_owner` / `exec_command` / `pointer_command` (pointers only,
|
||||
screened by `_assert_no_secret_material`) and a `has_native_exec` property.
|
||||
- [x] `whynot-design-npm-publish` entry: `exec_owner: secrets-engine`,
|
||||
`exec_command: secrets-engine exec --catalog whynot-design-npm-publish -- <cmd>`,
|
||||
`pointer_command: secrets-engine route whynot-design-npm-publish --json`. Keep the
|
||||
existing `fetch_command`/`exec_capable` (the proxy fallback).
|
||||
- [x] `warden access`: when `exec_owner` is set, render the secrets-engine exec as the
|
||||
**primary** line and the `warden access --exec` proxy as the **fallback**; JSON gains
|
||||
`exec_owner`/`exec_command`/`pointer_command`. `route find/show` JSON too.
|
||||
- [x] Tests in `tests/test_routing.py` / `tests/test_access.py`.
|
||||
|
||||
### T2 — Agent rule, SCOPE, playbook
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0019-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "96059b8a-8938-4763-b3d0-cc5a0eb2465c"
|
||||
```
|
||||
|
||||
- [x] `.claude/rules/credential-routing.md`: add secrets-engine as the secret-exec owner;
|
||||
for OpenBao-backed secret lanes the route is "secrets-engine `exec` (primary),
|
||||
ops-warden `warden access --exec` (transparent fallback)".
|
||||
- [x] SCOPE: add secrets-engine to Related Repos + the routing model; note the
|
||||
whynot-design lane is **production-exercised** (real 0.4.0 publish), not just resolvable.
|
||||
- [x] `wiki/playbooks/whynot-design-npm-publish.md`: lead with the secrets-engine exec
|
||||
command; fix the fallback one-liner per whynot-design's field notes
|
||||
(`--field NPM_AUTH_TOKEN`, and `--no-policy` while `policy.enabled=false`).
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `warden access whynot-design-npm-publish` shows the secrets-engine exec as primary and the
|
||||
warden proxy as fallback; `--json` carries `exec_owner`/`exec_command`.
|
||||
- The credential-routing rule names secrets-engine as the secret-exec owner.
|
||||
- No secret material anywhere; ops-warden holds no token on either path.
|
||||
|
||||
## See also
|
||||
|
||||
- secrets-engine SECRETS-WP-0003, decision e6381a56, `docs/whynot-design-real-publish-closeout.md`
|
||||
- `WARDEN-WP-0014` (proxy), `WARDEN-WP-0017` (discoverability), `WARDEN-WP-0018` (lane activation)
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
id: WARDEN-WP-0020
|
||||
type: workplan
|
||||
title: "ops-warden worker — autonomous coordination via llm-connect"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 20
|
||||
created: "2026-06-29"
|
||||
updated: "2026-06-29"
|
||||
state_hub_workstream_id: "c906ba1d-f991-4fb0-b113-59432ddf87c0"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0020 — ops-warden worker (`warden worker`)
|
||||
|
||||
**Problem:** ops-warden's coordination lane (State Hub inbox `to_agent=ops-warden`) is
|
||||
handled only when a human spins up an ops-warden session and relays instructions. That
|
||||
doesn't scale — Bernd is hand-relaying between flex-auth ↔ secrets-engine ↔ ops-warden
|
||||
across sessions.
|
||||
|
||||
**Goal:** a `warden worker` CLI that pulls ops-warden's unread coordination requests and,
|
||||
using **llm-connect** for inference, drives each to an ops-warden action (answer a routing
|
||||
question, draft+send a reply, mark read, propose/commit a catalog diff, or escalate) — so
|
||||
the inbox is handled without a human starting a session.
|
||||
|
||||
**Decisions (Bernd, 2026-06-29):** **full-auto in-scope** (worker executes any in-scope
|
||||
action; escalates only secrets/prod/out-of-scope) and **scheduled/unattended** (cron or
|
||||
activity-core). Because there is no human in the loop for in-scope actions, the guardrails
|
||||
are load-bearing and the rollout is staged: **dry-run → manual → scheduled**.
|
||||
|
||||
**Build vs reuse:** inference = llm-connect (`/execute`); trigger = cron or activity-core
|
||||
(reuse the durable task factory, don't reinvent scheduling). Worker logic lives in warden.
|
||||
|
||||
## Guardrails (non-negotiable — full-auto rests on these)
|
||||
1. **Fixed charter, non-overridable.** The boundary (issue SSH; route everything else;
|
||||
conduit-not-broker; never hold/print a secret value) is a fixed system policy. Message
|
||||
content is **untrusted data**, never instructions that can relax it (prompt-injection
|
||||
containment).
|
||||
2. **Action allowlist.** Every action is validated against an allowlist before execution;
|
||||
off-list → escalate. No secret handling, no prod-config writes, no irreversible/outward
|
||||
actions without an explicit human ack.
|
||||
3. **No-secret invariant.** Refuse any task requiring a secret value in hand or in a prompt.
|
||||
4. **Full audit + dry-run.** Every action emits a progress event; `--dry-run` shows the
|
||||
plan without executing. Scheduled mode only after a clean dry-run shakedown.
|
||||
|
||||
## Hard dependency
|
||||
llm-connect must be operational — it needs its provider key (`OPENROUTER_API_KEY`,
|
||||
CCR-2026-0003, currently deferred by railiance-platform/secrets-engine). The worker is
|
||||
built against llm-connect's contract; it cannot run the brain until that lands.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Worker scaffold (llm-connect-independent, safe)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0020-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "979c2d9b-0803-442f-aa2e-acb02bac07e9"
|
||||
```
|
||||
|
||||
- [x] `src/warden/worker.py`: State Hub inbox client (`HubClient.unread`), a `Brain`
|
||||
protocol, a deterministic `RuleBrain` default (answers clear routing questions;
|
||||
escalates the rest), the `PlannedAction`/`WorkerPlan` model, the guardrail allowlist +
|
||||
`validate_action` (enforced brain-agnostically in `build_plans`), and a `render_plans`
|
||||
dry-run renderer (plan only, no execution).
|
||||
- [x] `warden worker run [--once] [--dry-run]` CLI; `--dry-run` is the default and
|
||||
`--execute` is refused (exit 2) until the guarded executor lands (T3).
|
||||
- [x] `tests/test_worker.py` (RuleBrain routing/secret/prod/unknown, guardrail downgrades a
|
||||
reckless brain on secret/prod, off-allowlist rejection, render, CLI). 18 cases.
|
||||
- [x] Live dry-run against the real hub verified — read the inbox and produced a guardrailed
|
||||
plan (it surfaced secrets-engine's OIDC-role reply, demonstrating the value).
|
||||
|
||||
### T2 — llm-connect brain
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0020-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "52d281b2-7d48-44f5-b77e-80e3ed500b5f"
|
||||
```
|
||||
|
||||
- [x] llm-connect brought operational (operator set OPENROUTER_API_KEY k8s secret + restart).
|
||||
Contract discovered empirically from the running service: `POST /execute {"prompt":...}`
|
||||
→ `{"content": "<text>", ...}` (no OpenAPI; custom JSON API). End-to-end verified (pong).
|
||||
- [x] `LlmConnectBrain` (src/warden/worker.py): embeds the fixed charter + the message as
|
||||
untrusted data into the prompt, calls `/execute`, parses a JSON action plan
|
||||
(`_extract_json` tolerates fences/prose), and defensively escalates on malformed/empty/
|
||||
transport-error. Configurable `LLM_CONNECT_URL`. The guardrail pass still enforces the
|
||||
allowlist + no-secret invariant on whatever the model returns.
|
||||
- [x] `warden worker run --brain rule|llm` selector (dry-run default). Tests:
|
||||
`tests/test_worker.py` (extract_json, parse, escalate-on-flag/malformed/transport,
|
||||
guardrail-catches-unsafe-LLM-action). **Live verified** against the real inbox: the LLM
|
||||
brain produced a sensible reply+mark_read for the secrets-engine message and correctly
|
||||
escalated the llm-connect secret-custody request. 236 tests, lint clean.
|
||||
|
||||
### T3 — Action dispatch + guardrails (full-auto in-scope)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0020-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3a71965e-42d5-4258-9761-aced804c88e7"
|
||||
```
|
||||
|
||||
- [x] `HubClient` gained writes (`mark_read`, `send_reply`, `add_progress`); `execute_plan`
|
||||
/ `execute_plans` run the **safe, allowlisted** actions — route_answer (reply with the
|
||||
computed answer + auto mark-read), reply (with an LLM-drafted body), progress_note,
|
||||
mark_read. Escalated plans and non-auto-executable kinds are left for a human.
|
||||
- [x] **Deliberate guardrail:** `propose_catalog_diff` (and any code/routing change) is NOT
|
||||
auto-executed even under full-auto — a bad catalog commit could misroute credentials,
|
||||
so it goes to human review (recoverability over convenience). AUTO_EXECUTABLE is the
|
||||
messaging/hub tier only. No secret value is ever read, sent, or logged.
|
||||
- [x] `warden worker run --execute` runs the guarded executor (dry-run still the default);
|
||||
per-message audit summary. Tests in `tests/test_worker.py` (route_answer reply+mark,
|
||||
reply-with/without-body, escalated skip, catalog-diff left-for-human, progress_note,
|
||||
failure-without-crash). 243 pass, lint clean.
|
||||
- [x] **Conservative tier is now the `--execute` default (Bernd's Option A, 2026-06-30):**
|
||||
`run_conservative` triages NEW messages into a reviewed digest (`worker-digest.md`)
|
||||
with drafted replies, posts ONE progress note, tracks seen ids (schedule-safe dedup),
|
||||
and sends **nothing** to other agents / marks nothing read. `--full-auto` opts into the
|
||||
auto-send path. Live-verified with the LLM brain: produced a high-quality draft reply
|
||||
to secrets-engine and flagged the llm-connect request as NEEDS YOU. 244 tests.
|
||||
Rationale: the guardrails prevent *security* harm but not LLM *content* errors, so replies
|
||||
stay drafts-for-approval until quality is proven — matches the build-stage/recoverability
|
||||
posture. Conservative mode is safe to schedule (T4).
|
||||
|
||||
### T4 — Scheduled trigger
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0020-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "7f77ea6d-c281-42c5-ad25-2a0bb9fd68de"
|
||||
```
|
||||
|
||||
- [x] `scripts/worker-tick.sh` — scheduled tick for the conservative worker. `flock`
|
||||
concurrency guard (no overlapping runs); brings up a short-lived kubectl port-forward
|
||||
to llm-connect (or honors `LLM_CONNECT_URL`, or falls back to the rule brain offline).
|
||||
Ships **disabled**; the header documents the cron entry to enable it (every 15 min).
|
||||
Dry-shakedown done (the conservative live run + the rule-brain tick both verified).
|
||||
Schedules the **conservative** tier only — never the auto-send path.
|
||||
|
||||
### T5 — Docs / SCOPE / INTENT
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0020-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "6e7ae317-7f8b-468a-bb5c-b08093ed43a0"
|
||||
```
|
||||
|
||||
- [x] SCOPE: recorded the coordination worker (`warden worker`) as an implemented
|
||||
capability — conservative triage default, full-auto opt-in, llm-connect brain, the
|
||||
four guardrails, schedulable tick. The guardrails + the conservative-by-default
|
||||
posture are documented as the worker's security-model statement (here + in the
|
||||
build-stage decision 813899f9).
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `warden worker run --dry-run` reads the real inbox and prints a guardrailed plan.
|
||||
- Full-auto execution runs only in-scope, allowlisted actions; secrets/prod/out-of-scope
|
||||
escalate; every action is audited. No secret value ever enters a prompt, log, or commit.
|
||||
- Scheduled mode is enabled only after a dry-run shakedown.
|
||||
|
||||
## See also
|
||||
|
||||
- llm-connect (inference), activity-core (durable trigger), kaizen-agentic (personas)
|
||||
- `.claude/rules/credential-routing.md` (the boundary the worker enforces)
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
---
|
||||
id: WARDEN-WP-0021
|
||||
type: workplan
|
||||
title: "Enable the scheduled worker tick — conservative inbox triage, unattended"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 21
|
||||
created: "2026-06-30"
|
||||
updated: "2026-06-30"
|
||||
state_hub_workstream_id: "8c487014-b630-4016-a4f0-31b971a473d2"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0021 — Enable the scheduled worker tick
|
||||
|
||||
**Goal:** turn the WP-0020 conservative worker from *built-but-disabled* into a reliable,
|
||||
unattended schedule — so ops-warden's State Hub inbox is auto-triaged into a digest of
|
||||
**drafted replies** the operator reviews and approves, without anyone starting a session.
|
||||
This is the payoff of WP-0020: it ends the cross-session relay toil.
|
||||
|
||||
**Posture (unchanged):** schedule the **conservative** tier only — triage + draft, never
|
||||
auto-send (Option A / build-stage decision `813899f9`). The four guardrails hold. Easy
|
||||
kill switch is a requirement, not an afterthought (recoverability).
|
||||
|
||||
**What "enabled" means here:** (1) the tick runs on a schedule and survives the failure
|
||||
modes (hub/llm-connect down → graceful degrade), (2) the operator actually *sees* new
|
||||
drafts, (3) the operator can *act* on a draft with one command, (4) it's trivial to stop.
|
||||
|
||||
**Out of scope:** the full-auto (auto-send) path; flipping `policy.enabled`; moving the
|
||||
worker off the workstation.
|
||||
|
||||
**Depends on / relates to:** WP-0020 (the worker + `scripts/worker-tick.sh`); the State
|
||||
Hub migration to railiance01 (`cust-wp-0011`/`0038`) may change `WARDEN_HUB_URL` later —
|
||||
the tick already honors that env var.
|
||||
|
||||
---
|
||||
|
||||
## Decisions to settle (first)
|
||||
|
||||
- **Scheduler:** `systemd --user` timer (recommended — clean logs via `journalctl`,
|
||||
`systemctl --user status`, built-in scheduling) vs. plain cron (simplest) vs.
|
||||
activity-core (ecosystem-native durable trigger; heavier for build stage). Recommend the
|
||||
systemd user timer; cron documented as the one-liner fallback.
|
||||
- **Cadence:** every 15 min (default) — adjustable.
|
||||
- **llm-connect reachability:** per-tick short-lived port-forward (current behaviour) with
|
||||
rule-brain fallback, vs. a persistent forward. Recommend keeping the per-tick forward +
|
||||
fallback for build stage (no standing process).
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Scheduler install + enablement + kill switch
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0021-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "10451fe6-7fab-4ae0-8494-e6cfdfbcf8cf"
|
||||
```
|
||||
|
||||
- [ ] `systemd --user` timer + service units (`ops-warden-worker.{service,timer}`) that run
|
||||
`scripts/worker-tick.sh` on the chosen cadence, with `WARDEN_HUB_URL` / `WORKER_BRAIN`
|
||||
from an env file. Install script + documented cron fallback one-liner.
|
||||
- [ ] Concurrency is already guarded by the tick's `flock`; verify under the timer.
|
||||
- [ ] **Kill switch:** `systemctl --user disable --now ops-warden-worker.timer` (and the
|
||||
env-file `WORKER_ENABLED=0` short-circuit) — one command to stop, documented.
|
||||
|
||||
### T2 — Scheduled-run robustness (graceful degradation)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0021-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1f35f816-1af5-46ff-b48c-1715f3ae5784"
|
||||
```
|
||||
|
||||
- [ ] Harden `worker-tick.sh` for unattended runs: bounded timeouts, hub-unreachable →
|
||||
clean skip + log (no crash loop), llm-connect-unreachable → rule-brain fallback
|
||||
(already present; verify), non-zero exit only on real faults.
|
||||
- [ ] End-to-end verify a real timer-fired tick: new message → digest + progress note;
|
||||
no new message → no-op; hub down → graceful skip.
|
||||
|
||||
### T3 — Operator visibility (see new drafts)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0021-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "3c7f6423-8db0-4bc6-b67d-078d9d929c6d"
|
||||
```
|
||||
|
||||
- [ ] Surface new drafts beyond the file: desktop `notify-send` on new digest (when a
|
||||
display is present) and/or keep the hub progress note as the durable signal.
|
||||
- [ ] `warden worker status` — last run time, pending-draft count, digest path, timer state.
|
||||
|
||||
### T4 — Review→send loop (`warden worker approve`)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0021-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "dabc9fc0-abb1-4e9d-b87e-5f0c5950693c"
|
||||
```
|
||||
|
||||
- [ ] Persist structured drafts during the tick (`state_dir/worker-drafts.json`:
|
||||
message_id → to_agent, subject, drafted body, thread_id — no secret material).
|
||||
- [ ] `warden worker approve <message_id> [--edit]` — send the reviewed draft as the
|
||||
caller's reply + mark read; `warden worker drafts` to list pending. This is what makes
|
||||
the scheduled digest *actionable* in one command instead of hand-composing.
|
||||
|
||||
### T5 — Runbook + SCOPE
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0021-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "9915da96-1b33-4d0f-b752-408ea8d43333"
|
||||
```
|
||||
|
||||
- [ ] `wiki/playbooks/scheduled-worker.md` — enable/disable, cadence, the approve workflow,
|
||||
failure modes, and the build-stage posture (conservative only). SCOPE note.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- A `systemd --user` timer (or cron) runs the conservative tick unattended; one command
|
||||
disables it.
|
||||
- A timer-fired tick triages new messages into a digest + progress note and degrades
|
||||
gracefully when the hub or llm-connect is down.
|
||||
- The operator is notified of new drafts and can send a reviewed draft with
|
||||
`warden worker approve <id>`.
|
||||
- Still conservative: nothing is auto-sent; no secret value is read, sent, or logged.
|
||||
|
||||
## See also
|
||||
|
||||
- `WARDEN-WP-0020` (the worker + `scripts/worker-tick.sh`), build-stage decision `813899f9`
|
||||
- `cust-wp-0011`/`cust-wp-0038` (State Hub → railiance01; future `WARDEN_HUB_URL`)
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
id: WARDEN-WP-0022
|
||||
type: workplan
|
||||
title: "Audit trail + `warden activity` — one place to see what ops-warden did"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: claude
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 22
|
||||
created: "2026-07-01"
|
||||
updated: "2026-07-01"
|
||||
state_hub_workstream_id: "fc8afa28-68a7-4250-a19e-9754829f0cd5"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0022 — Audit trail + `warden activity`
|
||||
|
||||
**Problem:** ops-warden's actions are recorded in scattered places — `signatures.log`
|
||||
`access-audit.log`, the systemd journal (worker ticks), and
|
||||
State Hub progress notes (the narrative). There is **no single, structured audit trail**
|
||||
and no one command to answer *"what did ops-warden do in the last N days?"*. For a security
|
||||
steward, a coherent, metadata-only audit record is table stakes.
|
||||
|
||||
**Goal:** a unified, append-only audit log that captures **every** ops-warden action with a
|
||||
common shape (never a secret value), and a single `warden activity` command to read it.
|
||||
|
||||
**Non-negotiable (this is a security tool's audit):** the audit record holds **metadata
|
||||
only** — actor/subject, action, target/path id, decision id, TTL, outcome, timestamp — and
|
||||
**never** a token, key, cert body, or other secret. A secret-material guard rejects any
|
||||
event field that looks like a value (mirrors the catalog `_assert_no_secret_material`).
|
||||
|
||||
**Posture:** read/append-only, in-boundary (local logs + optional hub read). Tamper-evident
|
||||
hash-chaining is noted as an optional hardening for when the ecosystem reaches testing.
|
||||
|
||||
**Relates to:** WP-0014 (`access-audit.log`), the SSH lane (`signatures.log`), WP-0020/0021
|
||||
(the worker). Linger is now enabled (worker survives logout); full logged-out value also
|
||||
needs the State Hub + tunnels to be login-independent (State Hub → railiance01,
|
||||
`cust-wp-0011`).
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Unified audit event log
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0022-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "7f8f768a-4c62-4096-bad8-912cea0f35a7"
|
||||
```
|
||||
|
||||
- [x] `src/warden/audit.py`: append-only JSONL at `state_dir/audit.jsonl`. Common event
|
||||
schema — `ts`, `kind` (`sign`|`access`|`worker`), `action`, `subject`, `target`,
|
||||
`decision_id`, `outcome`, `source`. `record_event(**meta)` with a secret-material
|
||||
guard (reject token prefixes / high-entropy runs) so no value can ever land here.
|
||||
`read_events(*, since, kinds)` for the reader.
|
||||
- [x] Log rotation / bound (size or age) so it stays manageable.
|
||||
|
||||
### T2 — Instrument the actions
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0022-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "e7ae4037-ca79-4557-81f0-bfb8478ff647"
|
||||
```
|
||||
|
||||
- [x] Emit an audit event from each ops-warden action: `warden sign` (cert issued —
|
||||
actor, type, ttl, backend, policy_decision_id), `warden access --fetch/--exec`
|
||||
(proxy — need id, owner, decision id), and the worker (`approve` → reply sent to X;
|
||||
tick → triage summary N/drafted/escalated). Fold the existing `signatures.log` /
|
||||
`access-audit.log` in as sources (keep back-compat; don't drop a record).
|
||||
- [x] Assert no secret value reaches the audit in any path (tests).
|
||||
|
||||
### T3 — `warden activity` command
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0022-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "4439bdd8-1461-47df-8b0b-048df7384a68"
|
||||
```
|
||||
|
||||
- [x] `warden activity [--days N] [--kind sign|access|worker] [--json] [--hub]` — a single
|
||||
chronological view merging the audit log (and, for back-compat, `signatures.log` /
|
||||
`access-audit.log`); `--hub` also pulls recent ops-warden State Hub progress notes for
|
||||
the narrative. Human table by default; stable `--json` for agents.
|
||||
|
||||
### T4 — Tests, runbook, SCOPE
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0022-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "bdfb8703-7a79-43e7-913b-19d61722f164"
|
||||
```
|
||||
|
||||
- [x] Tests: audit append/read/rotation, the secret-material guard rejects values, the
|
||||
instrumented actions emit events, `warden activity` filtering + `--json` shape.
|
||||
- [x] `wiki/AuditTrail.md` (what's recorded, the no-secret guarantee, how to query, the
|
||||
linger + login-independence note). SCOPE entry.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Every ops-warden action (sign, access proxy, worker send/tick) appends a metadata-only
|
||||
audit event; the secret-material guard is proven to reject values.
|
||||
- `warden activity --days 3` answers "what did ops-warden do" in one command; `--json`
|
||||
gives agents a stable shape.
|
||||
- No secret value appears in the audit log, ever.
|
||||
|
||||
## See also
|
||||
|
||||
- `WARDEN-WP-0014` (`access-audit.log`), `WARDEN-WP-0020`/`0021` (the worker)
|
||||
- `wiki/OperatorAccessAssist.md` (the metadata-only audit principle)
|
||||
- `wiki/AuditTrail.md`
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
id: WARDEN-WP-0023
|
||||
type: workplan
|
||||
title: "INTENT–SCOPE Alignment Closeout"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 23
|
||||
created: "2026-07-01"
|
||||
updated: "2026-07-01"
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0022
|
||||
state_hub_workstream_id: "7bad1ec4-a7c2-4980-b8f9-49a7f5408574"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0023 — INTENT–SCOPE Alignment Closeout
|
||||
|
||||
## Goal
|
||||
|
||||
Close the July 2026 INTENT↔SCOPE gaps that ops-warden can address directly: sync
|
||||
aspirational docs with shipped capabilities, coordinate the remaining production
|
||||
integration blockers (flex-auth flip, ops-bridge cutover), improve daily operator
|
||||
UX for broker-backed signing, and establish a repeatable catalog promotion cadence.
|
||||
|
||||
Audit implementation stays in **WARDEN-WP-0022**; this workplan sequences and
|
||||
surrounds it.
|
||||
|
||||
**Assessment:** `history/2026-07-01-intent-scope-gap-analysis.md`
|
||||
|
||||
## Boundary
|
||||
|
||||
- ops-warden does **not** deploy flex-auth, flip ops-bridge tunnels, or implement
|
||||
the credential broker — it documents, coordinates, and routes.
|
||||
- Production cutover evidence is captured here; execution remains with owning repos.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Persist gap analysis
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "52485c90-87fe-40b1-9db5-a51ebb957dd5"
|
||||
```
|
||||
|
||||
Write and link `history/2026-07-01-intent-scope-gap-analysis.md` with success
|
||||
criteria matrix, mission pillars, prioritized gaps, and workplan recommendation.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- History file exists and is referenced from SCOPE and this workplan.
|
||||
- State Hub progress note logged for the assessment.
|
||||
|
||||
**2026-07-01:** Assessment written at
|
||||
`history/2026-07-01-intent-scope-gap-analysis.md`.
|
||||
|
||||
### T02 — Refresh INTENT.md
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9a9b3631-8948-45af-ace1-c19ee74ace4d"
|
||||
```
|
||||
|
||||
Update `INTENT.md` so the aspirational doc reflects shipped reality without
|
||||
becoming a second SCOPE:
|
||||
|
||||
- Mission pillar #2: assist layer (`warden access`) and owner-native exec routing
|
||||
(secrets-engine, railiance-platform credential broker).
|
||||
- NetKingdom literacy table: add secrets-engine and credential broker rows.
|
||||
- Credential flow diagram: broker vs secrets-engine vs OpenBao proxy vs SSH issue.
|
||||
- flex-auth: caller-side policy gate shipped; production flip external (FLEX-WP-0007).
|
||||
- Workload posture stewardship and coordination worker as steward capabilities.
|
||||
- Evolution notes pointer to July gap analysis.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- INTENT still describes direction, not implementation inventory.
|
||||
- No contradiction with SCOPE 2026-07-01 boundary (ops-warden does not mint tokens).
|
||||
|
||||
**2026-07-01:** INTENT.md updated.
|
||||
|
||||
### T03 — Production integration coordination pack
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "26f23798-494b-45fc-baa8-af27bdffa038"
|
||||
```
|
||||
|
||||
Prepare operator/coordination artifacts for the two P1 external gaps:
|
||||
|
||||
1. **flex-auth production flip** — checklist in `wiki/PolicyGatedSigning.md` or a
|
||||
short playbook section: prerequisites, `policy.enabled: true` steps, rollback,
|
||||
joint smoke with `credential-exec-ops-warden-smoke`, FLEX-WP-0007 cross-link.
|
||||
2. **ops-bridge live cutover** — evidence template (non-secret): tunnel id, readiness
|
||||
gate output, first warden-signed connection timestamp, pointer to
|
||||
`wiki/playbooks/ops-bridge-tunnel-cert.md`.
|
||||
|
||||
Optionally post State Hub coordination messages to `flex-auth` and `ops-bridge`
|
||||
agents with pointers only (no secrets).
|
||||
|
||||
Acceptance:
|
||||
|
||||
- A human operator can run the flip/cutover checklists without re-deriving steps.
|
||||
- Evidence fields are defined; completion is recorded via State Hub progress when done.
|
||||
|
||||
**2026-07-01:** Rollback section added to `wiki/PolicyGatedSigning.md`; live cutover
|
||||
evidence template added to `wiki/playbooks/ops-bridge-tunnel-cert.md`.
|
||||
|
||||
### T04 — `warden sign` broker hint when `VAULT_TOKEN` unset
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "85e324f9-273d-4740-a202-9c4e8fb122ae"
|
||||
```
|
||||
|
||||
When `backend: vault` and `VAULT_TOKEN` (or configured `token_env`) is missing,
|
||||
emit a structured hint pointing at `ops-warden-warden-sign-token` and the
|
||||
`railiance-platform` `credential exec` command — not a generic error only.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Unit test covers the hint text (catalog id + exec shape, no secret placeholders).
|
||||
- Manual `export VAULT_TOKEN` remains documented as fallback in playbooks.
|
||||
|
||||
**2026-07-01:** `src/warden/vault_hints.py` + `tests/test_vault.py`.
|
||||
|
||||
### T05 — Catalog draft-lane promotion checklist
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "82608692-2845-41e1-a498-90ed53780748"
|
||||
```
|
||||
|
||||
Document the promotion criteria for `registry/routing/catalog.yaml` entries from
|
||||
`draft` → `active` (concrete path, owner confirmation, `resolvable` or
|
||||
`exec_owner` native exec, playbook with `#worker-checklist`, tests). Add to
|
||||
`wiki/CredentialRouting.md` or a short `wiki/playbooks/catalog-lane-promotion.md`.
|
||||
|
||||
If any draft lane has owner-confirmed concrete paths during this WP, promote one
|
||||
as a worked example (issue-core, OpenRouter, STS, or database — whichever is ready).
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Checklist is reviewable by humans and agents.
|
||||
- At least one promotion example or explicit “none ready yet” note in the workplan.
|
||||
|
||||
**2026-07-01:** `wiki/playbooks/catalog-lane-promotion.md` — worked example
|
||||
`ops-warden-warden-sign-token`; four draft lanes explicitly not ready.
|
||||
|
||||
### T06 — SCOPE and workplan consistency
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "79ca7b9a-554e-4952-9393-a29b100f6190"
|
||||
```
|
||||
|
||||
Fix SCOPE inconsistencies noted in the July assessment:
|
||||
|
||||
- “All workplans finished” → acknowledge WP-0022/0023 as active/ready.
|
||||
- Latest gap analysis pointer → `history/2026-07-01-intent-scope-gap-analysis.md`.
|
||||
- Link WP-0023 from Getting Oriented.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- SCOPE and gap analysis cross-link correctly.
|
||||
- Uncommitted SCOPE edits from 2026-07-01 broker routing are committed with this WP.
|
||||
|
||||
**2026-07-01:** SCOPE.md updated.
|
||||
|
||||
### T07 — Sequence WP-0022 audit implementation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0023-T07
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1f3b3b33-974e-49bf-be4a-9d50b702c2a4"
|
||||
```
|
||||
|
||||
Promote `WARDEN-WP-0022` from `proposed` to `ready` (or `active` when T02–T06 allow
|
||||
bandwidth). Ensure dependency is explicit; log State Hub note that WP-0022 is the
|
||||
implementation vehicle for INTENT pillar 6 (observable gatekeeping).
|
||||
|
||||
Acceptance:
|
||||
|
||||
- WP-0022 frontmatter status updated.
|
||||
- WP-0023 `depends_on_workplans` includes WP-0022.
|
||||
- Hub consistency run syncs both workplans.
|
||||
|
||||
**2026-07-01:** WP-0022 implemented and both workplans marked `finished`.
|
||||
|
||||
---
|
||||
|
||||
## Exit criteria
|
||||
|
||||
- July gap analysis is the canonical reassessment (linked from SCOPE).
|
||||
- INTENT.md no longer understates assist, posture, worker, or owner-native exec.
|
||||
- Production integration checklists exist for flex-auth flip and ops-bridge cutover.
|
||||
- `warden sign` surfaces the broker path when vault backend lacks a token.
|
||||
- Catalog promotion cadence is documented; WP-0022 is queued for implementation.
|
||||
|
||||
## See also
|
||||
|
||||
- `history/2026-07-01-intent-scope-gap-analysis.md`
|
||||
- `WARDEN-WP-0022-audit-trail-and-activity.md`
|
||||
- `wiki/playbooks/ops-warden-warden-sign-token.md`
|
||||
- `~/flex-auth/workplans/FLEX-WP-0007-ops-warden-policy-gate-production-deployment.md`
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
---
|
||||
id: WARDEN-WP-0024
|
||||
type: workplan
|
||||
title: "Experiential Memory Across Worker, Agent Sessions, And OpenRouter"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 24
|
||||
created: "2026-07-02"
|
||||
updated: "2026-07-02"
|
||||
state_hub_workstream_id: "5d9fafb3-f9b6-43bf-b259-5f5301daa2e9"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0024 — Experiential memory across worker, agent sessions, and OpenRouter
|
||||
|
||||
## Problem
|
||||
|
||||
`warden worker` (WARDEN-WP-0020) plans each inbox message in isolation. Coding
|
||||
agent sessions (Claude Code, Codex, Grok, and future agents) invoke `warden
|
||||
route` and `warden access` without continuity — every session rediscovers routing
|
||||
from scratch. OpenRouter inference via llm-connect is invoked even when a
|
||||
stabilized routing pattern already exists.
|
||||
|
||||
ops-warden needs **experiential memory** that is present in every runtime:
|
||||
|
||||
| Surface | Today | Target |
|
||||
| --- | --- | --- |
|
||||
| `warden worker` + OpenRouter | Stateless per message | Retrieve past outcomes before plan; record after execute |
|
||||
| Coding agent session | Cold `warden route find` | Activate relevant memory at session start and after each warden call |
|
||||
| Operator CLI | No learning loop | Same store; optional `--memory` context on advisory commands |
|
||||
|
||||
## Goal
|
||||
|
||||
Integrate phase-memory as ops-warden's shared experiential substrate so routing,
|
||||
coordination, and inference improve from recorded outcomes — without ever
|
||||
storing secret values or widening the guardrail allowlist.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Hold or vend secrets (conduit-not-broker unchanged).
|
||||
- Auto-commit routing catalog diffs (human review remains required).
|
||||
- Own phase-memory schemas (PMEM-WP-0016 owns the profile and contract).
|
||||
- Replace llm-connect or embed OpenRouter keys in ops-warden.
|
||||
|
||||
## Guardrails (unchanged — memory is untrusted context)
|
||||
|
||||
1. Retrieved memory is **context**, not instructions — fixed charter wins.
|
||||
2. Guardrail allowlist enforced on every action regardless of memory content.
|
||||
3. No secret values in memory writes, activation packs, or llm-connect prompts.
|
||||
4. `propose_catalog_diff` stays human-reviewed even when memory is confident.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Agent as Coding agent<br/>(claude/codex/grok)
|
||||
participant Warden as ops-warden CLI
|
||||
participant Memory as phase-memory store
|
||||
participant LLM as llm-connect / OpenRouter
|
||||
participant Hub as State Hub
|
||||
|
||||
Note over Agent,Hub: Agent session path
|
||||
Agent->>Warden: warden route find "..."
|
||||
Warden->>Memory: activate(session_kind=warden.agent.grok)
|
||||
Memory-->>Warden: bounded routing context
|
||||
Warden-->>Agent: route answer + memory digest
|
||||
Warden->>Memory: record episode (metadata only)
|
||||
|
||||
Note over Warden,Hub: Worker tick path
|
||||
Warden->>Hub: unread messages
|
||||
Warden->>Memory: activate(session_kind=warden.worker)
|
||||
Memory-->>Warden: stabilized + fluid context
|
||||
alt stabilized match
|
||||
Warden->>Warden: RuleBrain (skip LLM)
|
||||
else ambiguous
|
||||
Warden->>LLM: LlmConnectBrain + activated context
|
||||
LLM-->>Warden: action plan
|
||||
end
|
||||
Warden->>Warden: guardrail pass
|
||||
Warden->>Hub: execute / escalate
|
||||
Warden->>Memory: record outcome
|
||||
```
|
||||
|
||||
## T01 - Canonical memory store and discovery
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6305f1bc-c016-4298-adc2-a07d52b6aca5"
|
||||
```
|
||||
|
||||
Establish the canonical phase-memory store path and discovery commands.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Default store at XDG location (e.g. `~/.local/share/warden/memory/`) with
|
||||
override via `WARDEN_MEMORY_STORE`.
|
||||
- `warden memory status` reports store path, schema version, episode counts by
|
||||
`session_kind`, and last activation timestamp — no secret fields.
|
||||
- Store initializes idempotently; missing phase-memory dependency fails with a
|
||||
clear install pointer, not a traceback.
|
||||
- Tests cover default path, override, and first-run initialization.
|
||||
|
||||
## T02 - Session recording hooks in CLI commands
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "242a4d9a-5375-4df8-8d43-063b0491d202"
|
||||
```
|
||||
|
||||
Record metadata-only episodes when `route`, `access`, and `sign` complete.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Each command writes a phase-memory event with `session_kind` derived from
|
||||
environment: `WARDEN_AGENT_ID` (claude|codex|grok|...) when set, else
|
||||
`warden.operator`.
|
||||
- Recorded fields match `PMEM-WP-0016-T03` schema; secret patterns are rejected.
|
||||
- Recording is opt-out via `WARDEN_MEMORY=0` for air-gapped/debug use.
|
||||
- `warden activity` and phase-memory audit export remain consistent (no
|
||||
duplicate secret-bearing logs).
|
||||
|
||||
## T03 - Memory-aware worker tick
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "176fcae1-e4e5-481f-9a83-e9a7000fac1a"
|
||||
```
|
||||
|
||||
Retrieve coordination memory before `Brain.plan` and record outcomes after execute.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- `warden worker run` activates memory with `session_kind=warden.worker` before
|
||||
planning each message.
|
||||
- Activated context is passed to `LlmConnectBrain` as bounded, redacted context
|
||||
— never replacing the fixed charter.
|
||||
- Post-execute hook records: message id, proposed actions, guardrail outcome,
|
||||
escalation reason, and route ids referenced.
|
||||
- Worker tick with empty store degrades gracefully (current behavior).
|
||||
|
||||
## T04 - Agent session activation helper
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "16501557-6cde-44ea-bc6f-1726cb7ec070"
|
||||
```
|
||||
|
||||
Expose memory activation for coding agent sessions across Claude, Codex, Grok, and
|
||||
future agents.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- `warden memory activate [--agent <id>] [--json]` returns a bounded activation
|
||||
package for session orientation.
|
||||
- Agent instructions (AGENTS.md template in consuming repos) document setting
|
||||
`WARDEN_AGENT_ID` and calling `warden memory activate` at session start.
|
||||
- Activation works without OpenRouter (local retrieval only).
|
||||
- Tests cover agent ids: `claude`, `codex`, `grok`, and an unknown future id.
|
||||
|
||||
## T05 - Cross-runtime continuity
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "55ae679c-c08f-4afd-8646-9f5f3019f86e"
|
||||
```
|
||||
|
||||
Ensure worker ticks see agent session episodes and vice versa.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Agent session routing outcomes appear in worker activation within the same
|
||||
store without manual export/import.
|
||||
- Worker escalation outcomes are visible to subsequent agent session activations.
|
||||
- Continuity is verified by an integration test: agent session write → worker
|
||||
read → agent session read round-trip.
|
||||
- Episode retention follows the ops-warden profile compaction rules from
|
||||
PMEM-WP-0016.
|
||||
|
||||
## T06 - OpenRouter efficiency layer
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "fc2dffcf-7184-4f3d-8653-d26dc18a9afc"
|
||||
```
|
||||
|
||||
Skip or downgrade OpenRouter calls when stabilized memory provides a verified match.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- When stabilized memory contains a verified route match for the message need,
|
||||
`RuleBrain` handles the plan and llm-connect is not called.
|
||||
- Ambiguous cases still use `LlmConnectBrain`; memory context is additive only.
|
||||
- Efficiency metrics (llm_calls_avoided, rule_brain_resolution_rate) are
|
||||
recorded for evaluation scenarios in PMEM-WP-0016.
|
||||
- Dry-run mode reports whether LLM would have been skipped and why.
|
||||
|
||||
## T07 - Operator and agent documentation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0024-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ca2aaf23-833f-49a6-a49b-a0b659208f5f"
|
||||
```
|
||||
|
||||
Document the memory workflow for operators and coding agents.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Wiki page covers: store location, session kinds, agent env vars, memory
|
||||
activation at session start, and interaction with OpenRouter inference.
|
||||
- ops-warden AGENTS.md and the state-hub agent template include memory
|
||||
orientation steps for Claude, Codex, and Grok sessions.
|
||||
- Credential routing doc cross-links PMEM-WP-0016 contract; anti-patterns
|
||||
updated (no secret values in memory store).
|
||||
- Scheduled worker playbook notes memory retention and evaluation gate checks.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- phase-memory is present and useful in all three runtime surfaces (worker,
|
||||
agent session, operator CLI) through one canonical store.
|
||||
- OpenRouter inference cost decreases when stabilized routing memory matches.
|
||||
- Cross-runtime continuity is tested and regression-gated.
|
||||
- Security invariants (no-secret, allowlist, conduit-not-broker) are unchanged.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `PMEM-WP-0016` (phase-memory) — profile, event schema, activation pack,
|
||||
evaluation scenarios. **Implement contract (T01–T03) before WARDEN T03–T05.**
|
||||
- `WARDEN-WP-0020` — worker brain and guardrails (finished).
|
||||
- `WARDEN-WP-0022` — audit trail for correlation (finished).
|
||||
- llm-connect / OpenRouter — required only for T06 live efficiency measurement;
|
||||
T01–T05 work offline.
|
||||
|
||||
## Suggested Implementation Order
|
||||
|
||||
1. PMEM-WP-0016 T01–T03 (profile + contract + event schema)
|
||||
2. WARDEN-WP-0024 T01–T02 (store + CLI recording)
|
||||
3. PMEM-WP-0016 T04 (activation pack)
|
||||
4. WARDEN-WP-0024 T03–T05 (worker + agent activation + continuity)
|
||||
5. PMEM-WP-0016 T05–T06 + WARDEN-WP-0024 T06–T07 (evaluation + docs)
|
||||
|
||||
## Closure Review
|
||||
|
||||
Integrated phase-memory across all ops-warden runtime surfaces:
|
||||
|
||||
- `warden memory status` and `warden memory activate` with canonical XDG store.
|
||||
- CLI recording hooks on `route find`, `access`, and `sign` (opt-out via
|
||||
`WARDEN_MEMORY=0`).
|
||||
- Memory-aware worker planning with stabilized-route RuleBrain short-circuit
|
||||
and LlmConnectBrain context injection.
|
||||
- Cross-runtime continuity verified in tests (agent session → worker activation).
|
||||
- `wiki/OpsWardenMemory.md` and AGENTS.md session orientation for Claude,
|
||||
Codex, Grok, and future agents.
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
id: WARDEN-WP-0025
|
||||
type: workplan
|
||||
title: "Forgejo admin PAT OpenBao lane (CCR-2026-0006)"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: grok
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 25
|
||||
created: "2026-07-12"
|
||||
updated: "2026-07-13"
|
||||
state_hub_workstream_id: "70c11222-d8e7-5936-99f7-7d626a4a5deb"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0025 — Forgejo admin PAT OpenBao lane
|
||||
|
||||
**Trigger:** the-custodian CCR request (msg `54125f84`) — establish OpenBao custody
|
||||
for the Forgejo site-admin PAT at `platform/workloads/forgejo/forgejo-admin`.
|
||||
Drivers: `ACTIVITY-WP-0020` weekly package prune and railiance-apps/platform tools
|
||||
still using `/tmp/forgejo-tegwick-api-token` or `FORGEJO_ADMIN_TOKEN`.
|
||||
|
||||
**Boundary:** ops-warden holds no PAT; workstation OIDC fetch mirrors
|
||||
`railiance-backup-offsite-lane` (CCR-2026-0004). Distinct from `forgejo-mailer`
|
||||
(SMTP via ESO). Phase 1: no cluster ExternalSecret.
|
||||
|
||||
**Depends on:** platform-operator approval of CCR-2026-0006; attended PAT mint.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Draft CCR + policy metadata
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0025-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "2c288bf0-b39c-5f5b-ad25-eed3da826dc3"
|
||||
```
|
||||
|
||||
- [x] `CCR-2026-0006-forgejo-admin-api-token-lane.yaml` (`status: proposed`)
|
||||
- [x] `openbao/policies/workload-kv-read-forgejo-admin.hcl`
|
||||
- [x] `docs/workload-kv-access-lanes.md` section
|
||||
|
||||
### T2 — ops-warden catalog + playbook
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0025-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "01b81595-f9e5-5746-b0dd-2075189cb00e"
|
||||
```
|
||||
|
||||
- [x] Catalog entry `forgejo-admin-api-token` (`status: draft`)
|
||||
- [x] `wiki/playbooks/forgejo-admin-api-token.md`
|
||||
|
||||
### T3 — Platform-operator approval + metadata apply
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0025-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "279b74d7-3240-5ca0-897d-b1ddffd23c4e"
|
||||
```
|
||||
|
||||
- [x] CCR approved by platform-operator (bernd.worsch, 2026-07-12)
|
||||
- [x] `scripts/credential-change.py applier-dry-run CCR-2026-0006`
|
||||
- [x] Policy `workload-kv-read-forgejo-admin` + OIDC role `forgejo-admin-workload-kv-read` applied on `bao.coulomb.social`
|
||||
- [x] Non-secret `delegated_metadata_apply` evidence on CCR
|
||||
|
||||
### T4 — Attended PAT provision + verification
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0025-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "4e21232c-62a1-5115-acce-edfbcfa84e48"
|
||||
```
|
||||
|
||||
- [x] Mint PAT as Forgejo user `tegwick` (attended, 2026-07-12)
|
||||
- [x] Stored at `platform/workloads/forgejo/forgejo-admin`, field `API_TOKEN`
|
||||
(initial provision used field `Token`; re-stored as `API_TOKEN` 2026-07-13 to
|
||||
match CCR/catalog/playbook `fetch_command`)
|
||||
- [x] Positive fetch verified 2026-07-13 — `bao kv get -field=API_TOKEN …` returns
|
||||
non-empty; PAT valid against `forgejo.coulomb.social` (`/api/v1/user` →
|
||||
`login=tegwick`, `is_admin=true`)
|
||||
- [x] Negative default-policy denial recorded on CCR
|
||||
- [x] Promoted catalog `forgejo-admin-api-token` to `active` (`resolvable: true`)
|
||||
|
||||
### T5 — Notify downstream consumers
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0025-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "f8c7c70b-b9b6-5980-a25b-7f11033b81a2"
|
||||
```
|
||||
|
||||
- [x] Ack the-custodian with CCR id + catalog id (no secret values) — msg 949e8ed1, 2026-07-13
|
||||
- [x] Signal railiance-platform / activity-core / railiance-apps to wire `load_token()`
|
||||
OpenBao paths — msgs 5be8e500 / 9ed1af98 / 2e47b6e5, 2026-07-13
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- CCR-2026-0006 approved, policy + OIDC role live, PAT in OpenBao
|
||||
- `warden route find "forgejo admin pat"` → `forgejo-admin-api-token`
|
||||
- No PAT in Git, State Hub, workplans, logs, or chat
|
||||
- Workstation file drop retired as steady-state path after downstream wiring
|
||||
|
||||
## See also
|
||||
|
||||
- `railiance-platform/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml`
|
||||
- `activity-core/workplans/ACTIVITY-WP-0020-weekly-forgejo-package-prune.md`
|
||||
- Custodian message `54125f84-e9df-4fa0-9309-7370633a20d3`
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
---
|
||||
id: WARDEN-WP-0026
|
||||
type: workplan
|
||||
title: "Credential disclosure hygiene + rotation guidance (Strand A)"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 26
|
||||
created: "2026-07-16"
|
||||
updated: "2026-07-16"
|
||||
state_hub_workstream_id: "331c7620-bd34-5acd-9135-591985b568e5"
|
||||
---
|
||||
|
||||
# Credential disclosure hygiene + rotation guidance (Strand A)
|
||||
|
||||
## Origin
|
||||
|
||||
Follow-up to a credential-disclosure incident on 2026-07-16 while verifying
|
||||
`CCR-2026-0004` (railiance offsite backup lane). A negative policy test was run
|
||||
as `BAO_TOKEN=$(bao token create -policy=default -field=token) bao kv get <path>`.
|
||||
The `token create` was denied (workload role lacks it), `BAO_TOKEN` fell back to
|
||||
the caller's privileged login token, and `bao kv get` printed all three field
|
||||
values (`NC_WEBDAV_TOKEN`, `NC_WEBDAV_URL`, `AGE_PRIVATE_KEY`) into an agent
|
||||
session transcript. Buildup mode — exposure accepted, learnings captured.
|
||||
|
||||
**Root causes:** (1) a deny-test that read the secret *data* path at all;
|
||||
(2) a silent privileged-token fallback; (3) the read landed in a logged context.
|
||||
|
||||
This is **Strand A** (disclosure hygiene). Tamper-resistant policy governance and
|
||||
one-command mass rotation/lockdown (Strand B) are deliberately **deferred** — see
|
||||
"Out of scope" below.
|
||||
|
||||
## Goal
|
||||
|
||||
Make accidental secret disclosure structurally hard, and make ops-warden the
|
||||
authoritative source for **how each secret is rotated or re-established** —
|
||||
advisory knowledge held next to the routing catalog, not in OpenBao.
|
||||
|
||||
## Design guardrails (binding on acceptance)
|
||||
|
||||
- **Verification never reads secret data.** Use `bao token capabilities` (allow/deny)
|
||||
instead of `kv get` for positive/negative lane tests.
|
||||
- **Masking is defense-in-depth, not a boundary.** Any display filter is a wrapper
|
||||
convenience; raw `bao kv get <path>` remains the documented anti-pattern.
|
||||
- **Rotation guidance covers both `rotate` (provider re-mint) and `re-establish`
|
||||
(regenerate from source, e.g. a new age keypair).**
|
||||
- **Coverage gate:** every `active` (and newly promoted) catalog lane must carry
|
||||
rotation guidance, enforced by a scorecard check.
|
||||
|
||||
## Out of scope (Strand B — deferred, not built here)
|
||||
|
||||
- Executable one-command rotation of all tainted secrets.
|
||||
- Graded lockdown / break-glass seal + re-key with a designed trust-root.
|
||||
- Policy time-travel / policy-as-code reconcile-to-past-commit. (Drift *detection*
|
||||
may be revisited separately; the reconcile machinery is out.)
|
||||
|
||||
## Task: Capabilities-based lane verification
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1cb22a40-b7c6-560a-a805-7766a5786dcc"
|
||||
```
|
||||
|
||||
Done 2026-07-16: canonical capabilities-safe verification pattern added to
|
||||
`wiki/playbooks/catalog-lane-promotion.md` (fleet promotion checklist criterion 8
|
||||
+ dedicated section), and applied to the `railiance-backup-offsite-lane` and
|
||||
`forgejo-admin-api-token` playbook verify sections. Positive/negative proven via
|
||||
`bao token capabilities` against the KV v2 data path — never `bao kv get`; the
|
||||
denied `default` token-create is documented as a pass, not a fallback trigger.
|
||||
Live CCR-2026-0004 re-verify carried under T07.
|
||||
|
||||
Replace secret-reading verify flows with capability checks. Positive test:
|
||||
approved identity has `read` on the KV data path. Negative test: a `default`-only
|
||||
identity is `deny`. Both via `bao token capabilities <token> <path>` (or the
|
||||
self endpoint) — **never** `bao kv get`. Update
|
||||
`wiki/playbooks/*lane*.md` verify sections and any lane-verify helper.
|
||||
|
||||
**Done when:** the documented and tooled verify path for any lane proves
|
||||
allow/deny without reading a secret value, and the CCR-2026-0004 re-verify uses
|
||||
it (see T07).
|
||||
|
||||
## Task: Safe access transport (no stdout values)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "bcb7da96-0a28-5484-bf3e-06e97acf5873"
|
||||
```
|
||||
|
||||
Done 2026-07-16: sanctioned transports added to `warden access` so a value never
|
||||
lands on stdout — `--out FILE` (mode-0600 file), `--exec` (child env, pre-existing),
|
||||
and `--wrap` (single-use OpenBao response-wrapping token via `bao kv get -wrap-ttl`,
|
||||
caller `bao unwrap`s in their own context). Raw `--fetch` to a non-TTY stdout is now
|
||||
refused (exit 6) unless `--unsafe-stdout` is passed (interactive human only).
|
||||
`proxy_fetch_to_file`/`proxy_fetch_wrapped`/`build_wrapped_fetch` in `proxy.py`; tests
|
||||
in `tests/test_proxy.py`. Anti-pattern + transports documented fleet-wide in
|
||||
`.claude/rules/credential-routing.md` and `wiki/OperatorAccessAssist.md` (G2).
|
||||
|
||||
`warden access` / fetch paths must emit values only into an env var, a file, or
|
||||
a **response-wrapping token** (`bao … -wrap-ttl`), never a stdout table. Add a
|
||||
wrapping-token transport for values that must move between processes. Record in
|
||||
canon (`credential-routing` rules) that raw `bao kv get <path>` (full table) is
|
||||
the anti-pattern; the sanctioned path is `warden access … --field <F>` into env.
|
||||
|
||||
**Done when:** the sanctioned fetch path cannot print a value to a terminal, and
|
||||
the anti-pattern is documented fleet-wide.
|
||||
|
||||
## Task: Masking display filter (defense-in-depth)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d90b0628-fa1d-527d-99c3-28a7ed933e52"
|
||||
```
|
||||
|
||||
Done 2026-07-16: `warden/mask.py` (`fingerprint`/`mask_value` — presence, length,
|
||||
8-char sha256 prefix; never the value) + `proxy_fetch_fingerprint` and a
|
||||
`warden access … --fingerprint` masked status view (bypasses the stdout guard
|
||||
because it emits no value). Lets two parties compare sha256 prefixes to confirm a
|
||||
shared value (e.g. rotation landed) without disclosure. Explicitly labelled
|
||||
defense-in-depth — raw `bao kv get` bypasses it — in `wiki/OperatorAccessAssist.md`
|
||||
and the module docstring. Tests in `tests/test_mask.py` + a CLI test in
|
||||
`tests/test_proxy.py`.
|
||||
|
||||
In the warden wrapper, mask KV data values by default when any listing/status is
|
||||
shown — display presence, length, and a short non-reversible hash instead of the
|
||||
value. Explicitly labelled as defense-in-depth (raw bao bypasses it).
|
||||
|
||||
**Done when:** wrapper-mediated output never shows a raw KV value, with the
|
||||
limitation documented.
|
||||
|
||||
## Task: Agent read-boundary on high-risk lanes
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "827fa67d-5f69-5fac-bdce-9903b1b909fb"
|
||||
```
|
||||
|
||||
Done 2026-07-16: Catalog `risk: high|standard` (default standard). High-risk:
|
||||
`railiance-backup-offsite-lane`, `forgejo-admin-api-token`, `openrouter-llm-connect`.
|
||||
OpenBao policy `agent-high-risk-boundary` (railiance-platform + live write) grants
|
||||
metadata/capabilities only and **denies** data-read on those paths — verified with
|
||||
minted agent token (data=deny, metadata=read). `warden access` with
|
||||
`WARDEN_AGENT_ID` set refuses raw value stream on high-risk lanes (exit 7);
|
||||
`--out`/`--exec`/`--wrap`/`--fingerprint` remain. Playbook:
|
||||
`wiki/playbooks/agent-read-boundary.md`. Tests in `tests/test_routing.py` +
|
||||
`tests/test_proxy.py`.
|
||||
|
||||
**Repo: railiance-platform (OpenBao policy/roles).** Agent identities receive
|
||||
`capabilities`/metadata and wrapping tokens on high-risk lanes, not raw data
|
||||
reads. Align with the existing credential-routing rule ("ops-warden proxies reads
|
||||
as the caller and must not retain values"). Classify which lanes are high-risk
|
||||
(recovery escrow like `AGE_PRIVATE_KEY`, upload tokens).
|
||||
|
||||
**Done when:** at least the high-risk lanes deny raw data reads to agent roles
|
||||
while still allowing wrapped/proxied access, verified via capabilities checks.
|
||||
|
||||
## Task: EXPOSED taint convention
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "09ef8727-31da-59ac-aac7-2d47924569fe"
|
||||
```
|
||||
|
||||
Done 2026-07-16: Convention documented in `wiki/playbooks/exposed-taint.md`
|
||||
(`exposed_at`, `exposed_version`, `exposed_reason`, `exposed_ref` on KV v2
|
||||
custom_metadata). First worked mark applied to
|
||||
`platform/workloads/railiance/backup/offsite-lane` version 2 (disclosure
|
||||
incident). `warden taint <id>` (+ `--json`) reports taint via metadata-only
|
||||
`bao kv metadata get` — never secret data (`src/warden/taint.py`). Tests in
|
||||
`tests/test_taint.py`.
|
||||
|
||||
**Repo: railiance-platform (OpenBao) + ops-warden surface.** Establish a KV v2
|
||||
`custom_metadata` convention to mark a tainted secret: `exposed_at=<datetime>`
|
||||
and the affected `version`. Identify semi-automatic candidates from the OpenBao
|
||||
audit log (reads from agent/shared contexts). `warden` surfaces taint status for
|
||||
a lane (advisory; no auto-rotation here).
|
||||
|
||||
**Done when:** a secret can be marked EXPOSED via a documented convention and
|
||||
`warden` reports whether a lane is currently tainted.
|
||||
|
||||
## Task: Rotation / re-establishment guidance registry
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T06
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a2e1544e-e501-57eb-a40e-9a2147cef12a"
|
||||
```
|
||||
|
||||
Done 2026-07-16: `rotation:` block (method rotate|re-establish, ordered steps,
|
||||
owner, automatable) added to the routing model/parser (`RotationGuide`,
|
||||
`RouteEntry.rotation`, `vends_secret`), screened for secret material in a prose-safe
|
||||
mode. `warden rotate-guide <id>` (human + `--json`) surfaces the guidance; `warden
|
||||
route show --json` carries `has_rotation` + `rotation`. Coverage enforced by the new
|
||||
`catalog_rotation_coverage` scorecard check (every active secret-vending lane must
|
||||
have a block) and promotion checklist criterion 9. Rotation blocks authored for all
|
||||
7 active vending lanes + the draft railiance-backup lane (re-establish example: age
|
||||
keypair regen + re-encrypt). Tests in `tests/test_routing.py`. Also fixed a
|
||||
pre-existing keyword collision (bare `npm` on the forgejo-admin lane → `forgejo-npm`)
|
||||
so "npm token" routes to the generic lane again.
|
||||
|
||||
Give every catalog lane **structured-but-advisory** renewal guidance, held in the
|
||||
ops-warden registry (not in OpenBao). Add a `rotation:` block per catalog entry
|
||||
capturing: `method` (rotate | re-establish), ordered `steps` (provider re-mint /
|
||||
keygen / OpenBao write / re-encrypt-and-reupload where relevant), `owner`, and
|
||||
`automatable` (bool, for future Strand-B). Surface via `warden rotate-guide <id>`
|
||||
(and/or `warden route … --rotate`). Add a **scorecard coverage check**: every
|
||||
`active` lane must have a `rotation:` block; flag any that don't.
|
||||
|
||||
**Done when:** `warden rotate-guide <id>` returns actionable renewal steps for
|
||||
every active lane, and the scorecard fails if any active lane lacks guidance.
|
||||
|
||||
## Task: Incident lessons + first worked lane (CCR-2026-0004)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0026-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "62d8286f-7954-52a8-bce6-6a16072e5246"
|
||||
```
|
||||
|
||||
Done 2026-07-16: Lessons note present. Capabilities-safe live re-verify on
|
||||
`bao.coulomb.social`: lane-policy token → `read` on data path; default + agent
|
||||
boundary → `deny`; field keys present (no values printed). Catalog promoted
|
||||
`draft`→`active`, `fetch_command` pinned to `NC_WEBDAV_TOKEN` (no placeholders)
|
||||
so `resolvable: true`; `risk: high`; rotation guidance + EXPOSED taint on v2.
|
||||
CCR-2026-0004 evidence + `access_frontdoor.resolvable: true` / `readiness: ready`.
|
||||
Playbook + `wiki/CredentialRouting.md` updated. Operator may still rotate the
|
||||
exposed values optionally (buildup) — not a promotion blocker.
|
||||
|
||||
Write a short lessons-learned note (buildup context; exposure accepted; the three
|
||||
root causes). Apply T01 + T06 to `CCR-2026-0004` as the first worked lane:
|
||||
re-verify it the capabilities-safe way so it can finally promote to
|
||||
`resolvable: true` (unblocking `RAILIANCE-WP-0015`), and ensure its `rotation:`
|
||||
block (rotate Nextcloud token; re-establish age keypair + re-encrypt artifacts)
|
||||
is present. **Rotation of the exposed values is the operator's optional call, not
|
||||
a blocker** (buildup).
|
||||
|
||||
**Done when:** the lessons note exists, CCR-2026-0004 has capabilities-based
|
||||
verify + rotation guidance, and its promotion path is unblocked.
|
||||
|
||||
## References
|
||||
|
||||
- `CCR-2026-0004-railiance-backup-offsite-lane.yaml` (railiance-platform)
|
||||
- `wiki/playbooks/railiance-backup-offsite-lane.md`
|
||||
- `.claude/rules/credential-routing.md` (the-custodian, fleet-inlined)
|
||||
- `RAILIANCE-WP-0015` (railiance-apps) — cnpg backup coverage, gated on CCR-2026-0004
|
||||
- Strand B (deferred): tamper-resistant governance, one-command rotation/lockdown,
|
||||
policy time-travel — capture separately if/when justified.
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
---
|
||||
id: WARDEN-WP-0027
|
||||
type: workplan
|
||||
title: "Tamper-resistant credential governance + mass rotation/lockdown (Strand B)"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: blocked
|
||||
flavor: implementation
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: medium
|
||||
planning_order: 27
|
||||
created: "2026-07-16"
|
||||
updated: "2026-10-03"
|
||||
state_hub_workstream_id: "21528e8d-a049-523d-9ae1-da7a27cb8bbf"
|
||||
---
|
||||
|
||||
# Tamper-resistant credential governance + mass rotation/lockdown (Strand B)
|
||||
|
||||
## Origin
|
||||
|
||||
Explicitly deferred from `WARDEN-WP-0026` (credential disclosure hygiene, Strand A).
|
||||
WP-0026 "Out of scope" carves out the heavyweight governance machinery and directs
|
||||
that it be "capture[d] separately if/when justified." This workplan is that capture.
|
||||
|
||||
Strand A makes accidental disclosure structurally hard and gives every lane
|
||||
**advisory** rotation guidance. Strand B is the **executable, tamper-resistant**
|
||||
layer: turning that advisory guidance into one-command action and hardening policy
|
||||
governance against silent drift or malicious change.
|
||||
|
||||
## Status: blocked on T02 (reviewed 2026-09-28)
|
||||
|
||||
Activated by the operator on 2026-08-22 after the second activation gate became
|
||||
concrete. `RAILIANCE-WP-0024-T03` now requires an approved recovery window,
|
||||
fresh encrypted Raft snapshot evidence, provider-console access, named abort
|
||||
authority, and the live **2-of-3 Shamir quorum** before a coordinated reboot.
|
||||
That is fleet policy requiring a designed break-glass path, not speculative
|
||||
heavyweight machinery.
|
||||
|
||||
Activation is deliberately narrow. No mass-disclosure incident triggers T01,
|
||||
and no fleet policy currently mandates T03's signed policy-manifest reconcile.
|
||||
Those tasks remain `cancel`; cancellation here continues to mean deferred, not
|
||||
abandoned. T02 alone was activated; it now waits on a fresh attended drill.
|
||||
|
||||
## Activation gate (promote to `ready` only when ≥1 holds)
|
||||
|
||||
- A real disclosure incident requires rotating **more than a couple** of secrets at
|
||||
once, making manual per-lane rotation (Strand A) too slow.
|
||||
- Fleet policy for OpenBao mandates tamper-evident policy governance or a designed
|
||||
break-glass path.
|
||||
- Audit/compliance requires provable "reconcile policy to a known-good commit."
|
||||
|
||||
## Goal
|
||||
|
||||
Make credential response **executable and trustworthy at fleet scale**: one command
|
||||
rotates or re-establishes a set of tainted secrets; policy changes are tamper-evident
|
||||
and reconcilable to a known-good state; a graded lockdown / break-glass path exists
|
||||
with an explicit trust-root.
|
||||
|
||||
## Scope boundary (unchanged from Strand A)
|
||||
|
||||
ops-warden still **custodies no secret values**. Strand B orchestrates the owner's
|
||||
tools (OpenBao, provider re-mint, railiance-platform credential broker) as the
|
||||
caller — it does not hold or vend secrets. Rotation execution runs the owner-native
|
||||
path; ops-warden sequences and verifies it.
|
||||
|
||||
## Task: Executable mass rotation driver
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0027-T01
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "b5691939-9d84-5115-9618-0f8839010d14"
|
||||
```
|
||||
|
||||
Turn Strand A's per-lane `rotation:` guidance (WP-0026 T06) into an executable
|
||||
driver: `warden rotate <id>` (single lane) and `warden rotate --tainted` (all lanes
|
||||
marked EXPOSED per WP-0026 T05). Each step runs the owner-native command
|
||||
(provider re-mint, `bao kv put`, re-encrypt+reupload for re-establish lanes) as the
|
||||
caller, verifies via capabilities (never reads the value), and clears the
|
||||
`exposed_at` taint on success. Dry-run first; idempotent; per-lane failure isolates.
|
||||
|
||||
**Done when:** a tainted set of lanes can be rotated/re-established with one command,
|
||||
each verified capabilities-safe, taint cleared only on success.
|
||||
|
||||
**Depends on:** WP-0026 T05 (taint convention), T06 (rotation registry).
|
||||
|
||||
## Task: Graded lockdown / break-glass with explicit trust-root
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0027-T02
|
||||
status: todo
|
||||
decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa
|
||||
priority: medium
|
||||
state_hub_task_id: "cae498ee-6307-5d32-9f1b-a471cfcc2536"
|
||||
```
|
||||
|
||||
2026-10-11: requalified after founder decision D3 (trust root, build-mode default) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md.
|
||||
|
||||
Design and document a graded lockdown: (a) soft — deny agent roles read on all
|
||||
high-risk lanes; (b) hard — seal + re-key with a pre-designed trust-root and quorum.
|
||||
Define the trust-root (who holds unseal shares, recovery keys), the break-glass
|
||||
invocation, and the re-entry path. **Design + runbook first**; any executable seal
|
||||
step is opt-in and attended.
|
||||
|
||||
**Done when:** a documented, rehearsed break-glass path exists with a named
|
||||
trust-root and quorum, and soft-lockdown is executable via capabilities-based
|
||||
policy toggles.
|
||||
|
||||
**Parked input — the warden-sign AppRole (2026-08-11).** secrets-engine holds a
|
||||
validated dry-run for a `warden-sign` AppRole (policy + role, `update` on
|
||||
`ssh/sign/{agt,adm,atm}-role` only). It was **parked** rather than withdrawn
|
||||
specifically because it is an input to this task: today the credential broker is the
|
||||
only *autonomous* path to a signing token, so if its issuer lapses, recovery is a
|
||||
founder OIDC act. Whether a second autonomous path should exist — and whether it is
|
||||
the AppRole or something this trust-root design supersedes — is a break-glass
|
||||
question, not a routing one. Resolve it here. Context and the counter-argument
|
||||
(AppRole is narrower in capability than placing the broker's issuer token on a remote
|
||||
host) are in `workplans/ADHOC-2026-08-11.md` T03 (ad-hoc **finished** 2026-08-15;
|
||||
question lives here now); secrets-engine was told to stop holding apply
|
||||
readiness until this task or the ops-bridge cutover fires (msg `863c7b57`).
|
||||
|
||||
**Rebaselined 2026-08-22.** The July description predates the authoritative
|
||||
OpenBao migration. The current barrier is a rotated **2-of-3**, not the
|
||||
aspirational 3-of-5 value still present in ops-warden's legacy posture
|
||||
descriptor. `RMASTER-WP-0020` records two attended restart/unseal cycles on
|
||||
2026-08-03 with shares supplied through hidden prompts, matching inventory,
|
||||
audit continuity, exact-path read, and sibling denial. That is valid rehearsal
|
||||
evidence for re-entry, but it is not misreported as a current production
|
||||
emergency-seal drill.
|
||||
|
||||
The soft half is also already live: `RAILIANCE-WP-0022` reports total concrete
|
||||
high-risk path coverage and a dedicated coding-agent AppRole proving deny-wins
|
||||
without reading a secret value. ops-warden consumes that owner control through
|
||||
`scripts/check_agent_read_boundary.py`; it does not take ownership of the live
|
||||
OpenBao policy.
|
||||
|
||||
The consumer contract and remaining acceptance gate are now documented in
|
||||
`docs/credential-governance-break-glass.md`. One attended production emergency
|
||||
seal/unseal drill remains. It must use railiance-platform's evidence template
|
||||
and validator, have snapshot/quorum/console/driver/abort receipts before the
|
||||
seal hold point, and be executed by the platform owner—not by a coding agent.
|
||||
|
||||
**Parked AppRole disposition:** do not unpark the standalone `warden-sign`
|
||||
AppRole for T02 break-glass. The normal broker remains autonomous; an issuer
|
||||
failure deliberately crosses into attended OIDC and, below that, the 2-of-3
|
||||
platform trust-root. A standing AppRole placed outside the broker would weaken
|
||||
that boundary and still would not recover a sealed OpenBao. A separately
|
||||
approved ops-bridge unattended-signing design may re-evaluate the narrow
|
||||
AppRole under its own workplan; that is service access, not recovery authority.
|
||||
|
||||
**Read-only readiness 2026-08-22.** The owner `node-reboot` preflight passed
|
||||
every automated check without observing a secret value: node/k3s, platform-pg
|
||||
and continuous archiving, a 16.37-hour successful backup, initialized/unsealed
|
||||
OpenBao with `shares=3` and `threshold=2`, ESO stores/projections, and the
|
||||
reviewed audit-core digest were healthy. `ready_for_live_execution` correctly
|
||||
remained false because no approved window, current encrypted off-host snapshot
|
||||
receipt, provider-console attestation, quorum attestation, owner-ack flag, or
|
||||
named abort operator was supplied.
|
||||
|
||||
That preflight also exposed a Warden safety defect: the ceremony request matched
|
||||
the generic `openbao-api-key` template and proposed paste-once provisioning.
|
||||
`openbao-shamir-recovery-ceremony` now distinguishes the owner-operated approval
|
||||
ceremony from secret retrieval. It is a non-value-bearing pointer and can never
|
||||
offer `--fetch`, `--exec`, `--out`, `--wrap`, or paste-once share transport.
|
||||
|
||||
**Scenario established 2026-08-22.** The operator delegated preparation to the
|
||||
agent and reserved their involvement for the final GO/NO-GO. The bounded,
|
||||
non-secret scenario is
|
||||
`docs/evidence/WARDEN-WP-0027-T02-drill-scenario-2026-08-22.md`: ops-warden
|
||||
coordinates and enforces the hold point; railiance-platform is the proposed
|
||||
OpenBao driver; railiance-infra is the proposed independent console/abort owner;
|
||||
and railiance-master is asked only for a metadata-only 2-of-3 availability
|
||||
attestation. All three owner receipts and a green fully parameterized preflight
|
||||
are required before the final operator question.
|
||||
|
||||
The railiance-infra role is scoped by the authoritative review contract
|
||||
`WARDEN-WP-0027-T02-DRILL-20260822-01-INFRA` in
|
||||
`interfaces/reviews/WARDEN-WP-0027-T02-DRILL-20260822-01-railiance-infra.json`.
|
||||
It binds the exact scenario artifact and expiry, requires explicit independent
|
||||
provider-console and distinct-abort attestations, permits metadata-only evidence,
|
||||
and states `authorizes_execution: false`.
|
||||
|
||||
**Preparation approved 2026-08-22.** Decision
|
||||
`9da57559-712a-4521-b46e-a4c69729f9d2` authorizes preparation only and narrows
|
||||
the possible live scope to one intentional OpenBao seal followed by the existing
|
||||
2-of-3 unseal ceremony. It excludes a host reboot, re-key, restore, policy
|
||||
change, PVC mutation, credential disclosure, and general workload restart.
|
||||
Railiance-infra satisfied its direct contract with receipt
|
||||
`01a02b4b-7295-7836-b288-f29407008524`. The revisioned, non-authorizing gate
|
||||
matrix is in
|
||||
`docs/evidence/WARDEN-WP-0027-T02-drill-preparation-checklist-2026-08-22.md`;
|
||||
platform snapshot/driver and master quorum contracts remain required before the
|
||||
fully parameterized read-only preflight.
|
||||
|
||||
**Live attempt terminal NO-GO 2026-08-23.** All owner receipts and the final
|
||||
read-only preflight became green, and the operator opened the exact bounded
|
||||
window with decision `449a697a-5303-4582-aa9e-b0bc8b35ab2d`. The platform
|
||||
driver stopped before seal when attended OIDC succeeded but the read-only agent
|
||||
home prevented token-helper persistence and the underlying client emitted the
|
||||
short-lived credential into captured output despite `-no-print`. The credential
|
||||
was immediately self-revoked. Independent metadata confirmed OpenBao remained
|
||||
initialized and unsealed with zero unseal progress; no seal, unseal, reboot,
|
||||
restore, policy, PVC, or workload mutation occurred. NO-GO decision
|
||||
`85724c0c-e70f-4e2f-a8c6-a9cb1ea6331b` supersedes and consumes the GO; the
|
||||
scenario and its receipts cannot be reused.
|
||||
|
||||
The direct remediation interface is `RAILIANCE-WP-0026-T01`. Ops-warden commit
|
||||
`0fae0904ce8d8694338dd53a8a79abec5fec788d` replaces the persistent login-only
|
||||
handoff with a contained login-plus-reviewed-command envelope. It proves a
|
||||
private writable helper before OIDC, captures login/child/revocation stdout and
|
||||
stderr, fails closed on any output or persistence defect, self-revokes, and
|
||||
removes the helper. No live OIDC was used for verification. The value-safe
|
||||
owner receipt is
|
||||
`docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json`; a future drill
|
||||
requires owner acceptance, fresh receipts, a new scenario id, and a new human
|
||||
decision.
|
||||
|
||||
**Containment review status 2026-08-23.** `railiance-infra` independently
|
||||
accepted the exact implementation revision at its commit `186b030` and State
|
||||
Hub message `7b2846dd-4b7c-4933-b61f-921e8ccf9ff2`, after rerunning the 42
|
||||
focused tests and lint. Direct platform review request
|
||||
`9a5f8973-0e74-4df2-8089-5a5bdc42295b` now carries the exact revision, receipt,
|
||||
test results, and infra acceptance. T02 remains `progress` until
|
||||
`railiance-platform` accepts or requests changes. No human GO is relevant while
|
||||
that owner gate is open; acceptance will permit preparation of a new scenario,
|
||||
not execution or reuse of the terminal one.
|
||||
|
||||
**Owner gate CLOSED — accepted 2026-08-23, found 2026-08-28.**
|
||||
`railiance-platform` accepted the exact revision `0fae0904`. Recorded in their
|
||||
`RPF-WP-0017-attended-login-output-containment.md` (`status: finished`), which
|
||||
also records railiance-infra's independent approval at `186b030` and marks all
|
||||
five acceptance criteria met. The receipt digest was verified here rather than
|
||||
taken on trust: `docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json` at
|
||||
ops-warden `bc1966da` hashes to
|
||||
`d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4`, matching
|
||||
their record exactly.
|
||||
|
||||
Note the identifier: the remediation interface recorded above as
|
||||
`RAILIANCE-WP-0026-T01` is `RPF-WP-0017-T01` in the owner's repo. Searching for
|
||||
the cited id finds an unrelated workplan, which is part of why this sat unnoticed.
|
||||
|
||||
**Their acceptance is source acceptance only and authorizes no live OIDC or
|
||||
drill** — their words, and the boundary holds. So T02's state changes but its
|
||||
`Done when` does not: what was blocked was *preparing a new scenario*, and that
|
||||
is now permitted. The terminal NO-GO scenario and its receipts remain unusable.
|
||||
|
||||
**Third instance of the same failure this session.** The acceptance existed for
|
||||
five days; no message reached ops-warden. Identically, `key-cape` accepted the
|
||||
WP-0033-T04 question on 2026-08-23 with no message, and nine unread messages
|
||||
were sitting on already-superseded threads. The `verified:` field added by
|
||||
WP-0033-T05 was built for exactly this and it works — what does not work is
|
||||
waiting for a counterparty to tell you. Re-checking a blocker means reading the
|
||||
owner's repository.
|
||||
|
||||
**Remaining to close T02:** one attended production emergency seal/unseal drill,
|
||||
requiring a new scenario id, fresh owner receipts from platform/infra/master, a
|
||||
fully parameterized green preflight, and a new human GO. It is executed by the
|
||||
platform owner, never by a coding agent. That is an operator decision, not an
|
||||
agent one, so T02 stays `progress` and the decision is surfaced rather than taken.
|
||||
|
||||
2026-10-03: human gate routed to hub decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa (D3: Trust root and secret custody: unseal/recovery holders, break-glass, and the deferred rotation of exposed material) by CUST-WP-0075; resolving that decision raises C-40 here.
|
||||
|
||||
## Task: Tamper-evident policy governance + reconcile
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0027-T03
|
||||
status: cancel
|
||||
priority: medium
|
||||
state_hub_task_id: "7dbedcdc-dd5a-551c-bff1-0702fea0a9cf"
|
||||
```
|
||||
|
||||
Policy-as-code for OpenBao policies/roles with tamper-evidence: a signed/hashed
|
||||
manifest of the intended policy set, drift **detection** against live OpenBao, and a
|
||||
reconcile-to-known-good-commit path. (Drift detection may land independently even if
|
||||
full reconcile stays gated.) Coordinate ownership with railiance-platform (OpenBao
|
||||
deployment) — ops-warden contributes the ops-access policy surface, not the cluster.
|
||||
|
||||
**Done when:** live OpenBao policy state is diffable against a signed known-good
|
||||
manifest, and an attended reconcile can restore it.
|
||||
|
||||
**Cross-repo:** railiance-platform (OpenBao cluster + policy custody).
|
||||
|
||||
## References
|
||||
|
||||
- `WARDEN-WP-0026` — Strand A (disclosure hygiene, advisory rotation) — prerequisite
|
||||
- `.claude/rules/credential-routing.md` — ops-warden custodies no secret values
|
||||
- `railiance-platform` — OpenBao cluster, policy custody, credential broker
|
||||
- `wiki/AccessRouting.md` — issue vs route vs assist boundary
|
||||
- `workplans/ADHOC-2026-08-11.md` T03 — parked warden-sign AppRole (ad-hoc finished
|
||||
2026-08-15); T02 resolves it as unsuitable for break-glass, while a separately
|
||||
approved ops-bridge unattended-signing design may still re-evaluate it
|
||||
cert_command cutover
|
||||
- `secrets-engine` `SECRETS-WP-0004` — the parked AppRole apply/handoff
|
||||
|
||||
### 2026-09-28 loose-end review
|
||||
|
||||
T02 now waits and the workplan is blocked. Source containment acceptance is
|
||||
already complete in railiance-platform's archived RPF-WP-0017; it is not a live
|
||||
drill receipt. The terminal August scenario remains consumed. Completion still
|
||||
requires a fresh platform-driven attended emergency seal/unseal scenario, fresh
|
||||
platform/infra/master receipts and a new founder GO. The cancelled T01/T03 stay
|
||||
cancelled. No ceremony, rotation or production mutation was performed.
|
||||
|
|
@ -0,0 +1,421 @@
|
|||
---
|
||||
id: WARDEN-WP-0028
|
||||
type: workplan
|
||||
title: "Tenant secret custody — NetKingdom pattern for client/tenant secrets"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: grok
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 28
|
||||
created: "2026-07-16"
|
||||
updated: "2026-07-17"
|
||||
state_hub_workstream_id: "6b66228a-199a-5b85-b5e2-a7afeaab903b"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0028 — Tenant secret custody (NetKingdom pattern)
|
||||
|
||||
## Origin
|
||||
|
||||
Founder establishing **binky-control** as the control-plane repo for a Coulomb
|
||||
client/tenant (Binky-Hedgehog GmbH). Immediate need: store **tenant-specific**
|
||||
secrets in OpenBao (e.g. company mailbox usernames/passwords for IMAP scan) and
|
||||
consume them safely via email-connect / agents **without** putting values in
|
||||
git, State Hub, chat, or workplans.
|
||||
|
||||
BINKY-WP-0003-T01 prepared a draft plan
|
||||
(`binky-control/integrations/company-email-openbao.md`) that targeted
|
||||
`secret/prod/binky/...` via secrets-engine. That draft is directionally right on
|
||||
*workflow*, but it does not match a production-ready custody layout on
|
||||
`bao.coulomb.social`. This workplan resolves the NetKingdom layout and makes
|
||||
**tenant** secrets first-class — **separate from** platform workload lanes
|
||||
(`platform/workloads/...`).
|
||||
|
||||
## Goal
|
||||
|
||||
Define and land a **repeatable, multi-tenant-safe** pattern for:
|
||||
|
||||
1. Where tenant secrets live in OpenBao (path + mount convention)
|
||||
2. Who owns policy, CCR, catalog, and front door
|
||||
3. How agents and workloads obtain values (sanctioned transports only)
|
||||
4. First concrete lane: **binky company email IMAP** (unblocks real-world event
|
||||
intake for binky-control)
|
||||
|
||||
## Architectural facts (as of 2026-07-16)
|
||||
|
||||
### Planes (ADR-0006)
|
||||
|
||||
| Plane | Role | Example |
|
||||
| --- | --- | --- |
|
||||
| Bootstrap | First trust / recovery | unseal, platform-root |
|
||||
| Platform control | Shared identity, secrets, authz | OpenBao, key-cape, flex-auth, railiance-platform |
|
||||
| Tenant | Scoped client/workload authority | coulomb products, **binky**, future clients |
|
||||
|
||||
**Binky is a tenant**, not platform-root. Tenant secrets must not require
|
||||
platform-admin for day-to-day read, and tenant operators must not gain
|
||||
platform-root grants.
|
||||
|
||||
### OpenBao mounts (live + planned)
|
||||
|
||||
| Mount | Type | Role |
|
||||
| --- | --- | --- |
|
||||
| **`platform/`** | KV v2 | **Platform control-plane** secrets: `platform/workloads/...` (fleet CCRs, ESO) and `platform/operators/...` — *not* client/tenant commercial secrets |
|
||||
| **`secret/`** | KV v2 | secrets-engine stage / pilot paths (`secret/coulomb/...`) — not the tenant home |
|
||||
| **`tenants/`** | KV v2 (**new**) | **Client/tenant commercial secrets** — explicit multi-tenant namespace |
|
||||
|
||||
Live under `platform/workloads/` today: `activity-core/`, `coulomb/`, `forgejo/`,
|
||||
`issue-core/`, `railiance/`, `reuse/`. Those stay where they are; we do **not**
|
||||
migrate them into `tenants/` in this workplan.
|
||||
|
||||
### Dual front-door systems (both real; don't invent a third)
|
||||
|
||||
| Layer | Owns | Entry |
|
||||
| --- | --- | --- |
|
||||
| **OpenBao** | Custody, ACL, audit | `bao` CLI / API |
|
||||
| **railiance-platform CCR** | Approved metadata apply (policy + OIDC role + evidence) | `credential-change-requests/CCR-*.yaml` |
|
||||
| **ops-warden catalog** | Routing + `warden access` proxy (no custody) | `registry/routing/catalog.yaml` |
|
||||
| **secrets-engine catalog** | Workflow: decision → plan → provision → exec delivery | `secrets-engine/catalog/*.yaml` |
|
||||
|
||||
**Binding rule (ops-warden):** never vend secret values; only route/proxy as the
|
||||
caller. **Binding rule (WP-0026):** capabilities-safe verify; agents on
|
||||
`risk: high` use `--out` / `--exec` / `--wrap` only.
|
||||
|
||||
### Why not bury tenants under `platform/workloads/`
|
||||
|
||||
Earlier draft of this workplan used `platform/workloads/<tenant>/...`. Founder
|
||||
prefer a **shallower, explicit** namespace. That is sound:
|
||||
|
||||
- **No conflict with Vault/OpenBao best practice.** Separate mounts (or
|
||||
top-level prefixes) for different security *domains* are common and good.
|
||||
`platform/workloads` is an *internal fleet convention* for platform services,
|
||||
not an industry mandate for every secret.
|
||||
- **Clearer mental model:** platform plane vs tenant plane (ADR-0006) maps to
|
||||
mount/prefix names operators can see at a glance.
|
||||
- **Isolation:** ACLs, list boundaries, and future audit queries stay simpler
|
||||
when tenant material is not mixed under the same path tree as forgejo/ESO
|
||||
lanes.
|
||||
|
||||
### Decision (2026-07-17) — use dedicated mount `tenants/`
|
||||
|
||||
```text
|
||||
mount: tenants # KV v2, enable once (platform-admin)
|
||||
logical path: <tenant_slug>/<workload>/<bundle>
|
||||
CLI: tenants/<tenant_slug>/<workload>/<bundle>
|
||||
API data path: tenants/data/<tenant_slug>/<workload>/<bundle>
|
||||
```
|
||||
|
||||
**Rejected alternatives (kept for archaeology only):**
|
||||
|
||||
| Option | Why not |
|
||||
| --- | --- |
|
||||
| `secret/prod/binky/...` | `secret/prod/` does not exist; stage model not ready as sole production path |
|
||||
| `platform/workloads/binky/...` | Too deep; conflates tenant clients with platform workloads |
|
||||
| `platform/tenants/binky/...` | Acceptable fallback if enabling a new mount is blocked; prefer full `tenants/` mount |
|
||||
|
||||
### Tooling debt to clear (not a reason to keep the deep path)
|
||||
|
||||
`railiance-platform/scripts/credential-change.py` currently hard-fails unless:
|
||||
|
||||
- `openbao.mount == "platform"`
|
||||
- `openbao.kv_path` starts with `platform/workloads/`
|
||||
|
||||
That guard must be **extended** to allow `mount: tenants` and
|
||||
`kv_path` under `tenants/` (T03). It is an implementation constraint, not a
|
||||
security reason to force the deep path.
|
||||
|
||||
## Recommended path convention (tenant secrets)
|
||||
|
||||
```text
|
||||
tenants/<tenant_slug>/<workload>/<bundle>
|
||||
```
|
||||
|
||||
| Segment | Rules | Binky email example |
|
||||
| --- | --- | --- |
|
||||
| `tenant_slug` | Stable kebab slug; company/client id | `binky` |
|
||||
| `workload` | Capability or system using the secret | `company-email` |
|
||||
| `bundle` | Single purpose unit (one CCR / one policy) | `imap` |
|
||||
|
||||
Full CLI path:
|
||||
|
||||
```text
|
||||
tenants/binky/company-email/imap
|
||||
```
|
||||
|
||||
Suggested fields (names only — never values in git):
|
||||
|
||||
| Field | Purpose |
|
||||
| --- | --- |
|
||||
| `IMAP_USERNAME` | mailbox login (often the address) |
|
||||
| `IMAP_PASSWORD` | app password / mailbox password |
|
||||
| `IMAP_HOST` | optional if not fixed in consumer config |
|
||||
| `IMAP_PORT` | optional (default 993 in config) |
|
||||
|
||||
Non-secret connection facts (provider host if stable) may live in
|
||||
`binky-control` config / email-connect yaml as **env names + host**, not
|
||||
passwords.
|
||||
|
||||
### Future multi-mailbox / multi-tenant
|
||||
|
||||
```text
|
||||
tenants/<tenant>/mailbox/<mailbox_id>
|
||||
# e.g. tenants/binky/mailbox/founder-primary
|
||||
# tenants/acme/mailbox/billing
|
||||
```
|
||||
|
||||
One CCR + one least-privilege policy **per bundle** (or per mailbox). Do not
|
||||
grant `tenants/binky/*` list/read to agents — exact-path policies only.
|
||||
|
||||
### Risk class
|
||||
|
||||
Mailbox credentials and similar client secrets are **`risk: high`** (WP-0026
|
||||
T04): agent identities get metadata/capabilities only; raw stream refused when
|
||||
`WARDEN_AGENT_ID` is set.
|
||||
|
||||
## Ownership split
|
||||
|
||||
| Concern | Owner repo | Artifact |
|
||||
| --- | --- | --- |
|
||||
| Tenant business need, IMAP host facts, scan config, queues | **binky-control** | `integrations/*`, mailmeta (metadata only), activity defs |
|
||||
| OpenBao path, policy HCL, OIDC role, CCR lifecycle | **railiance-platform** | `CCR-YYYY-NNNN-…yaml`, `openbao/policies/…` |
|
||||
| Routing front door + rotation guidance | **ops-warden** | catalog entry, playbook, `warden access` / `rotate-guide` |
|
||||
| Exec-time delivery workflow (optional same path) | **secrets-engine** | catalog entry pointing at `tenants/...` (same path; no second copy) |
|
||||
| Identity groups for tenant operators | **net-kingdom / key-cape** | group e.g. `tenant-binky-operators` (near-term may use `net-kingdom-admins` for founder-only) |
|
||||
| Mailbox scan consumer | **email-connect** | config with `username_env` / `password_env` only |
|
||||
|
||||
## Auth model (near-term vs target)
|
||||
|
||||
**Near-term (founder dogfood):** OIDC `netkingdom` role bound to
|
||||
`groups=net-kingdom-admins` (same pattern as backup/forgejo lanes). Acceptable
|
||||
while binky is founder-operated only.
|
||||
|
||||
**Target (real multi-tenant):**
|
||||
|
||||
- IAM group `tenant-binky-operators` (and later per-tenant groups)
|
||||
- OpenBao OIDC role `binky-company-email-imap-workload-kv-read` bound only to
|
||||
that group
|
||||
- flex-auth check `secret.read:binky-company-email` if pre-approval required
|
||||
- Agents **never** hold the workload-kv-read policy; use operator wrap / exec
|
||||
injection / AppRole for email-connect scanner only
|
||||
|
||||
## First worked lane (deliverable sketch)
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Catalog id | `binky-company-email-imap` |
|
||||
| CCR | `CCR-2026-0007` (next free) — title: Binky company email IMAP |
|
||||
| Mount | `tenants` |
|
||||
| KV path | `tenants/binky/company-email/imap` |
|
||||
| Policy | `workload-kv-read-binky-company-email-imap` |
|
||||
| OIDC role | `binky-company-email-imap-workload-kv-read` |
|
||||
| Consumer | email-connect `scan-mailbox` via env inject |
|
||||
| Front door | `warden access binky-company-email-imap --out FILE` or `--exec -- …` |
|
||||
| Provision | **Red lane, founder once** — value via `bao kv put … @file` or secrets-engine provision; never chat |
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Mass rotation / lockdown machinery (WARDEN-WP-0027 Strand B)
|
||||
- Sending mail / SMTP from company address (separate lane if needed)
|
||||
- Migrating all `secret/` mount lanes onto `platform/` (separate secrets-engine
|
||||
/ railiance work)
|
||||
- Full key-cape tenant group productization (may be a net-kingdom follow-on)
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Canon note: tenant secret path + ownership
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9982a884-7a50-593e-861e-cc8d2343a0ba"
|
||||
```
|
||||
|
||||
Done 2026-07-17: `wiki/playbooks/tenant-secret-onboarding.md` + CredentialRouting
|
||||
tenant paragraph; catalog-lane-promotion draft table updated.
|
||||
|
||||
Land a short ops-warden wiki page (and one paragraph in
|
||||
`wiki/CredentialRouting.md`) that freezes:
|
||||
|
||||
- mount **`tenants`** + path `tenants/<tenant>/<workload>/<bundle>`
|
||||
- ownership table (binky-control / railiance-platform / ops-warden / secrets-engine)
|
||||
- link to WP-0026 hygiene (capabilities verify, high-risk, taint)
|
||||
- **do not** put new client/tenant commercial secrets under
|
||||
`platform/workloads/` or invent `secret/prod/...` as the production home
|
||||
|
||||
**Done when:** wiki + CredentialRouting pointer exist; binky integration doc
|
||||
updated to match (or superseded with link).
|
||||
|
||||
### T02 — Align binky-control integration plan to production path
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d7d7ee9d-2ecf-5492-8a13-0b747d899456"
|
||||
```
|
||||
|
||||
Done 2026-07-17: `binky-control/integrations/company-email-openbao.md` rewritten
|
||||
to `tenants/binky/company-email/imap` + checklist (host confirm + Red provision
|
||||
still open).
|
||||
|
||||
**Cross-repo: binky-control.** Rewrite
|
||||
`integrations/company-email-openbao.md` to use
|
||||
`tenants/binky/company-email/imap`, CCR + ops-warden front door as primary,
|
||||
secrets-engine as optional exec wrapper on the same path. Confirm non-secret
|
||||
IMAP host/port with founder (Blue). Keep Red-lane value provision as the last
|
||||
step.
|
||||
|
||||
**Done when:** binky doc matches this workplan; checklist items re-opened for
|
||||
implementation (T01 in BINKY was "prepared only").
|
||||
|
||||
### T03 — Enable `tenants` mount + extend CCR tooling + policy/role
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "e0b675ef-9c08-5f89-8f13-ef4249ca2364"
|
||||
```
|
||||
|
||||
Done 2026-07-17: `tenants/` KV v2 mount live; CCR applier allowlist extended;
|
||||
CCR-2026-0007 + policy + OIDC role applied; lane-policy `read` / default
|
||||
`deny` / agent boundary on tenants path; `docs/workload-kv-access-lanes.md`
|
||||
tenant section.
|
||||
|
||||
**Cross-repo: railiance-platform (+ OpenBao admin once).**
|
||||
|
||||
1. **Enable KV v2 mount** `tenants/` on `bao.coulomb.social` (platform-admin /
|
||||
attended; record non-secret evidence). Versioning + max versions policy
|
||||
aligned with `platform` if practical.
|
||||
2. **Extend** `scripts/credential-change.py` allowlist: `mount: tenants` and
|
||||
`kv_path` under `tenants/` (keep existing `platform/workloads/` rules
|
||||
intact for fleet lanes). Update dry-run docs and tests.
|
||||
3. Author `CCR-2026-0007` (or next id) for the binky IMAP path; policy HCL on
|
||||
exact data/metadata paths under `tenants/…`; OIDC role (founder group
|
||||
near-term). Dry-run; founder approves; apply metadata only.
|
||||
4. Document fields without values; add a **tenant lanes** section to
|
||||
`docs/workload-kv-access-lanes.md` (or sibling doc).
|
||||
|
||||
**Done when:** mount exists; CCR tool accepts tenant paths; CCR approved +
|
||||
policy/role applied; capabilities-safe positive/negative evidence (no value
|
||||
reads for verify).
|
||||
|
||||
### T04 — ops-warden catalog + playbook + rotation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9405b13d-4045-519b-8e3f-79a891323397"
|
||||
```
|
||||
|
||||
Done 2026-07-17: catalog draft `binky-company-email-imap` (`risk: high`,
|
||||
rotation, path `tenants/binky/...`); playbooks
|
||||
`binky-company-email-imap.md` + onboarding. Promote to active after T05.
|
||||
|
||||
Add `binky-company-email-imap` to `registry/routing/catalog.yaml`:
|
||||
`status: draft` until verify, then promote; `risk: high`; `exec_capable: true`;
|
||||
concrete `fetch_command` for primary field; `rotation:` block (re-establish or
|
||||
rotate mailbox app-password). Playbook under `wiki/playbooks/`. Scorecard
|
||||
rotation coverage satisfied on promote.
|
||||
|
||||
**Done when:** `warden route show binky-company-email-imap --json` shows
|
||||
expected pointers; after T03+T05, `resolvable: true`.
|
||||
|
||||
### T05 — Founder provision (Red) + first scan evidence
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "f17bba95-bc53-5c2a-8b44-7df9e42b2341"
|
||||
```
|
||||
|
||||
Done 2026-07-17: Founder provisioned via OpenBao UI (KV version 2; not
|
||||
placeholder). Capabilities-safe verify pass; catalog + CCR promoted
|
||||
active/resolvable. Optional follow-up: first email-connect read-only scan into
|
||||
`binky-control/mailmeta/` (OperatingRhythm), not a custody blocker.
|
||||
|
||||
**Human-only value path.** Founder provisions IMAP username/password into
|
||||
OpenBao via approved tool (`bao kv put … @file` or secrets-engine provision).
|
||||
Agents never see the value. Run email-connect read-only scan with
|
||||
`warden access … --exec` or secrets-engine exec; store **metadata-only**
|
||||
evidence under `binky-control/mailmeta/`.
|
||||
|
||||
**Done when:** one successful read-only scan evidence note exists; lane
|
||||
promoted active/resolvable; CCR verification evidence complete.
|
||||
|
||||
### T06 — Generalize "tenant secret onboarding" playbook
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "76bd01a0-1d03-5ff9-8f59-a1b44763979d"
|
||||
```
|
||||
|
||||
Done 2026-07-17 with T01: `wiki/playbooks/tenant-secret-onboarding.md` +
|
||||
CredentialRouting link.
|
||||
|
||||
From the binky lane, write a reusable playbook:
|
||||
`wiki/playbooks/tenant-secret-onboarding.md` — steps for any new tenant:
|
||||
slug, CCR template fields, policy naming, catalog entry, agent boundary,
|
||||
rotation block, promotion checklist. Intended for the next Coulomb client
|
||||
without redesign.
|
||||
|
||||
**Done when:** playbook exists and is linked from CredentialRouting + first
|
||||
session notes for tenant repos.
|
||||
|
||||
### T07 — secrets-engine alignment decision (record only)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0028-T07
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "46c8f8a9-3bbe-568f-8a45-07b690874273"
|
||||
```
|
||||
|
||||
Done 2026-07-17: **Decision** — tenant production lanes use `mount: tenants`
|
||||
and the CCR path only; secrets-engine may wrap exec delivery against that same
|
||||
path later but must not store a second copy under `secret/`. Until stage roles
|
||||
gain an approved `tenants/` grant, production path is CCR + ops-warden +
|
||||
caller `bao`.
|
||||
|
||||
Record a short decision: secrets-engine catalog entries for **tenant**
|
||||
production lanes **must** use `mount: tenants` and the same path as the CCR
|
||||
(no second copy under `secret/`). Stage roles may need a later extension to
|
||||
touch `tenants/` under an approved plan — until then, ops-warden + CCR +
|
||||
`bao` as caller are the production path.
|
||||
|
||||
**Done when:** decision note in this workplan or `POST /decisions/` + wiki
|
||||
pointer; no dual-value storage for the IMAP password.
|
||||
|
||||
## Suggested implementation order
|
||||
|
||||
1. T01 canon (unblocks everyone)
|
||||
2. T02 binky doc alignment
|
||||
3. T03 mount + CCR tooling + CCR apply (metadata)
|
||||
4. T04 catalog draft
|
||||
5. T05 founder provision + verify + promote
|
||||
6. T06 generalize playbook
|
||||
7. T07 secrets-engine alignment (can parallel after T01)
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [ ] Documented path convention `tenants/<tenant>/…` used for ≥1 live lane (`binky`)
|
||||
- [ ] CCR applier accepts `tenants/` without weakening `platform/workloads/` rules
|
||||
- [ ] No secret values in any git/State Hub artifact
|
||||
- [ ] Lane is capabilities-verified and agent high-risk safe
|
||||
- [ ] email-connect can scan with env injection without printing password
|
||||
- [ ] Next tenant can copy the onboarding playbook without redesign
|
||||
|
||||
## References
|
||||
|
||||
- ADR-0006 recursive multi-tenant identity (`net-kingdom/docs/adr/…`)
|
||||
- `net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`
|
||||
- `railiance-platform/docs/workload-kv-access-lanes.md`
|
||||
- `railiance-platform/docs/credential-change-approval.md`
|
||||
- `binky-control/integrations/company-email-openbao.md` (draft to align)
|
||||
- WARDEN-WP-0026 disclosure hygiene (capabilities, high-risk, taint, rotation)
|
||||
- WARDEN-WP-0027 Strand B (out of scope here)
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
---
|
||||
id: WARDEN-WP-0029
|
||||
type: workplan
|
||||
title: "Policy front door: posture-aware access planning + founder interaction surface"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 29
|
||||
created: "2026-07-18"
|
||||
updated: "2026-07-18"
|
||||
state_hub_workstream_id: "bbb3d9ec-d88d-5088-b4c0-55bfba0a10cf"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0029 — Policy front door + founder interaction surface
|
||||
|
||||
## Origin
|
||||
|
||||
Founder directive 2026-07-18 (binky-control cutover prep): agents proposed
|
||||
raw credential mechanics to the founder ("attach the deploy key in the
|
||||
forgejo UI", "save the PAT to /tmp/...") although a catalogued lane
|
||||
(`forgejo-admin-api-token`, WARDEN-WP-0025) already covered the need — the
|
||||
installed CLI's catalog was stale, and nothing forced the ask-warden-first
|
||||
step. Directive: **ops-warden is the service to ask what can and needs to be
|
||||
done** per NetKingdom policy; the founder is bothered only when policy makes
|
||||
it absolutely necessary, and then preferably via a purpose-built interaction
|
||||
surface, not CLI/file handoffs. The organization is in **build phase** and
|
||||
ops-warden must know that posture. INTENT.md principles 7 and 8 (added with
|
||||
this workplan) capture the direction.
|
||||
|
||||
## Goal
|
||||
|
||||
1. `warden plan "<need>"` — a policy decision front door: given a need, answer
|
||||
*autonomous / founder-act-required / unroutable*, with the exact commands
|
||||
or the exact founder act, posture-stated.
|
||||
2. Declared **organization posture** (`build`) as a **third axis** beside env
|
||||
posture (dev/test/prod) and workload maturity (M0–M3).
|
||||
3. A **founder interaction surface**: local web page for the rare founder
|
||||
acts (approve, OIDC-login prompt, paste-once secret capture straight into
|
||||
OpenBao) — no values through CLI history or files.
|
||||
4. Catalog freshness + agent guidance so ask-warden-first is the enforced
|
||||
default.
|
||||
|
||||
## Design constraints (optimized 2026-07-18)
|
||||
|
||||
- **Compose, do not fork:** `warden plan` must call the routing catalog +
|
||||
`expand_handoff` / `resolvable`; it must not re-implement keyword matching
|
||||
or invent a second catalog.
|
||||
- **Org posture is a third axis:** do not overload env posture or maturity.
|
||||
- **Desk MVP is build-phase only:** localhost, OS-session trust, stdlib HTTP
|
||||
server (pattern: net-kingdom `security-bootstrap-console`). No core-hub /
|
||||
whynot dependency for v1.
|
||||
- **Reuse map (reuse.coulomb.social):** flex-auth (policy-evaluate), key-cape
|
||||
(OIDC act), net-kingdom bootstrap console (localhost desk shape),
|
||||
railiance-platform (OpenBao custody). Do not rebuild those owners.
|
||||
|
||||
## Delivery sequence
|
||||
|
||||
```text
|
||||
T02 (org posture) ─┐
|
||||
T05 (catalog freshness) ─┼─→ T01 (warden plan composes both)
|
||||
T04 (playbook sweep) ───┘ (parallel once plan shape known)
|
||||
T03 (desk) ← after T01 can emit founder_required with a typed act
|
||||
```
|
||||
|
||||
T05 is high priority: catalog staleness was the incident root cause.
|
||||
|
||||
## Tasks
|
||||
|
||||
### T02 — Declared organization posture (build phase)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0029-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6c213024-6601-5116-b52f-d6711dc0587d"
|
||||
```
|
||||
|
||||
Added `organization_posture: build` as axis C in
|
||||
`registry/policy/security-posture.yaml` (relaxations + graduation triggers).
|
||||
Surfaced in `warden policy list/show`, scorecard, and `warden plan` output.
|
||||
|
||||
### T05 — Catalog freshness + agent guidance
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0029-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "c82d8745-4af4-5b89-ab49-06d8a902e592"
|
||||
```
|
||||
|
||||
`Catalog.freshness()` reports source (repo/bundled/override), content hash,
|
||||
mtime, package version, stale entry count, and warnings for bundled fallback.
|
||||
Human `warden route list` prints catalog line; plan JSON embeds `catalog`.
|
||||
Scorecard check `catalog_freshness`. AGENTS.md + credential-routing rules
|
||||
require `warden plan` before founder credential steps.
|
||||
|
||||
### T01 — `warden plan` decision front door
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0029-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "34db38fa-cb99-5ced-9a12-85176a7f2b44"
|
||||
```
|
||||
|
||||
`warden plan "<need>" [--actor] [--domain] [--json]` composes catalog find +
|
||||
handoff + org posture + policy gate. Verdicts: `autonomous` /
|
||||
`founder_required` (`oidc_login` | `approve` | `paste_once_provision`) /
|
||||
`unroutable` (CCR stub). Metadata-only audit. Module: `src/warden/plan.py`.
|
||||
|
||||
### T04 — Retire file-drop patterns from playbooks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0029-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "717f57da-fbc4-5a4d-9f8c-c1c3fa75e0ee"
|
||||
```
|
||||
|
||||
`wiki/playbooks/forgejo-admin-api-token.md` rewritten: plan-first, sanctioned
|
||||
transports (`--exec`/`--out`/`--wrap`), desk paste-once for provision; `/tmp`
|
||||
file drops marked retired. Consumer follow-ups noted for railiance-platform
|
||||
and binky-control docs.
|
||||
|
||||
### T03 — Founder interaction surface (local web approval page)
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0029-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "47c781d2-768b-5777-b971-b5227fe41f5c"
|
||||
```
|
||||
|
||||
`warden desk` — loopback `ThreadingHTTPServer`, short-lived token URL, acts
|
||||
approve / oidc_login / paste_once_provision (bao kv put via stdin, dry-run
|
||||
supported). Metadata-only audit open/close. Module: `src/warden/desk.py`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] `warden plan "forgejo deploy key for binky-control"` → `autonomous` /
|
||||
`agent-harness-forgejo-deploy` with access commands
|
||||
- [x] Provision-style needs → `founder_required` with typed founder act
|
||||
- [x] Posture `build` in plan + policy + scorecard
|
||||
- [x] Desk approve flow (unit) with zero secrets in audit
|
||||
- [x] No in-repo playbook instructs founder file drop as steady state
|
||||
- [x] Catalog freshness on `warden route list` / plan JSON
|
||||
|
||||
## See also
|
||||
|
||||
- INTENT.md §7 (founder escalated, never tasked) and §8 (build-phase posture)
|
||||
- WARDEN-WP-0025 (forgejo admin token lane), WARDEN-WP-0026/0027 (disclosure
|
||||
hygiene, governance lockdown)
|
||||
- reuse.coulomb.social: `capability.authorization.policy-evaluate`,
|
||||
`capability.iam.key-cape`, `capability.security.iam-tooling-suite`
|
||||
- binky-control DEC-2026-003 (first consumer: cutover without founder
|
||||
mechanics)
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
---
|
||||
id: WARDEN-WP-0030
|
||||
type: workplan
|
||||
title: "Delegation register — make gap-covering interim, visible, and retirable"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: grok
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 30
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-15"
|
||||
state_hub_workstream_id: "da3367d5-890c-52c6-aa54-1bdd0f277342"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0030 — Delegation register
|
||||
|
||||
## Origin
|
||||
|
||||
Founder directive 2026-08-11: **ops-warden should work with, but never replace or
|
||||
duplicate, secrets-engine, tenant-engine, user-engine and other NetKingdom
|
||||
components.** It is acceptable for ops-warden to cover a gap where needed security
|
||||
functionality is not yet systematically provided — *provided* the gap is kept in
|
||||
mind, filled, and given proper governance, after which ops-warden delegates to the
|
||||
improved component.
|
||||
|
||||
The directive is already half-lived and nowhere written. Survey of
|
||||
`registry/routing/catalog.yaml` on 2026-08-11 (24 entries):
|
||||
|
||||
| Execution mode | Count | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `warden_executes: true` | 1 | ops-warden's own lane (`ssh-cert-host-access`) |
|
||||
| `exec_owner:` set | 2 | Delegated — route-primary, proxy-fallback |
|
||||
| `exec_capable` proxy, no `exec_owner` | 11 | **ops-warden is the de facto front door** |
|
||||
| route-only | 10 | Pointer, nothing to delegate |
|
||||
|
||||
The delegation primitive already exists and works: `exec_owner` / `exec_command` /
|
||||
`pointer_command` (`whynot-design-npm-publish` → secrets-engine, WP-0019;
|
||||
`ops-warden-warden-sign-token` → railiance-platform credential broker,
|
||||
RAILIANCE-WP-0005 T08). It is used by 2 of 24 lanes.
|
||||
|
||||
Nothing distinguishes the other eleven — "ops-warden proxies because that is the
|
||||
right end state" reads identically to "ops-warden proxies because no owner front
|
||||
door was ever built." Supporting evidence of the doctrine gap:
|
||||
|
||||
- `wiki/AccessRouting.md` does not mention secrets-engine at all and has no section
|
||||
on interim positions.
|
||||
- `wiki/playbooks/catalog-lane-promotion.md` gates draft→active on the lane
|
||||
*working*, never on whether ops-warden should be the one running it.
|
||||
|
||||
## Goal
|
||||
|
||||
Make every ops-warden execution position **explicitly interim or explicitly
|
||||
permanent**, with the intended owner and blocking condition recorded in the
|
||||
machine-readable layer — so gap-covering is a tracked, retirable state rather than
|
||||
silent ownership drift.
|
||||
|
||||
Success is not removing proxies. Success is that no proxy exists without an answer
|
||||
to *"who should own this front door, and what is missing?"*
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Removing or degrading any working lane. Proxies keep working until the owner's
|
||||
front door exists and is proven.
|
||||
- Building the missing front doors. That work belongs to secrets-engine,
|
||||
tenant-engine, user-engine, and railiance-platform — this workplan produces the
|
||||
register they need, not their implementations.
|
||||
- A second catalog or a parallel schema. `delegation:` extends the existing entry
|
||||
shape; `warden route gaps` composes the existing loader.
|
||||
|
||||
## Design constraints
|
||||
|
||||
- **Interim is the default.** A lane without a `delegation:` block is treated as
|
||||
`interim` with an unknown owner, not as settled. Absence must read as a question.
|
||||
- **Founder classifies, agent drafts.** Which of the eleven are legitimately
|
||||
permanent is an architecture judgement (`key-cape-oidc-login` plausibly is; the
|
||||
tenant/workload secret lanes plausibly are not). T02 lands a *drafted*
|
||||
classification for review; the founder's answer is authoritative.
|
||||
- **No restating owner procedure.** The register names the intended owner and the
|
||||
blocker; it does not describe how that owner will implement their front door.
|
||||
Same pointer-layer discipline as the rest of the catalog.
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Interim custodianship doctrine
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6f88876e-434c-5718-9c8d-ec6bf64ae4aa"
|
||||
```
|
||||
|
||||
Add a doctrine section to `wiki/AccessRouting.md` stating the boundary: the only
|
||||
lane ops-warden executes with its own authority is SSH issuance; every other
|
||||
execution position is interim, held because the owning component does not yet cover
|
||||
the need, and retired to that owner once it does. Name secrets-engine,
|
||||
tenant-engine, user-engine, railiance-platform and flex-auth as the delegation
|
||||
targets. Cross-link INTENT.md §9.
|
||||
|
||||
### T02 — `delegation:` metadata + backfill
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b02e8da6-57ca-5f9f-9405-9b0624498e3a"
|
||||
```
|
||||
|
||||
Extend the catalog entry schema with:
|
||||
|
||||
```yaml
|
||||
delegation:
|
||||
mode: native | interim | permanent # native = owner already fronts it
|
||||
intended_owner: <repo> # required unless mode: permanent
|
||||
blocked_on: <what is missing> # required when mode: interim
|
||||
reviewed: "YYYY-MM-DD"
|
||||
```
|
||||
|
||||
Backfill all 24 entries. `exec_owner` lanes become `mode: native`.
|
||||
`ssh-cert-host-access` becomes `mode: permanent` (ops-warden's own lane). The
|
||||
eleven undelegated proxies are classified per the founder review below — five
|
||||
`interim` now, six held pending secrets-engine's answer.
|
||||
|
||||
**Landed 2026-08-15.** Catalog is now 27 entries. All 27 carry `delegation:`.
|
||||
|
||||
- `permanent` (1): `ssh-cert-host-access`
|
||||
- `native` (10): both `exec_owner` lanes plus the route-only pointers
|
||||
- `interim` (16): the five founder-classified now; the six held pending
|
||||
secrets-engine (still unanswered as of 2026-08-15, msg `7d55d332`) recorded as
|
||||
`interim` / `intended_owner: secrets-engine` / `blocked_on` the generic-vs-per-lane
|
||||
question — **not** `permanent`; plus five new-since-survey lanes drafted the same
|
||||
way (`email-connect-transactional` same held question; two AppRoles;
|
||||
`coulomb-social-runtime-env`; draft `scaleway-bootstrap`)
|
||||
|
||||
The six are not guessed permanent. Interim is the default until secrets-engine
|
||||
answers. Reclassify to `permanent` only if they confirm `exec --catalog` stays
|
||||
per-lane.
|
||||
|
||||
### T03 — `warden route gaps` + conformance test
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "f5e0f5af-45d8-5c82-9de2-d640d7d0a1f7"
|
||||
```
|
||||
|
||||
`warden route gaps [--json]` lists interim lanes with intended owner, blocker, and
|
||||
age since review — the queryable register. Add a routing test asserting every
|
||||
`exec_capable` non-`warden_executes` entry declares `delegation`, so a new proxy
|
||||
cannot be added without answering the ownership question. Surface stale interim
|
||||
entries in the existing drift/stale review cadence.
|
||||
|
||||
### T04 — Promotion gate
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "b808a749-e1d7-5708-aabf-91732dd76abd"
|
||||
```
|
||||
|
||||
Update `wiki/playbooks/catalog-lane-promotion.md`: draft→active requires a
|
||||
`delegation` block. If `mode: interim`, the promotion note must state the intended
|
||||
owner and the retirement condition. Add the matching question to the lane-review
|
||||
checklist.
|
||||
|
||||
### T05 — Publish the register to the owners
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "b0188ec4-4860-57c8-8030-45904a132190"
|
||||
```
|
||||
|
||||
Once T02 is reviewed, send the interim register to secrets-engine, tenant-engine,
|
||||
user-engine, railiance-platform and net-kingdom as a coordination message: here is
|
||||
what ops-warden currently fronts on your behalf, here is what would let us step
|
||||
back. This is the artefact that converts a private ops-warden position into a
|
||||
fleet-visible capability gap.
|
||||
|
||||
**Landed 2026-08-15.** Register sent (no secret values):
|
||||
|
||||
| To | Message |
|
||||
| --- | --- |
|
||||
| secrets-engine | `9c1d753f` — 1 native + 7 interim pending generic-exec answer |
|
||||
| tenant-engine | `17c851b1` — 2 Binky tenant lanes |
|
||||
| user-engine | `38aeccd5` — confirm USER_ENGINE_PROXY_SECRET ownership |
|
||||
| railiance-platform | `e75793e3` — 1 native + 4 interim |
|
||||
| net-kingdom | `3fea09df` — object-storage-sts remains native/draft |
|
||||
| key-cape | `28ded56c` — rapp-qonto-keycape-client (founder-classified interim) |
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] `wiki/AccessRouting.md` states the interim-custodianship boundary and names
|
||||
the delegation targets
|
||||
- [x] All catalog entries carry `delegation`; `warden route gaps` returns the
|
||||
interim set with owner + blocker (27 entries; 15 active interim)
|
||||
- [x] Routing test fails when a proxy lane omits `delegation`
|
||||
- [x] Promotion playbook gates draft→active on the ownership question
|
||||
- [x] Founder has reviewed the interim/permanent classification of the eleven
|
||||
(2026-08-11); the six held lanes stay interim pending secrets-engine, not
|
||||
marked permanent
|
||||
- [x] Register delivered to the named owner repos (T05)
|
||||
|
||||
## Classification of the eleven (founder review, 2026-08-11)
|
||||
|
||||
### The test
|
||||
|
||||
An initial draft sorted by *subsystem* (tenant lanes → tenant-engine, workload lanes →
|
||||
secrets-engine). Inspecting the entries showed that is the wrong axis. Nine of the
|
||||
eleven share one `auth_method` — "caller's own OpenBao token" (operator OIDC via
|
||||
key-cape, or a `workload-kv-read-*` policy) — and one `fetch_command` shape,
|
||||
`bao kv get -field=X <path>`. No owner procedure is duplicated there. Contrast
|
||||
`whynot-design-npm-publish`, which needs npm config and token injection into a specific
|
||||
tool; that is a *procedure*, which is why WP-0019 handed it to secrets-engine.
|
||||
|
||||
**Test: owner-specific procedure or lifecycle → `interim`. Generic KV read →
|
||||
ops-warden's thin wrapper is arguably `permanent`.**
|
||||
|
||||
### Interim — classify now (5)
|
||||
|
||||
| Lane | `intended_owner` | `blocked_on` |
|
||||
| --- | --- | --- |
|
||||
| `rapp-qonto-keycape-client` | key-cape | `client_secret_basic` exchange is a key-cape protocol procedure, not a KV read; rotation already `automatable: true`, so key-cape could front it today |
|
||||
| `binky-company-email-imap` | tenant-engine | Custody at `tenants/binky/...` but rotation owner is `binky-control` — split lifecycle, no front door reconciling it |
|
||||
| `binky-qonto-api` | tenant-engine | Same split, same tenant |
|
||||
| `railiance-backup-offsite-lane` | railiance-platform | Rotation is `re-establish`, a multi-step procedure ops-warden only describes |
|
||||
| `agent-harness-forgejo-deploy` | railiance-platform / agent-harness | `re-establish` plus an alternative host-local key path; two ways in, neither owner-fronted |
|
||||
|
||||
### Held pending secrets-engine (6)
|
||||
|
||||
`openbao-api-key`, `key-cape-oidc-login`, `issue-core-ingestion-api-key`,
|
||||
`reuse-surface-hub-write-token`, `openrouter-llm-connect`, `forgejo-admin-api-token`.
|
||||
|
||||
These pass the test as `permanent` **only if `secrets-engine exec` stays per-lane and
|
||||
provisioned.** If secrets-engine intends `exec --catalog <id>` to generalize over
|
||||
arbitrary OpenBao lanes, the thin-wrapper argument collapses and all six become
|
||||
`interim` with `intended_owner: secrets-engine` — ops-warden would then be duplicating
|
||||
a front door the owner provides.
|
||||
|
||||
Asked directly (msg `7d55d332`, 2026-08-11): generic or per-lane; if generic, is it
|
||||
near-term enough to mark now; and are there lanes they would decline, so those can be
|
||||
marked permanent with the owner's position on record rather than ops-warden's inference.
|
||||
|
||||
Supporting detail: for `issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`
|
||||
and `openrouter-llm-connect`, **production never touches the proxy** — External Secrets
|
||||
syncs the value into the cluster and the proxy exists for operator verification and
|
||||
debugging. That weakens the case that they represent a missing front door at all.
|
||||
|
||||
**Do not backfill these six until the answer arrives.** A lane wrongly marked
|
||||
`permanent` bakes in exactly the ownership drift this register exists to catch.
|
||||
|
||||
### user-engine
|
||||
|
||||
No lane names **user-engine** as owner — it appears only as a consumer inside
|
||||
`coulomb-social-runtime-env` (`USER_ENGINE_PROXY_SECRET`, rotated at
|
||||
`user-engine/user-engine-runtime`). Whether user-engine should front that lane itself
|
||||
is worth confirming.
|
||||
|
||||
## See also
|
||||
|
||||
- INTENT.md §9 (cover gaps, never silently own them)
|
||||
- WARDEN-WP-0019 (route to secrets-engine — the pattern this generalizes)
|
||||
- WARDEN-WP-0028 (tenant secret custody pattern; front door still ops-warden's proxy)
|
||||
- `history/2026-08-11-delegation-surface-assessment.md`
|
||||
- `registry/routing/catalog.yaml`, `wiki/playbooks/catalog-lane-promotion.md`
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
---
|
||||
id: WARDEN-WP-0031
|
||||
type: workplan
|
||||
title: "Calling-side identity for flex-auth, so policy.enabled can flip"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0007
|
||||
related_workplans:
|
||||
- WARDEN-WP-0009
|
||||
created: "2026-08-19"
|
||||
updated: "2026-08-19"
|
||||
state_hub_workstream_id: "739bad25-2345-5f4f-aaa3-cc4cd8c71f6c"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0031 — Calling-side identity for flex-auth
|
||||
|
||||
flex-auth shipped `flex-auth-ops-warden` (FLEX-WP-0016 T01/T02): an
|
||||
independently rollable in-cluster pin carrying ops-warden's production registry
|
||||
and policy package, on digest `sha256:138aa347…`, at
|
||||
`flex-auth-ops-warden.flex-auth.svc.cluster.local:8080`.
|
||||
|
||||
It runs `callerAuth.mode: warn`, and it says why in its own logs:
|
||||
|
||||
```
|
||||
caller authentication warning: caller is not authenticated
|
||||
```
|
||||
|
||||
`src/warden/policy.py` posted `/v1/check` with **no `Authorization` header**.
|
||||
flex-auth authenticates the caller with a Kubernetes TokenReview and binds
|
||||
`resource.system: ops-warden` to `system:serviceaccount:ops-warden:ops-warden`;
|
||||
an unauthenticated caller can only be served in `warn`. So the pin cannot
|
||||
enforce, and per ADHOC-2026-08-17-T01 — `policy.enabled` must not flip anywhere
|
||||
while `/v1/check` still answers unauthenticated callers — `policy.enabled` stays
|
||||
false. The gap is ours, not flex-auth's, and this workplan closes it.
|
||||
|
||||
Warn is also not A2 evidence: a request that succeeds because failures are
|
||||
downgraded proves nothing about the enforcing path.
|
||||
|
||||
## Ownership
|
||||
|
||||
| Concern | Owner |
|
||||
| --- | --- |
|
||||
| The pin, its digest, `callerAuth.mode` | flex-auth |
|
||||
| Sending a caller identity on `/v1/check` | **ops-warden** (this workplan) |
|
||||
| Choosing the token source on a given host | ops-warden operator |
|
||||
| `policy.enabled: true` in `warden.yaml` | ops-warden operator |
|
||||
|
||||
## Design note — fail closed on identity too
|
||||
|
||||
When a caller token is configured but cannot be obtained, `check_sign_policy`
|
||||
raises under `fail_closed` rather than retrying unauthenticated. Falling back to
|
||||
an anonymous call is precisely the behaviour that keeps the pin in `warn`; a
|
||||
gate that silently degrades to the ungated path is not a gate (ADR-0004's choke
|
||||
point argument, applied to ops-warden as a caller).
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d3b7c701-bcdd-53f9-aa72-6f289bf5909b"
|
||||
```
|
||||
|
||||
**Caller identity on the outbound policy call.** `policy.caller_auth` in
|
||||
`warden.yaml` (`mode: none | file | env | command`, `token_path`, `token_env`,
|
||||
`command`, `audience`); `src/warden/caller_identity.py` resolves the token at
|
||||
call time and never caches, logs, or echoes it (ADR-0002); both
|
||||
`check_sign_policy` and `check_fetch_policy` attach `Authorization: Bearer …`.
|
||||
Whitespace-bearing and empty tokens are rejected before the call, because
|
||||
flex-auth rejects them outright.
|
||||
|
||||
Done 2026-08-19. `mode: none` remains the default, so behaviour is unchanged
|
||||
until an operator opts in. Tests in `tests/test_policy.py`.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b77b3c80-a168-564a-9b7f-3063aefc3c2e"
|
||||
```
|
||||
|
||||
**Readiness gate.** `scripts/check_policy_caller_identity.py` — read-only:
|
||||
config loads, mode is not `none`, a token is actually obtainable, and with
|
||||
`--url` a live `/v1/check` against a port-forward of the warn pin. Prints the
|
||||
token's length and a truncated SHA-256 fingerprint only, so its output is safe
|
||||
to paste into a handoff. Exit 0 ready / 1 not ready / 2 bad input. Distinguishes
|
||||
401 (token not accepted — audience or binding) from 403 (authenticated but not
|
||||
allowed to represent `system: ops-warden`).
|
||||
|
||||
Done 2026-08-19.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "4245155e-6c71-5425-b574-11f61e1d4461"
|
||||
```
|
||||
|
||||
**Docs.** `examples/warden.production.example.yaml` gains the `caller_auth`
|
||||
block with both realistic sources, and its `flex_auth_url` is corrected — the
|
||||
example pointed at `flex-auth.flex-auth.svc.cluster.local`, a Service that does
|
||||
not exist. `wiki/PolicyGatedSigning.md` gains the caller-identity section and
|
||||
the flip sequence.
|
||||
|
||||
Done 2026-08-19.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "f3834af7-2a08-51dd-bf31-8ce8550de699"
|
||||
```
|
||||
|
||||
**Pick the token source and prove it against the warn pin.** Operator work on
|
||||
the real host: `kubectl create token` (workstation) or a projected token
|
||||
(in-cluster PEP), then
|
||||
`python scripts/check_policy_caller_identity.py --url http://127.0.0.1:19090`
|
||||
against a port-forward. Expect `effect=allow` for `agt-state-hub-bridge` while
|
||||
the warn log stops printing `caller authentication warning` — the absence of
|
||||
that line, not the allow, is the evidence.
|
||||
|
||||
Done 2026-08-19. Source is `mode: command` — `kubectl create token ops-warden
|
||||
-n ops-warden --audience flex-auth --duration 10m` against the railiance01
|
||||
cluster (tunnel `k3s-api-railiance01`, local `16444`; `16443` was CoulombCore's
|
||||
k3s, a different cluster, which is why a `system:masters` cert 401s there —
|
||||
not a port collision, as first reported).
|
||||
`deploy/kubernetes/caller-identity.yaml` creates the Namespace and
|
||||
ServiceAccount the binding names — no RBAC, `automountServiceAccountToken:
|
||||
false`; it exists only to be TokenReviewed. Gate exits 0 live:
|
||||
`HTTP 200, effect=allow, decision:f3f7c88f9585582a`, and the pin's
|
||||
`caller authentication warning` count held at 4 across two authenticated runs.
|
||||
Evidence: `history/2026-08-19-flex-auth-caller-identity-evidence.md`.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T05
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "3f6dc609-89db-52eb-a6f9-d2fd271be821"
|
||||
```
|
||||
|
||||
**Sequence the flip.** Only after T04: tell flex-auth to set
|
||||
`callerAuth.mode: enforce` on `flex-auth-ops-warden` (their FLEX-WP-0016 T03),
|
||||
re-run the gate against the enforcing pin, and only then set
|
||||
`policy.enabled: true` with `fail_closed: true`. Flipping before enforce buys
|
||||
nothing; flipping before T04 401s every `warden sign`.
|
||||
|
||||
**Deferred 2026-08-19 under `ADR-0006`** — not blocked, decided against for now.
|
||||
|
||||
flex-auth did enforce (FLEX-WP-0016 T03, Helm rev 2): the pin runs
|
||||
`--caller-auth-mode enforce`, the gate exits 0 against it
|
||||
(`HTTP 200, effect=allow, decision:f3f7c88f9585582a`), and an anonymous
|
||||
`/v1/check` is 401. Everything needed to flip was in place.
|
||||
|
||||
It was not flipped. `policy.enabled` is a single repo-wide boolean, and with
|
||||
`fail_closed: true` it makes flex-auth a hard dependency of every `warden sign`
|
||||
— including the certs the ops-bridge tunnels depend on, one of which carries
|
||||
the policy call itself. Uniform enforcement across an estate being actively
|
||||
rebuilt would harden the access needed to perform the rebuild. Enforcement
|
||||
belongs to a zone, not to the repo; that is `ADR-0006`, and the model is
|
||||
`WARDEN-WP-0032`. This task resumes as WARDEN-WP-0032-T05.
|
||||
|
||||
Also shipped while proving the flip: the gate URL is now a managed ops-bridge
|
||||
tunnel `flex-auth-ops-warden-railiance01` (`-L 19090:10.43.1.165:8080`) instead
|
||||
of a hand-run `kubectl port-forward`.
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
---
|
||||
id: WARDEN-WP-0032
|
||||
type: workplan
|
||||
title: "Adopt security zones as a consumer — retire the global policy.enabled"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0031
|
||||
created: "2026-08-19"
|
||||
updated: "2026-08-22"
|
||||
state_hub_workstream_id: "38c6a5f3-fb0d-5230-be85-f9e3ffc850f6"
|
||||
quality_dod: DoD-Ok
|
||||
quality_dod_at: "2026-08-22"
|
||||
quality_dod_by: codex
|
||||
quality_dod_note: "All tasks are done; the global switches and trust-zone source are retired, workload references are explicit, the owner policy is total, declarations validate, live caller identity is re-proven, and the full suite passes."
|
||||
---
|
||||
|
||||
# WARDEN-WP-0032 — Adopt security zones as a consumer
|
||||
|
||||
`ADR-0006` defers `policy.enabled: true` until enforcement can be scoped to a
|
||||
zone. **The zone model itself is no longer ops-warden's work.** It moved to
|
||||
`zone-engine` as `ZONE-WP-0001` on 2026-08-19, where it belongs under `ADR-0005`
|
||||
— ops-warden implements one lane narrowly and routes the rest, and an
|
||||
estate-wide enforcement model is not a lane it should absorb.
|
||||
|
||||
What stays here is the consumer side: ops-warden was the repo whose deferred
|
||||
flip exposed the gap, it holds the controls the model must be able to express,
|
||||
and it is the first consumer the model has to satisfy.
|
||||
|
||||
## What ops-warden owes zone-engine
|
||||
|
||||
Inputs, not designs. `ZONE-WP-0001-T02` derives the model from the real estate,
|
||||
and most of that estate is ops-warden's:
|
||||
|
||||
- **27 routing catalog lanes** (`registry/routing/catalog.yaml`) with `risk`,
|
||||
`status`, and `delegation` already on each — the likeliest membership inputs.
|
||||
- **The actor inventory** (`adm` / `agt` / `atm`) and its TTL policy.
|
||||
- **The three posture axes already shipped** — environment and maturity
|
||||
(WP-0015), `organization_posture` (WP-0029) — including the honest answer to
|
||||
whether `organization_posture` should be folded into zones rather than run
|
||||
beside them.
|
||||
- **Three controls the model must be able to express**: the flex-auth pre-sign
|
||||
gate (`policy.enabled` + `fail_closed`), the agent read-boundary on
|
||||
`risk: high` lanes (`ADR-0004`), and the `warden plan` escalation verdicts.
|
||||
- **The compiled-registry path** (`scripts/build_flex_auth_registry.py`) — how
|
||||
membership can reach flex-auth without a lookup in a latency-critical decision
|
||||
path.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b03a5caa-0bb5-5cdd-bb99-32c694b0da29"
|
||||
```
|
||||
|
||||
**Hand the estate inputs to `ZONE-WP-0001-T02`.** Not a design proposal — the
|
||||
lanes, actors, axes, and controls above, with the exceptions ops-warden already
|
||||
knows do not fit cleanly (the interim delegation lanes from WP-0030 are the
|
||||
obvious candidates: a lane covered on someone else's behalf may not sit in the
|
||||
same zone as one ops-warden owns outright).
|
||||
|
||||
Include the `organization_posture` fold-in question honestly, including the case
|
||||
against keeping it.
|
||||
|
||||
**Answered by net-kingdom 2026-08-19** (canon owner of `tenancy-posture_v0.1`,
|
||||
answering `ZONE-WP-0001-T01`): **do not fold it in, and do not put it in a
|
||||
per-repo declaration under any key.** `organization_posture` is a fleet-wide,
|
||||
time-varying scalar describing the *estate*, not a property of a declaring
|
||||
service; a per-repo copy of a global goes stale in as many places as there are
|
||||
repos. It stays what WP-0029 made it — an input to stance selection that the
|
||||
zone model reads. Hand it over as an input, not as a candidate axis. Environment
|
||||
posture and `M0`–`M3` are per-workload and remain genuinely composable; those two
|
||||
are still open for `ZONE-WP-0001-T02`.
|
||||
|
||||
**Done 2026-08-21.** Every input listed above is now carried in `ZONE-WP-0001`,
|
||||
and `T02` there is `done` — which is the acceptance condition for this task, since
|
||||
what was owed was inputs rather than a design.
|
||||
|
||||
What actually reached them: the 27 graded lanes with `risk`/`status`/`delegation`
|
||||
(T05), the `M0`–`M3` ladder in `registry/policy/security-posture.yaml` — which
|
||||
`ZONE-WP-0001-T02` adopted as the maturity ladder rather than
|
||||
`.repo-classification.yaml` `category`, on the evidence that the latter grades a
|
||||
production SSH CA below a documentation repo — the three controls, and the
|
||||
compiled-registry path including the dormant `trust_zone` constant at
|
||||
`scripts/build_flex_auth_registry.py:77`.
|
||||
|
||||
Two inputs were handed over as corrections to ops-warden's own earlier claims,
|
||||
which is the part worth recording. `organization_posture` was offered as a
|
||||
candidate axis and net-kingdom refused it (above); and ops-warden asserted no
|
||||
registry carried a workload join key, which was true of its own catalog and false
|
||||
of the estate — `rapp-*/declarations/rapp.yaml` carries eight
|
||||
`workload_identity` declarations. `scripts/report_workload_join.py` then measured
|
||||
the join rather than asserting it: **1 of 27 lanes** matches a declared workload.
|
||||
That number is `ZONE-WP-0001-T03`'s critical path, and it came out of correcting
|
||||
this repo's own input rather than out of supplying a new one.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b3f41c85-a293-58ad-ac27-9f8110c51266"
|
||||
```
|
||||
|
||||
**Replace `policy.enabled` with a zone-aware control.** Waits on
|
||||
`ZONE-WP-0001-T03` and `T05`. Reads the zone of the actor being signed for and
|
||||
that zone's failure mode. Ship deprecation and migration in the same change —
|
||||
leaving both is the second-source-of-truth failure `ADR-0001` exists to prevent.
|
||||
|
||||
Re-run `scripts/check_policy_caller_identity.py` before enabling anything: the
|
||||
WP-0031 evidence (`decision:f3f7c88f9585582a`, 2026-08-19) will be stale, and
|
||||
re-establishing it is cheap precisely so this is a re-check rather than a re-do.
|
||||
|
||||
This closes `WARDEN-WP-0031-T05`.
|
||||
|
||||
**Amended by flex-auth 2026-08-19, reviewing `ZONE-WP-0001` as the PDP.** Two
|
||||
constraints that change what this task can build, both argued in full at
|
||||
`ZONE-WP-0001-T03` and `T04`:
|
||||
|
||||
1. **The zone-aware control splits across the boundary, it does not move.**
|
||||
flex-auth will read compiled zone *membership* from the registry and apply the
|
||||
per-zone *stance* from its policy package, returning an effect plus an
|
||||
advisory annotation. What stays on the ops-warden side is the axis flex-auth
|
||||
structurally cannot carry: **`fail_closed` is not expressible by a PDP.**
|
||||
Fail-open describes what `warden sign` does when flex-auth is *unreachable* —
|
||||
no decision is rendered, so no compiled data and no policy rule can reach it.
|
||||
So the replacement for `policy.enabled` is not one zone-derived boolean
|
||||
either; it is (a) stance, which arrives *in the decision*, and (b) failure
|
||||
mode, which stays a local ops-warden setting declared per zone. Plan for two,
|
||||
or T02 will be built expecting flex-auth to answer something it cannot.
|
||||
|
||||
2. **The membership compiler is ops-warden's to change, and it has a name
|
||||
collision to resolve first.** `scripts/build_flex_auth_registry.py:77` already
|
||||
emits `"trust_zone": "platform"` as a hardcoded constant on every
|
||||
ssh-certificate resource. It is a first-class field on flex-auth's `Resource`,
|
||||
it is surfaced into rego input, and **no policy package reads it**. Before
|
||||
compiling zone membership, either retire that constant or deliberately
|
||||
repurpose it — do not add `security_zone` beside a dormant `trust_zone` and
|
||||
leave the next reader to guess which is real. That is the `ADR-0001`
|
||||
second-source-of-truth failure in miniature, inside a generated artifact.
|
||||
|
||||
Good news for T03's cost: **no flex-auth registry schema change is required.**
|
||||
`metadata`, `labels` and `attributes` already flatten into the rego input, so the
|
||||
compiler can emit membership today.
|
||||
|
||||
**Consumer implementation landed in the working tree 2026-08-22.** The config
|
||||
loader rejects the retired `policy.enabled` and global `policy.fail_closed`
|
||||
keys. `scripts/build_flex_auth_registry.py` now emits the normative
|
||||
`workload_id`, `security_zone`, `security_zone_declared`,
|
||||
`security_zone_admission`, `security_zone_reason`, and
|
||||
`security_zone_revision` attributes; the dormant `trust_zone` field is gone.
|
||||
The PEP reads compiled resource membership and applies its local per-zone
|
||||
failure mode. Sign and audit records retain the zone, selected failure mode,
|
||||
outcome, and decision id.
|
||||
|
||||
The legacy `--no-policy` proxy switch remains only as a rejected compatibility
|
||||
flag. It can no longer bypass the gate: unresolved credential targets take the
|
||||
explicit `unknown` profile and its configured failure mode.
|
||||
|
||||
**Done 2026-08-22.** flex-auth package v2 (commit `e521e7b`) supplies total
|
||||
stance over every v0.1 zone plus `unknown`, preserves native enforcement for
|
||||
`not-applicable`, and returns `audit_only` for advisory decisions. The required
|
||||
live caller check passed through the existing tunnel with command-mode caller
|
||||
identity and decision `decision:f3f7c88f9585582a`. The operator config was then
|
||||
migrated from the two rejected global keys to `zone_registry_path`, and the
|
||||
same live check passed against that real config. Full repo tests pass and
|
||||
sign/audit evidence records zone, failure mode, outcome, and decision id.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d04a737b-ecdf-5747-ba25-20dadd99d3bc"
|
||||
```
|
||||
|
||||
**Declare ops-warden's zones** in the format `ZONE-WP-0001-T05` settles,
|
||||
alongside the existing posture descriptors.
|
||||
|
||||
**Amended by net-kingdom 2026-08-19 — the carrier file is already settled, only
|
||||
its contents are open.** Canon Decision 5.6 (`tenancy-posture_v0.1` draft-9)
|
||||
rules that zone membership is declared in **`tenancy.yaml` under a reserved
|
||||
top-level `zones:` key**, sibling to `tenancy:` and `provider:` and never inside
|
||||
`tenancy.current`. §5.4 makes that file the repo's single posture declaration
|
||||
surface, and a second root file would be the second-source-of-truth failure
|
||||
`ADR-0001` exists to prevent — in ops-warden's own idiom. The key is reserved and
|
||||
deliberately unconstrained in `net-kingdom/canon/schemas/tenancy-posture_v0.1.schema.json`,
|
||||
so a combined declaration validates today.
|
||||
|
||||
Note the consequence for this repo: **ops-warden does not currently have a
|
||||
`tenancy.yaml`.** Declaring zones means writing one, which means declaring the
|
||||
six-axis posture vector too. That is a real and probably overdue cost, not an
|
||||
accident of this amendment — canon would rather ops-warden declare both
|
||||
accurately than declare a zone with no posture beside it.
|
||||
|
||||
Note also *why* stance is not something this declaration may set: canon Decision
|
||||
5.6 rules that a declarer must not be the party that sets the stance, or an
|
||||
accurately declared `exempt` becomes conformant *and* exempt. ops-warden declares
|
||||
which zone a lane or actor is in. The stance of the pre-sign gate in that zone is
|
||||
flex-auth's policy package; the failure mode is ops-warden's own setting, per
|
||||
flex-auth's T03 amendment. Per flex-auth's T05 amendment, this
|
||||
declaration must also say whether a zone rides the **actor** (a flex-auth
|
||||
subject) or the **lane** (a flex-auth per-actor resource) — in the compiled
|
||||
registry an actor is both, and the compiler needs to be told which record
|
||||
carries membership. Carry the conformance rule:
|
||||
*accuracy, not altitude*. Declaring a stricter zone than can be evidenced is the
|
||||
failure mode that looks like progress.
|
||||
|
||||
**Done 2026-08-22.** `tenancy.yaml` now declares ops-warden as an independently
|
||||
governed operational execution unit with its Kubernetes service-account
|
||||
binding, and admits it to `z1-operational` at `M1`, `medium`, `internal`.
|
||||
`docs/evidence/security-zone-admission-2026-08-22.md` records why this is the
|
||||
highest evidenced admission rather than an aspirational `M2`. The declaration
|
||||
passes net-kingdom's current `tenancy-posture_v0.1` validator.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "c7879127-3dba-55c0-853c-a10775736873"
|
||||
```
|
||||
|
||||
**Amend `ADR-0006`.** Once zones exist and enforcement scoping is owned by
|
||||
`zone-engine`, ADR-0006 must say that ops-warden *follows* the model rather than
|
||||
owning it — a superseding record, never an in-place edit. Update `SCOPE.md`,
|
||||
`wiki/WorkloadSecurityPosture.md`, and `wiki/PolicyGatedSigning.md` with it.
|
||||
|
||||
**Done 2026-08-22.** ADR-0006 is marked superseded without rewriting its
|
||||
decision. ADR-0009 accepts `security-zones_v0.1` as a consumer, records the
|
||||
PDP/PEP split and unknown handling, and is indexed as its successor. `SCOPE.md`,
|
||||
`wiki/WorkloadSecurityPosture.md`, `wiki/PolicyGatedSigning.md`, configuration
|
||||
guidance, access guidance, and affected playbooks now describe the zone-aware
|
||||
control and do not instruct operators to use a global bypass.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1d968627-83f4-59cd-84ca-0f9f35e435ff"
|
||||
```
|
||||
|
||||
**Grade the five exposed lanes now — do not wait for the model.**
|
||||
`RISK-F-0003`: `is_high_risk` is `risk == "high"` and `risk` is optional, so the
|
||||
14 ungraded lanes never reach the agent read-boundary. Five are `exec_capable`
|
||||
and can therefore stream a value to an agent session: `openbao-api-key`,
|
||||
`whynot-design-npm-publish`, `key-cape-oidc-login`,
|
||||
`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`.
|
||||
|
||||
The durable answer is a maturity-derived default (`ZONE-WP-0001-T03`), and it is
|
||||
the right answer. It is also months away, and this is a live control gap in a
|
||||
shipped ADR. Grade these five explicitly, then the remaining nine.
|
||||
|
||||
Grading is judgement, not backfill — each lane's grade should be justified in the
|
||||
entry, and the operator should sanction the high/standard calls rather than
|
||||
having them inferred. Verify separately whether OpenBao's
|
||||
`agent-high-risk-boundary` policy covers these paths; `RISK-F-0003` deliberately
|
||||
does not assume it does, because those paths were graded by the same omission.
|
||||
|
||||
**Done 2026-08-19, operator-sanctioned.** All 14 ungraded lanes graded on merit,
|
||||
each with its justification in the entry: 17 `high`, 10 `standard`, **0
|
||||
ungraded**. `warden access <lane> --fetch` with `WARDEN_AGENT_ID` set now exits 7
|
||||
on lanes that were silently outside the control an hour earlier.
|
||||
|
||||
Graded on merit, not defensively. A first pass marked
|
||||
`issue-core-ingestion-api-key` and `reuse-surface-hub-write-token` `high`; the
|
||||
existing test `test_high_risk_lanes_classified` asserted the opposite and was
|
||||
right — ordinary internal workload secrets are `standard`. Both were regraded
|
||||
down. `high` means disclosure into a logged context is damaging beyond what
|
||||
rotation recovers: provider keys with spend, admin PATs, tenant commercial data,
|
||||
supply-chain publish rights. `inter-hub-bootstrap-ssh` is `high` **conservatively**
|
||||
— ops-warden could not establish that no key material moves in the envelope, and
|
||||
that is recorded in the entry so it is regraded with evidence rather than assumed
|
||||
down.
|
||||
|
||||
The rule is now `ADR-0007`: build-stage permissiveness stops at credential
|
||||
disclosure. Not yet verified: whether OpenBao's `agent-high-risk-boundary`
|
||||
policy covers these paths (T06).
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "4294084c-bf3f-5aa6-b84d-5173121882ff"
|
||||
```
|
||||
|
||||
**Make absence impossible, once the model says what absence means.** Waits on
|
||||
`ZONE-WP-0001-T03`. Either invert the default (absent `risk` resolves through the
|
||||
lane owner's maturity, per the operator direction) or require `risk` at catalog
|
||||
load and in CI. Whichever lands, the failure mode to kill is the current one:
|
||||
adding a lane without a grade silently places it outside a control, with nothing
|
||||
at load or in CI noticing.
|
||||
|
||||
Feed back to `ZONE-WP-0001-T03` whether ops-warden can supply the join it needs —
|
||||
today no lane references a workload or an environment, so the `M0`–`M3` ladder
|
||||
has nothing to attach to from this side.
|
||||
|
||||
**Enforcement half done 2026-08-20.** It did not need the zone model: `ADR-0007`
|
||||
already decided absence is a defect, which is enough to make the code fail safe
|
||||
and to gate CI.
|
||||
|
||||
The real mechanism turned out to be sharper than `RISK-F-0003` described.
|
||||
`is_high_risk` was `risk == "high"`, but `risk` was **not** absent at the model
|
||||
layer — `RouteEntry.risk` carried a dataclass default of `"standard"`. So an
|
||||
omitted grade was not unhandled; it was actively resolved to the permissive
|
||||
value. Fail-open by construction, which is why nothing warned.
|
||||
|
||||
Now: the default is `"ungraded"`, and `is_high_risk` returns true for anything
|
||||
not in an explicit low-risk vocabulary (`standard` / `low` / `accepted`). An
|
||||
omitted grade **and** a grade from a newer catalog both resolve to high, so the
|
||||
boundary fails safe in both directions. `is_graded` exposes the distinction, and
|
||||
`test_every_repo_catalog_lane_is_explicitly_graded` is the CI gate that stops an
|
||||
ungraded lane being committed. Four regression tests cover it.
|
||||
|
||||
`accepted` is in the low-risk vocabulary deliberately, ready for the
|
||||
maturity-derived default: an experimental-context lane may be explicitly
|
||||
accepted, which is a graded decision rather than an omission.
|
||||
|
||||
**Second layer checked 2026-08-20 — it does not cover them.** The OpenBao side
|
||||
was compared statically (policy file vs catalog): `agent-high-risk-boundary`
|
||||
denies 5 data paths covering **6** of the **17** high-risk lanes. Eight
|
||||
high-risk lanes with concrete KV paths are not denied — and **four of those were
|
||||
already graded `high` before the regrade**, so the divergence is pre-existing
|
||||
rather than something the grading introduced. It had simply never been
|
||||
comparable before.
|
||||
|
||||
This matters more than the ops-warden half: `warden access` exits 7 for all 17,
|
||||
but that only protects the ops-warden path. The OpenBao policy is what protects a
|
||||
direct `bao kv get`, which is the actual 2026-07-16 vector.
|
||||
|
||||
Routed to `risk-nexus` as **`RISK-F-0004`**, `fix_owner: railiance-platform` —
|
||||
the policy is theirs, and ops-warden does not amend another repo's control.
|
||||
|
||||
**Live confirmation done 2026-08-21 — and the blocker was not real.** The
|
||||
token was not expired: `bao token lookup` returned a valid `platform-admin`
|
||||
token from an OIDC login, and `bao policy read agent-high-risk-boundary`
|
||||
succeeded. No `bao login` was needed. Worth recording as a small instance of the
|
||||
lesson `.claude/rules/finding-routing.md` already states — *re-read a blocker
|
||||
before trusting it*. This one was a stale claim about the world, carried for a
|
||||
day in both this workplan and `RISK-F-0009`.
|
||||
|
||||
The verification script also did not exist. It was described here as "ready",
|
||||
and nothing was committed. `scripts/check_agent_read_boundary.py` now exists,
|
||||
with tests, and is the invariant `RISK-F-0009` asked for rather than a one-off
|
||||
audit: exit 1 when any high-risk lane has no corresponding deny. It prefers the
|
||||
deployed policy and falls back to the file only with a loud warning, because
|
||||
deployment drift is the thing it exists to catch. Capabilities-only by
|
||||
construction — it reads the policy document and lane metadata, never a secret
|
||||
value, and never mints a token.
|
||||
|
||||
Three results, one against ourselves:
|
||||
|
||||
1. **Coverage confirmed at 6 of 17** against the live policy — the headline was
|
||||
right and is no longer inferred from a checkout.
|
||||
2. **Six lanes uncovered, not eight.** `RISK-F-0009` counted `openbao-api-key`
|
||||
(a `<domain>/<workload>/<bundle>` pattern) and `ops-warden-warden-sign-token`
|
||||
(a broker grant, not KV) among the concrete uncovered paths, while its own
|
||||
prose said the first was a pattern. Neither can be expressed as a deny.
|
||||
Corrected: 6 covered, 6 uncovered, 5 with no address.
|
||||
3. **The deployed policy has drifted from the file.** The file denies
|
||||
`platform/workloads/core-hub/runtime`; the server does not. No ops-warden
|
||||
lane maps there, so our numbers are unchanged — it matters as evidence, since
|
||||
`RISK-F-0009` named exactly this divergence as its unconfirmed risk.
|
||||
|
||||
Still not established, and not ops-warden's to establish: whether any agent
|
||||
token carries `agent-high-risk-boundary`, and whether any carries it together
|
||||
with a `workload-kv-read-*` policy. Confirming that means minting or inspecting
|
||||
tokens — a write against railiance-platform's OpenBao. Exposure stays theoretical
|
||||
to the same degree as before.
|
||||
|
||||
**Platform half closed 2026-08-22.** `RAILIANCE-WP-0022` consumed the generated
|
||||
high-risk path input and deployed the completed deny policy. The platform-owned
|
||||
invariants report **19 high-risk lanes, 14 concrete entries, 0 uncovered**. A
|
||||
dedicated `coding-agent-railiance-platform` AppRole then proved deny-wins with
|
||||
exactly `agent-high-risk-boundary` plus one workload read policy: data access was
|
||||
denied while metadata remained readable; its single-use test identity was
|
||||
self-revoked and no test tokens remained. Decision `f0955252` records the
|
||||
operational identity. No KV value was read.
|
||||
|
||||
The local invariant agrees against the platform policy file: 19 high-risk lanes,
|
||||
14 concrete entries covered, 5 without a concrete address, 0 uncovered. This
|
||||
session could not independently read the deployed policy, so live-state evidence
|
||||
is the platform-owned readback above rather than a claim inferred from the local
|
||||
file.
|
||||
|
||||
**Done 2026-08-22.** The settled model makes the two layers complementary:
|
||||
catalog CI continues to require an explicit `risk` field so omission cannot
|
||||
silently weaken the agent boundary, while `RouteEntry.risk_for_zone` implements
|
||||
the normative maturity-derived fallback for consumers evaluating unresolved or
|
||||
future inputs (`z0` + satisfied + synthetic-only → `standard`; satisfied `z3`
|
||||
→ `critical`; everything else → `high`). An explicit catalog grade always wins.
|
||||
The platform deny policy and its live proof above close the direct-OpenBao half.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0032-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "6b4bbbed-2864-5fe9-82be-22ff9543f6f4"
|
||||
```
|
||||
|
||||
**Adopt Repo Manager's workload-reference owner interface.** Accepted with one
|
||||
documented amendment against repo-manager revision `890f3b0`: managed
|
||||
deployables use the exact `(rapp_id, workload_identity.name)` pair and optional
|
||||
deployable name; an independently governed operational execution unit may use
|
||||
an exact local `tenancy.yaml` declaration. Native actions, actors, grants,
|
||||
patterns, and non-workload resources are explicitly `not-applicable`; unresolved
|
||||
workload-applicable references remain `unknown`. No path, owner name, or
|
||||
repository-name inference is allowed.
|
||||
|
||||
Every one of the 27 catalog lanes now carries an explicit `workload_ref`: 3
|
||||
resolved (2 exact managed RAPP references and ops-warden's direct operational
|
||||
declaration), 17 unknown with reasons, and 7 not-applicable with reasons.
|
||||
`scripts/report_workload_join.py` resolves only those explicit references,
|
||||
Repo Manager validates the interface and resolves both managed tuples exactly,
|
||||
and regression tests reject malformed or inferred joins. This incorporates
|
||||
net-kingdom's draft-12 correction received 2026-08-22: local tenancy declaration
|
||||
is not an escape hatch for a managed running deployable.
|
||||
|
||||
## Related
|
||||
|
||||
- `zone-engine` `ZONE-WP-0001` — the model, and where this work is led from
|
||||
- `ADR-0006` — enforcement is zone-scoped, never a global flag
|
||||
- `WARDEN-WP-0031` — the deferred flip and its readiness evidence
|
||||
- `net-kingdom` `tenancy-posture_v0.1` draft-9 Decisions 5.6, 8.4.1, 8.4.2 — canon's
|
||||
answer to `ZONE-WP-0001-T01`; enforcement stance is a sibling standard, not a
|
||||
seventh axis, and the declaration surface is `tenancy.yaml`
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
---
|
||||
id: WARDEN-WP-0033
|
||||
type: workplan
|
||||
title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0030
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-28"
|
||||
state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0033 — Native lane handoff
|
||||
|
||||
On 2026-08-20 `secrets-engine` accepted five of ops-warden's seven interim
|
||||
proxy lanes for catalog admission (`SECRETS-WP-0006`, decision
|
||||
`ae676382-1826-4e04-aa4e-bb77990c7a0d`), rejected two with reasons ops-warden
|
||||
agrees with, drafted the five entries itself rather than waiting for the offered
|
||||
contribution, and asked for a line-by-line review of the non-secret metadata.
|
||||
|
||||
In the same hour `railiance-platform` closed the `RISK-F-0009` coverage gap and
|
||||
asked ops-warden for two things back.
|
||||
|
||||
This workplan is the response to both, plus the defect the review turned up in
|
||||
ops-warden's own grading model — which is the most consequential item here and
|
||||
would not have been found without the second pair of eyes.
|
||||
|
||||
## Why a workplan and not an adhoc
|
||||
|
||||
Four counterparties are waiting, one deliverable is a **cross-repo interface**
|
||||
another repo will consume on a schedule, and the review carries approval
|
||||
semantics — `secrets-engine` holds interim proxy ownership open until each lane
|
||||
has approved native verification. The convention reserves adhocs for low-risk
|
||||
work completed directly; this is none of those.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "154f2f03-387d-5fe6-a0f5-1929c46a2bd8"
|
||||
```
|
||||
|
||||
**Review the five drafted catalog entries and reply.**
|
||||
`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`,
|
||||
`openrouter-llm-connect`, `forgejo-admin-api-token`,
|
||||
`email-connect-transactional` at `secrets-engine@784be97`.
|
||||
|
||||
Review the axes they asked for: owner-repo coordinates, field grouping, workload
|
||||
consumers, rotation/deactivation owners, delivery intent. Verify claims against
|
||||
the authoritative `railiance-platform` CCRs — **never against a secret read**;
|
||||
`bao kv get` on any of these paths is the 2026-07-16 vector and three of the five
|
||||
are `risk: high`.
|
||||
|
||||
Accept their two rejections. `openbao-api-key` is a routing template rather than
|
||||
one lane and `key-cape-oidc-login` belongs to key-cape — that is `ADR-0005`
|
||||
applied to ops-warden by someone else, correctly.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6996d07f-63bb-5708-a171-68c4b1bbddde"
|
||||
```
|
||||
|
||||
**Correct ops-warden's per-path risk grading — the defect T01 exposed.**
|
||||
|
||||
`secrets-engine` graded `issue-core-ingestion-api-key` **high**; ops-warden grades
|
||||
it **standard**, and deliberately: WP-0032-T05 regraded it *down* on 2026-08-19,
|
||||
operator-sanctioned, because `test_high_risk_lanes_classified` asserted standard
|
||||
and was judged right — "ordinary internal workload secrets are standard".
|
||||
|
||||
That reasoning was incomplete, and CCR-2026-0002 says so explicitly: the path
|
||||
carries **both** `ISSUE_CORE_API_KEY` **and** `GITEA_BACKEND_TOKEN`, a Forgejo
|
||||
backend token, and the CCR records keeping both as a deliberate field-set
|
||||
decision.
|
||||
|
||||
**The root cause is structural, not a single bad call.** ops-warden grades a
|
||||
*lane* by its headline field — the catalog carries one `fetch_command` naming one
|
||||
field and no `fields` list at all — but the disclosure unit is the **path**: a
|
||||
`bao kv get` returns every field stored there. So a lane can be graded on its
|
||||
least dangerous contents. `ADR-0007` says every lane carries an explicit grade;
|
||||
it does not say the grade must cover everything a read of that path would
|
||||
disclose, and it should.
|
||||
|
||||
Fix the grade, then fix the model that produced it: record `fields` per lane and
|
||||
grade on the union. Check the other 25 lanes for the same shape.
|
||||
|
||||
**Done 2026-08-21 — and it was two lanes, not one.** While verifying
|
||||
`reuse-surface-hub-write-token` I told secrets-engine their second field was
|
||||
unevidenced and asked them to confirm it. It was evidenced: `CCR-2026-0005`'s
|
||||
`kv_path` block lists both fields and its notes describe the HMAC's alignment
|
||||
with Forgejo org webhook id=1. A truncated grep, and a retraction sent within
|
||||
twenty minutes so they would not spend time on it. That lane was under-graded on
|
||||
exactly the same reasoning, and both had been regraded *down* in the same T05
|
||||
pass — which is what makes this a systematic flaw rather than one bad call.
|
||||
|
||||
Blast radius checked and bounded: of the 8 remaining `standard` lanes, 6 have no
|
||||
KV path at all (SSH, policy check, tunnel, principals, issue-sink, key-cape
|
||||
login) so nothing is disclosed by a read. Two do have paths and no CCR field
|
||||
evidence — `rein-openweights-openrouter-approle` and `coulomb-social-runtime-env`
|
||||
(a whole k8s env Secret, which by shape almost certainly holds several fields).
|
||||
Deliberately **not** regraded: `ADR-0008` §3 says an unknown field set is stated
|
||||
rather than assumed, and grading is operator-sanctioned judgement, not backfill.
|
||||
They are the open item on this task.
|
||||
|
||||
Shipped: both regrades with their evidence and the superseded reasoning kept
|
||||
inline, `fields` recorded with its CCR source, the test that had been holding the
|
||||
wrong answer inverted with an explanation of why it was wrong to trust it, and
|
||||
**`ADR-0008`** — a lane's grade covers every field its path discloses. That is a
|
||||
new binding rule, so it is a record rather than a wiki note.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a736f983-94da-5a4a-aaf9-5114485518a6"
|
||||
```
|
||||
|
||||
**Emit the generated high-risk data-path artifact for `railiance-platform`.**
|
||||
|
||||
They asked for a versioned artifact of concrete high-risk data paths
|
||||
(`id` + `data_path` + catalog revision) to consume instead of hand-maintaining
|
||||
the deny list — the half of the `RISK-F-0009` fix ops-warden explicitly declined
|
||||
to build *for* them. Emitting the artifact is not the same as amending their
|
||||
policy: they still own what to deny. That boundary is the point of `ADR-0002`
|
||||
and must survive this task.
|
||||
|
||||
Must be generated, never hand-edited, and must carry the catalog revision so a
|
||||
consumer can tell what it was derived from. Depends on T02 — publishing the deny
|
||||
set before fixing the grades would ship the wrong list to a consumer who will
|
||||
apply it.
|
||||
|
||||
**Done 2026-08-21.** `scripts/emit_high_risk_paths.py` →
|
||||
`registry/generated/high-risk-data-paths.yaml`: 19 high-risk lanes, 14 concrete
|
||||
data paths, 5 with no single KV address listed separately so a consumer does not
|
||||
read the absence as an omission. Carries `catalog_revision`, its date, and a
|
||||
`catalog_dirty` flag — a revision that does not describe the file it came from is
|
||||
worse than none.
|
||||
|
||||
The T02 dependency was not theoretical. The two regrades land in this artifact,
|
||||
and `check_agent_read_boundary.py` now reports **2 uncovered** against a policy
|
||||
railiance-platform closed to 0 yesterday. Emitting before regrading would have
|
||||
handed them a list that confirmed a coverage claim that had just stopped being
|
||||
true.
|
||||
|
||||
`fields` is emitted as `null` where no CCR declares the set, never as a
|
||||
single-element guess — `ADR-0008` §3. Two CI tests: the artifact must be current,
|
||||
and every high-risk lane must appear in it, so a lane graded high after the last
|
||||
emit cannot silently fail to reach the consumer.
|
||||
|
||||
Boundary held: the header states this is an input and not a policy, and that
|
||||
railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786"
|
||||
```
|
||||
|
||||
**Route the coding-agent issuance identity question.**
|
||||
|
||||
`RAILIANCE-WP-0017` is blocked on defining a distinct coding-agent issuance
|
||||
identity and proving deny-wins when that identity is combined with workload read.
|
||||
They asked ops-warden to route ownership.
|
||||
|
||||
Route it; do not absorb it (`ADR-0005`, `ADR-0003`). ops-warden owns actor
|
||||
identity for `adm`/`agt`/`atm` **SSH certificates** and nothing else — a coding
|
||||
agent's OpenBao issuance identity is an IAM question. The likely owner is
|
||||
`key-cape`, with `user-engine` and `zone-engine` both plausibly involved. Say so
|
||||
with reasoning rather than guessing, and record the answer either way.
|
||||
|
||||
Note the interaction with `ADR-0004`: the agent read-boundary already depends on
|
||||
`WARDEN_AGENT_ID` being set, which is an honour-system marker on the ops-warden
|
||||
side. A real issuance identity is what would make that boundary hold on the
|
||||
OpenBao side too, so ops-warden is an interested consumer, not a bystander.
|
||||
|
||||
**Routed 2026-08-21 to `key-cape` (msg 903b2223); waiting on accept or refuse.**
|
||||
Reasoning given: it is an identity and issuance question about a principal
|
||||
authenticating to OpenBao, which is key-cape/Keycloak's. The precedent is an hour
|
||||
old and runs the same direction — `secrets-engine` declined `key-cape-oidc-login`
|
||||
as ops-warden's to hand them, on the grounds that login and identity-token
|
||||
issuance stay with key-cape. Absorbing this would contradict agreeing with them.
|
||||
|
||||
Named the adjacent parties explicitly rather than leaving them to inference:
|
||||
`zone-engine` has an interest (a coding-agent identity is a strong candidate zone
|
||||
subject) and `user-engine` is **not** involved — this is a machine principal, not
|
||||
an end-user account. Stated so nobody concludes it by elimination.
|
||||
|
||||
Asked for a refusal-with-pointer as an equally good answer. The failure mode to
|
||||
avoid is the 2026-08-17 one recorded in `.claude/rules/finding-routing.md`:
|
||||
ops-warden answered a question well and never routed it, and another repo ended
|
||||
up filing it.
|
||||
|
||||
**Followed up 2026-08-23 after the immediate enforcement gap closed.**
|
||||
`RAILIANCE-WP-0022` no longer waits for this ownership decision: the platform
|
||||
owner deployed a dedicated coding-agent AppRole, proved deny-wins when it is
|
||||
combined with workload read, and identified an exact-bound KeyCape JWT role as
|
||||
the migration target. That makes the remaining question narrower and more
|
||||
important rather than obsolete: who owns issuance of the durable
|
||||
KeyCape/Keycloak-backed machine identity?
|
||||
|
||||
Direct follow-up `d25d4604-5713-42a8-8e3a-1ea31b5a5cc7` asks `key-cape` to
|
||||
accept that target identity with an authoritative workplan/interface, or refuse
|
||||
and name the actual owner. T04 remains `wait` until one of those two answers is
|
||||
recorded; the live AppRole is operational evidence, not an ownership answer.
|
||||
|
||||
**Answered — accepted. Closed 2026-08-28.** `key-cape` accepted issuance
|
||||
ownership in `KEY-WP-0009-T03` (`status: done`, 2026-08-23): the non-secret static
|
||||
registration `codex-railiance-platform` is published in
|
||||
`key-cape/config/service-clients.example.yaml` — subject
|
||||
`service:codex:railiance-platform`, tenant `tenant:coulomb`, role `coding-agent`,
|
||||
scope `openbao:login`, `client_credentials`, 15-minute lifetime — with the
|
||||
service-auth claims, renewal, expiry and failure semantics in
|
||||
`key-cape/docs/openbao-service-auth-contract.md` (`T02`). The split is exactly the
|
||||
one the routing asked for: KeyCape owns JWT issuance and client disablement,
|
||||
railiance-platform owns the exact-bound OpenBao role and policy, OpenBao owns
|
||||
enforcement, and no secret value enters either repository.
|
||||
|
||||
**The answer was found by reading their repo, not by receiving it.**
|
||||
`KEY-WP-0009-T04` records replying to ops-warden; no such message exists in the
|
||||
ops-warden inbox — 0 messages from `key-cape`, read or unread. The acceptance had
|
||||
been sitting done for five days while this task sat `wait` on it.
|
||||
|
||||
That is the T05 lesson landing on T04: a blocker is a claim about the world at a
|
||||
date, and this one had stopped being true. `verified: source-read` is doing real
|
||||
work here — it is the difference between "we asked" and "we checked". The
|
||||
mechanism is right; what it needs is for someone to run it, which is why the
|
||||
lanes below were re-verified in the same pass rather than date-bumped.
|
||||
|
||||
Consequence for `ADR-0004`: the honour-system `WARDEN_AGENT_ID` marker now has a
|
||||
real issuance identity behind it on the OpenBao side. ops-warden remains a
|
||||
consumer of that identity and does not own it.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "75051d17-399b-5129-860b-ae00dae91c47"
|
||||
```
|
||||
|
||||
**Make blocker staleness a mechanism instead of an intention.**
|
||||
|
||||
Four stale blockers surfaced in twelve hours: an OpenBao token recorded expired
|
||||
that was valid, a verification script recorded ready that had never been written,
|
||||
a ten-day `secrets-engine` question answerable from their source, and
|
||||
`FLEX-WP-0007` cited as blocking `policy.enabled` seven weeks after it read
|
||||
`finished`. `.claude/rules/finding-routing.md` has said *re-read a blocker before
|
||||
trusting it* since `RISK-F-0001`. Saying it has not worked.
|
||||
|
||||
`warden route gaps` had a `--stale-days` threshold defaulting to 90, which was
|
||||
not loose but **inert** — the register was created 2026-08-15, so it could not
|
||||
fire before November.
|
||||
|
||||
**Done 2026-08-21.** Two changes, and the second matters more:
|
||||
|
||||
1. **Split the cadences.** `DEFAULT_STALE_DAYS` (90) still governs pointer
|
||||
freshness — "is this the right owner and page" genuinely is quarterly. New
|
||||
`DEFAULT_BLOCKER_STALE_DAYS` (14) governs interim blockers, calibrated on the
|
||||
cases that cost something: ten days for the secrets-engine lanes, one day for
|
||||
`RISK-F-0001`, ~50 for `FLEX-WP-0007`. At ~15 lanes it surfaces about one a
|
||||
day rather than a wall, and it fires on zero lanes on age today.
|
||||
|
||||
**Then scaled by risk, after risk-nexus answered.** They accepted the offer to
|
||||
converge and published their convention: 14 days critical/high, 30 medium, 60
|
||||
low, with fix state *read* from the owning repo rather than remembered. Their
|
||||
framing — "point `warden route gaps` at those windows and the two will agree
|
||||
without either of us building a shared mechanism" — is better than a joint
|
||||
tool, so `blocker_stale_days()` now maps lane `risk` onto exactly those
|
||||
windows. `ungraded` takes the *shortest*, not the longest: `ADR-0007` makes an
|
||||
absent grade a defect, so its blocker is the least trustworthy of all.
|
||||
|
||||
2. **`verified:` distinguishes re-checking from re-editing.** `reviewed` records
|
||||
when someone touched the entry; nothing recorded whether the claim was
|
||||
re-established. `owner-confirmed` and `source-read` count;
|
||||
**`asked-and-waiting` and `unverified` do not**, and a lane in those states is
|
||||
stale regardless of its date. `key-cape-oidc-login` is the proof: asked today,
|
||||
zero days old, correctly flagged.
|
||||
|
||||
Current state: 14 non-draft interim lanes — 5 `owner-confirmed`, 1
|
||||
`asked-and-waiting`, 8 `unverified`. The 8 are honest; they were carried forward
|
||||
this session without a check and now say so instead of hiding behind a fresh date.
|
||||
|
||||
`--fail-on-stale` exits 3 so a cron job or gate can act. **Deliberately not a CI
|
||||
test on age**: a date-triggered failure breaks the build on a calendar day with
|
||||
no code change, punishing whoever commits next rather than whoever owns the
|
||||
blocker. The CI test is structural instead — every interim lane must record
|
||||
*how* it was verified, which fails on the commit that introduces the omission.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T06
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "94f77f5a-f919-5328-832c-ba1d24c6431b"
|
||||
```
|
||||
|
||||
**Correct first-time OpenBao administration routing.** `rapp-postgres` reported
|
||||
on 2026-08-22 that `warden plan` mapped first-time
|
||||
`database/config/platform-pg-2` administration to the generic
|
||||
`openbao-api-key` template. It consequently proposed paste-once KV provisioning
|
||||
and a workload OIDC role, neither of which can configure database connections,
|
||||
policies, auth roles, or token roles. Their Desk session stopped without an
|
||||
approval or secret action.
|
||||
|
||||
The authoritative platform runbook and rapp-postgres's live T04 evidence agree
|
||||
on the missing distinction: this is one attended KeyCape-backed OpenBao identity
|
||||
act at auth mount `netkingdom`, role `platform-admin`. It is not a credential
|
||||
value handoff. Root stays offline break-glass authority and a workload role must
|
||||
never be widened to make the operation pass.
|
||||
|
||||
Add an exact `openbao-platform-admin-login` lane, an operator playbook, and a
|
||||
regression that makes the reported request resolve to `founder_required` with
|
||||
`oidc_login` — never `paste_once_provision`. Verify the route, then return the
|
||||
corrected non-secret command to rapp-postgres.
|
||||
|
||||
**Done 2026-08-22.** The new active lane resolves the exact reported request at
|
||||
score 20, ahead of the generic KV template at 11, and returns one
|
||||
`founder_required` act:
|
||||
`bao login -no-print -method=oidc -path=netkingdom role=platform-admin`.
|
||||
Planner output offers only `warden access openbao-platform-admin-login --fetch`
|
||||
and the exact owner command; login lanes no longer inherit secret-value
|
||||
transports (`--exec`, `--out`, `--wrap`). The lane is explicitly a high-risk,
|
||||
non-workload human identity act, so the generated boundary artifact lists it as
|
||||
having no KV address rather than inventing one.
|
||||
|
||||
Verification: 384 tests pass, Ruff passes, workload accounting resolves all 28
|
||||
lanes (3 resolved, 17 unknown, 8 not-applicable), and the boundary invariant
|
||||
reports 20 high-risk lanes, 14 concrete paths covered, 6 non-KV/pattern lanes,
|
||||
0 uncovered. No login or credential action was performed.
|
||||
|
||||
## Related
|
||||
|
||||
- `secrets-engine` `SECRETS-WP-0006` — catalog admission, decision `ae676382`
|
||||
- `RISK-F-0009` — closed by railiance-platform 2026-08-21; 0 uncovered
|
||||
- `railiance-platform` `RAILIANCE-WP-0022` (boundary coverage), `RAILIANCE-WP-0017`
|
||||
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0007`
|
||||
- `WARDEN-WP-0030` — the delegation register these five lanes retire from
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
---
|
||||
id: WARDEN-WP-0034
|
||||
type: workplan
|
||||
title: "Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
flavor: residual
|
||||
depends_on:
|
||||
- WARDEN-WP-0030
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0030
|
||||
created: "2026-08-29"
|
||||
updated: "2026-09-28"
|
||||
state_hub_workstream_id: "ae3ff76f-883d-5e2f-b6aa-144d61e8fdef"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0034 — Layer model v0.7 conformance
|
||||
|
||||
`security-layer-model_v0.7` is **accepted**. ops-warden declared Staff and PEP-shaped,
|
||||
shipped the two declaration artifacts the standard now cites as estate reference forms,
|
||||
and had four findings adopted into the text between v0.4 and v0.7.
|
||||
|
||||
The assessment in `history/2026-08-29-v07-scope-intent-assessment.md` checked every
|
||||
v0.7 obligation against shipped code rather than intent. Three gaps survive, plus a
|
||||
role the companion assigns that no conformance check will ever catch.
|
||||
|
||||
## Why a workplan and not an adhoc
|
||||
|
||||
T01 is a `MUST` that is currently unstated. T02 changes an enforcement boundary and
|
||||
touches `ADR-0004`. T04 is a cross-repo stewardship commitment against a standard eight
|
||||
repositories have yet to adopt. The convention reserves adhocs for low-risk work
|
||||
completed directly; none of these qualify.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8b3bdb9f-d2c2-5b3e-89e2-417bf3e37484"
|
||||
```
|
||||
|
||||
**State the revocation visibility deadline (§9.7.2, a MUST).**
|
||||
|
||||
ops-warden states none, and the honest value is the certificate TTL: **up to 48 hours**.
|
||||
A cert issued under an allow remains valid for its full TTL even if the authorizing
|
||||
decision is revoked the next minute. There is no CRL, no KRL distribution, and host-side
|
||||
`auth_principals` belongs to `railiance-infra`.
|
||||
|
||||
Add the deadline to `pep-stance.yaml` as what it is — `adm` 48h / `agt` 24h / `atm` 8h —
|
||||
with the mechanism named (TTL expiry, no revocation channel) rather than implied. Assert
|
||||
it against the shipped `ActorType` TTL policy by test, the same way the stance map is
|
||||
asserted equal to shipped behaviour: a stated deadline free to drift from the code has
|
||||
the same defect as a stated stance free to drift.
|
||||
|
||||
**Done when:** the deadline is published, test-bound to the TTL policy, and the absence
|
||||
of a revocation channel is stated rather than left to inference.
|
||||
|
||||
**Not in scope:** shortening it. Whether 48h is acceptable is a joint question with
|
||||
`railiance-infra` (KRL distribution) and is T05's to raise, not this task's to decide.
|
||||
|
||||
Completed 2026-09-04. `pep-stance.yaml` now publishes TTL expiry as the only
|
||||
revocation mechanism, explicitly records that no CRL/KRL channel exists, and
|
||||
states `adm=48h`, `agt=24h`, and `atm=8h`. The conformance test derives the
|
||||
expected map from `ActorType`/`MAX_TTL_HOURS`, so declaration and issuance
|
||||
policy cannot drift independently. The layer and stance declarations now name
|
||||
the accepted v0.7 standard.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3318ee1a-b5d9-5d39-baf7-9c42a8bc7b55"
|
||||
```
|
||||
|
||||
**Bind the agent read-boundary to an issued identity (§3.4 rule 1).**
|
||||
|
||||
`ADR-0004`'s boundary triggers on `WARDEN_AGENT_ID` — a variable the agent sets about
|
||||
itself. An agent that omits it is not recognised as one. §3.4 rule 1 now requires
|
||||
authority to be *issued* per task and attributable to the principal acted for.
|
||||
|
||||
The identity exists as of `KEY-WP-0009-T03`: `codex-railiance-platform`, subject
|
||||
`service:codex:railiance-platform`, role `coding-agent`, 15-minute lifetime, with
|
||||
`railiance-platform` enforcing the OpenBao-side policy.
|
||||
|
||||
Key the boundary on the issued identity where one is present; keep `WARDEN_AGENT_ID` as
|
||||
a fallback that fails **toward** the boundary, never away from it. State plainly in the
|
||||
ADR trail which half is enforced and which is advisory: the OpenBao-side deny is real,
|
||||
the ops-warden-side refusal is a courtesy that a determined caller can decline.
|
||||
|
||||
**Done when:** an agent presenting the issued identity is recognised without setting
|
||||
`WARDEN_AGENT_ID`, the fallback still refuses on `risk: high` lanes, and the
|
||||
enforced/advisory split is written down.
|
||||
|
||||
**Watch:** do not turn this into ops-warden validating a token — that is verifying an
|
||||
identity claim, adjacent to deciding, and `ADR-0002`/§6 both point away from it. Read
|
||||
the identity; do not adjudicate it.
|
||||
|
||||
Completed 2026-09-04. The advisory CLI guard now prefers the exact issued
|
||||
KeyCape subject `service:codex:railiance-platform` from
|
||||
`WARDEN_POLICY_SUBJECT`, then falls back to `WARDEN_AGENT_ID`. Tests prove the
|
||||
issued subject triggers exit 7 without the legacy marker, the fallback remains,
|
||||
and an operator subject does not manufacture an agent identity. ADR-0004
|
||||
revision 2 records the enforced/advisory split: Warden reads the marker and
|
||||
does not validate a token; OpenBao's `agent-high-risk-boundary` is the real
|
||||
enforcement.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "a891b32c-b0a7-59f6-a5cd-977be65c09ca"
|
||||
```
|
||||
|
||||
**Derive an emission cadence, or defer it with a reason (§9.6).**
|
||||
|
||||
ops-warden's trail is attributive, so cadence is a SHOULD rather than v0.7's MUST for
|
||||
load-bearing sources. It has been silent through two reviews, which is the one outcome
|
||||
that is not defensible.
|
||||
|
||||
Derive a baseline from the existing `audit.jsonl` and signatures log. If the signal is
|
||||
too bursty to support a threshold — plausible, since volume is operator-driven — record
|
||||
that as the finding with the distribution that shows it, and declare the deferral in
|
||||
`pep-stance.yaml`. A measured "no useful baseline" is a result; silence is not.
|
||||
|
||||
**Done when:** either a declared cadence with its derivation, or a declared deferral
|
||||
carrying the data that justifies it.
|
||||
|
||||
Completed 2026-09-04 with an explicit measured deferral. The signatures log
|
||||
contains three issuances across the 79-day observation window, on only two
|
||||
active days: one on 2026-06-17 and two within 40 minutes on 2026-08-22. The
|
||||
unified audit carries the latter two events. `pep-stance.yaml` records the
|
||||
counts, dates, attributive classification, and reason that this sparse,
|
||||
operator-driven burst cannot support a meaningful rate threshold.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "94e73daa-f74d-51fd-8639-68896a4066ee"
|
||||
```
|
||||
|
||||
**Answer the question the companion sends the estate here to ask.**
|
||||
|
||||
> *"For how to get something done — which lane, which credential, which route — ask
|
||||
> `ops-warden`."*
|
||||
|
||||
Today the repo answers credential questions and no others. `warden route` and
|
||||
`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*, *"how
|
||||
do I declare"*, *"I am PEP-shaped, what do I owe"* — and eight of fifteen catalogued
|
||||
repositories have yet to declare.
|
||||
|
||||
Provide the path, not the doctrine (that boundary is `ADR-0010`'s and does not move):
|
||||
a routing entry and a short playbook that carry a reader from the companion to the files
|
||||
to copy — `layer.yaml`, `pep-stance.yaml`, `check_layer_conformance.py`,
|
||||
`test_layer_conformance.py` — and the check to run. The standard already names these in
|
||||
§11 and §6.4; what is missing is the route to them.
|
||||
|
||||
**Done when:** `warden route find "how do I declare my layer"` resolves, and the
|
||||
playbook is reachable from the catalog. **Not** a restatement of the companion — a
|
||||
pointer layer, per `ADR-0001`.
|
||||
|
||||
Completed 2026-09-04. Catalog entry `netkingdom-layer-declaration` resolves the
|
||||
exact query to `wiki/playbooks/netkingdom-layer-declaration.md`. The short
|
||||
playbook points at the accepted companion/statute, the four reference artifacts
|
||||
and checks, and the gate-house review path while explicitly leaving doctrine
|
||||
with gate-house and declaration truth with each repository.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T05
|
||||
status: wait
|
||||
blocked_on: message-from:ops-mason
|
||||
blocking_reason: "Two items to route, not absorb: ops-mason has published no stance map; the second is another repository's to own."
|
||||
priority: low
|
||||
state_hub_task_id: "7d1b3c82-9b96-5087-a53a-496212909029"
|
||||
```
|
||||
|
||||
**Two things to raise rather than absorb.**
|
||||
|
||||
Both are other repositories' to own; ops-warden's obligation is to route them, not to
|
||||
fix them (`ADR-0003`, `ADR-0005`).
|
||||
|
||||
1. **`ops-mason` has published no stance map.** §13.1's register has one row and the
|
||||
standard says that is itself the finding. `ops-mason` is catalogued PEP-shaped in
|
||||
the same paragraph and is ops-warden's peer lane owner. Offer the reference form;
|
||||
do not write their map.
|
||||
2. **The 48-hour replay window from T01.** Once stated, raise with `railiance-infra`
|
||||
whether KRL distribution is worth building, and with `access-engine` whether a
|
||||
decision lifetime shorter than the cert TTL is meaningful when nothing can recall
|
||||
the cert. State the question; let the owners answer.
|
||||
|
||||
**Done when:** both are routed with reasoning, and the answers recorded either way —
|
||||
including a refusal, which is an equally good answer.
|
||||
|
||||
Raised 2026-09-04 and waiting for answers. Ops-mason received the stance-map
|
||||
reference and classification question (message `6ddd6cc7`). Railiance-infra
|
||||
received the KRL-versus-TTL question (message `3bfa306e`). Flex-auth, as the
|
||||
current access-engine implementation, received the decision-lifetime semantics
|
||||
question (message `02c99a74`). No implementation or policy decision was assigned
|
||||
to another owner by these messages.
|
||||
|
||||
**One of three answered, 2026-09-09.** `flex-auth` answered the decision-lifetime
|
||||
question as `FLEX-DEC-2026-004` (flex-auth commit `6a6464f`), and answered it
|
||||
rather than declining it: a decision lifetime shorter than the certificate TTL is
|
||||
meaningful, but only as authority to **issue**, never as authority to **use** an
|
||||
already-issued certificate. The action is `sign` and it completes at issuance, so
|
||||
the decision is consumed once the certificate exists and no field in the decision
|
||||
record reaches the artifact. 15m against a 48h `adm` certificate was never an
|
||||
inconsistency to reconcile — the question mistook a decision lifetime for a
|
||||
credential lifetime.
|
||||
|
||||
Two obligations land on this side and are accepted: no replay of an allow past
|
||||
`expires_at`, and a fresh Check per sign. The second is where the value is, and it
|
||||
is real rather than nominal because claims are not cached PDP-side (deadline 0 for
|
||||
the claim class), so a revoked principal stops obtaining *new* certificates
|
||||
immediately.
|
||||
|
||||
`pep-stance.yaml` §9.7.2 is unchanged and stays here: flex-auth explicitly declined
|
||||
to move the residue to their side, on the ground that a PDP recalling an issued
|
||||
credential would be "the same shape of lie as fail-open". Declining it was the
|
||||
right call even though absorbing it would have made their record look tidier.
|
||||
|
||||
The TTL lever they named — capping requested TTL per actor class or zone, already a
|
||||
policy input since `ttl_out_of_bounds` is denied before OpenBao is reached — is
|
||||
noted and deliberately not requested. Shortening `adm` from 48h has an operator
|
||||
cost, and issuance on this lane is too sparse (3 signature records across 79 days,
|
||||
`pep-stance.yaml` `emission_cadence`) to price it from intuition.
|
||||
|
||||
T05 stays `wait` on the remaining two: `ops-mason` (no stance map published) and
|
||||
`railiance-infra` (KRL distribution versus TTL expiry). Neither has replied.
|
||||
|
||||
## Await gate-house's §11 precedence and case-sensitivity ruling
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T06
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "b3b573df-2d2d-5a2c-9662-a13e435be57b"
|
||||
```
|
||||
|
||||
ops-warden declares `layer: Staff` in `INTENT.md` frontmatter and `layer: staff`
|
||||
in `layer.yaml`. §11 permits both forms and is silent on which governs when both
|
||||
exist and disagree, so two conformance runs over this repository can disagree
|
||||
while both follow the standard. Nine of nine repositories carrying both forms do
|
||||
the same thing (flex-auth `tools/survey_layer_declarations.go`, receipt
|
||||
`docs/evidence/2026-09-21-layer-declaration-survey.json`).
|
||||
|
||||
**RULED 2026-09-21, APPLIED 2026-09-21.** `GH-DEC-2026-017`
|
||||
(`gate-house@def0af2`, amendments A9-A13) answers both questions, and the answer
|
||||
to the second dissolves the first's consequence:
|
||||
|
||||
- **`INTENT.md` governs**; `layer.yaml` is a derived artifact that must be marked
|
||||
derived, must name `INTENT.md` as its source, and must agree with it.
|
||||
- **The §3 vocabulary is case-insensitive**, closed, and has four tokens
|
||||
(`Taxonomy`, `Tooling`, `Engine`, `Staff`). A conformance run MUST ASCII-fold
|
||||
case before comparing, and **no repository was asked to re-spell anything**.
|
||||
`Staff` and `staff` are one value.
|
||||
- **A declaration MUST NOT carry a standard version** — and that field is the
|
||||
*reference form's*, not this repository's habit, so ops-warden was asked to
|
||||
remove it here rather than each of seven adopters deciding.
|
||||
|
||||
Verified before editing against gate-house's own committed files rather than the
|
||||
inbox message: the decision at `gate-house@def0af2`, amendments A9-A13 in
|
||||
`docs/amendments/v0.8-section-11-declaration-amendments.md`, and §3/§4/§11 of
|
||||
`net-kingdom/canon/standards/security-layer-model_v0.8.md`.
|
||||
|
||||
**What was applied.** `standard_version` removed from `layer.yaml` **and** from
|
||||
`INTENT.md` frontmatter (the ruling's subject is the declaration, and `INTENT.md`
|
||||
is the declaration), with the version-pinned `standard:` path de-versioned for the
|
||||
same reason; `derived: true` / `derived_from: INTENT.md` added; **no layer value
|
||||
changed**; `scripts/check_layer_conformance.py` rewritten to read `INTENT.md` as
|
||||
governing, fold case, validate the closed four-token vocabulary, require the
|
||||
derived marking, and reject a returning `standard_version` — it previously
|
||||
*required* that field and so would have rejected the conforming declaration this
|
||||
ruling produces; `tests/test_layer_conformance.py` asserts the **fold** rather
|
||||
than equality, because an equality assertion would perform the re-spelling the
|
||||
ruling declined to order. `pep-stance.yaml` untouched: a stance map is not a layer
|
||||
declaration, and the schema beyond the derived marking and the version is
|
||||
explicitly not ruled.
|
||||
|
||||
**Evidence.** `python3 scripts/check_layer_conformance.py --report` exits 0 and
|
||||
prints the governing form and the derived one separately; `pytest
|
||||
tests/test_layer_conformance.py` green; full suite and `ruff` green. Reasoning
|
||||
and the adopter change set: `docs/layer-declaration-precedence.md` and
|
||||
`wiki/playbooks/netkingdom-layer-declaration.md`.
|
||||
|
||||
**Left open, and not decided here.** Where the removed version now lives. A12
|
||||
says version-scoped state belongs in the derived conformance record, which
|
||||
"already MUST" carry the version it was derived at; ops-warden has a re-runnable
|
||||
checker that emits nothing durable, not an emitted record. Whether §11 expects an
|
||||
emitted artifact or a re-runnable check discharges it is asked of gate-house in
|
||||
message `4220413a` and unanswered. Nothing applied above depends on the answer.
|
||||
**Closed 2026-09-21 by `GH-DEC-2026-020` §4 (gate-house@104f3fc):** §5 was wrong
|
||||
that the record exists; a re-runnable checker is sufficient if every run prints
|
||||
the version it checks against and its scope. Applied: the checker now prints
|
||||
`VALIDATED_AGAINST` and `SCOPE` on every run and enforces A12 r2 by content, not
|
||||
key name (versioned `standard:` path, `companion_version`); `pep-stance.yaml`
|
||||
untouched per §3; the playbook carries the adopter change set.
|
||||
|
||||
**Ruled the same day, and still `wait` — deliberately.** `GH-DEC-2026-017`
|
||||
(message `3715e247`) landed hours later: `INTENT.md` governs, the sidecar is a
|
||||
derived artifact that must be marked as such, §3's vocabulary is case-insensitive
|
||||
so **nobody re-spells anything**, and `standard_version` must come out of the
|
||||
declaration. Two asks land on ops-warden specifically because `layer.yaml` is the
|
||||
form seven repositories copied.
|
||||
|
||||
This task stays `wait` rather than flipping to `progress`, because applying it
|
||||
edits this repository's security-layer declaration — and the estate's reference
|
||||
shape — on the strength of an instruction delivered in an inbox message. The
|
||||
session that applies it should be mandated to, and should verify the decision at
|
||||
`gate-house@def0af2` and amendments A9–A13 in the repository rather than from the
|
||||
message text. The exact change set and its four conditions are written down in
|
||||
`docs/layer-declaration-precedence.md`; the casing half of the original "done
|
||||
when" above is moot rather than outstanding, since the ruling folds case.
|
||||
|
||||
Raised by flex-auth's corrected B1 (message `719b3e9e`, 2026-09-21), which
|
||||
withdrew an earlier claim that the estate disagreed *across* repositories. The
|
||||
withdrawal matters to this task: the original finding would have had ops-warden
|
||||
changing a file to match an estate consensus that did not exist.
|
||||
|
||||
## Related
|
||||
|
||||
Review 2026-09-05: reviewed the pending implementation and fixed the identity
|
||||
helper so an explicitly empty environment does not inherit the process identity.
|
||||
Regression coverage also proves an operator subject cannot override the legacy
|
||||
agent marker. Refreshed the generated high-risk path artifact after the catalog
|
||||
changes. T05 remains waiting: no corresponding reply was present in the inbox,
|
||||
and the checked owner workplans contained no resolution of these questions.
|
||||
Validation: 415 unit tests and four SSH integration tests pass; Ruff, the
|
||||
layer-conformance script, and the declaration-route CLI smoke check pass.
|
||||
|
||||
- `history/2026-08-29-v07-scope-intent-assessment.md` — the gap analysis behind this plan
|
||||
- `history/2026-08-29-layer-model-v04-review.md`, `-v06-review.md` — the two prior reviews
|
||||
- `security-layer-model_v0.7.md` §3.4, §6.4, §9.6, §9.7, §11, §13.1
|
||||
- `net-kingdom/SECURITY-COMPANION.md` v0.2
|
||||
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0009`, `ADR-0010`
|
||||
|
||||
### 2026-09-28 loose-end review
|
||||
|
||||
T05 remains wait; the workplan is blocked on the two outstanding owner answers.
|
||||
The local ops-mason checkout still has no published stance map, and the available
|
||||
railiance-infra workplans/docs contain no KRL-versus-TTL acceptance or refusal.
|
||||
The flex-auth decision-lifetime answer remains accepted. Warden's declaration,
|
||||
TTL-bound tests and fresh-check behavior are complete; inventing an owner answer
|
||||
would not satisfy T05. No certificate lifetime or revocation policy was changed.
|
||||
|
||||
> 2026-10-11: demoted to `flavor: residual` / `backlog` by founder-authorized triage — off the
|
||||
> critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged;
|
||||
> promote back when demand or risk appears. See the-custodian
|
||||
> `history/20261011-netkingdom-security-progress-assessment.md`.
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
id: WARDEN-WP-0035
|
||||
type: workplan
|
||||
title: "Register the Policy Nexus Forgejo source-read route"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: policy-nexus-forgejo-source-read
|
||||
created: "2026-09-01"
|
||||
updated: "2026-09-01"
|
||||
state_hub_workstream_id: "45aec8d3-94b3-586e-b019-a47e656efafa"
|
||||
---
|
||||
|
||||
## Register the exact high-risk lane
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0035-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "dd84f2be-0143-540c-9c16-74f0fd129260"
|
||||
```
|
||||
|
||||
Add the exact OpenBao path, field, OIDC role, owner pointer, and rotation
|
||||
boundary from railiance-platform CCR-2026-0014. The entry must be concrete and
|
||||
resolvable while remaining subject to Warden's high-risk agent read boundary.
|
||||
|
||||
## Verify routing and governed use
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0035-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1fa8f778-3e46-5f44-86c4-cab8628b7e60"
|
||||
```
|
||||
|
||||
Pass catalog, route-selection, proxy, and policy tests; reinstall the CLI; prove
|
||||
the installed route resolves and can hand the value only to a sanctioned child
|
||||
transport without printing or persisting it.
|
||||
|
||||
Completed 2026-09-01. All 406 selected tests passed, including the generated
|
||||
high-risk data-path boundary. The no-cache installed CLI resolves the exact
|
||||
lane, and `warden plan` returns only sanctioned `--exec`, `--out`, and `--wrap`
|
||||
transports for an agent caller. Policy Nexus Actions run 32 separately proved
|
||||
the installed credential against the complete private-source fetch and release
|
||||
path without exposing the value.
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
id: WARDEN-WP-0036
|
||||
type: workplan
|
||||
title: "Accept contained OpenBao login output only after helper persistence"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: attended-login-openbao-output
|
||||
created: "2026-09-01"
|
||||
updated: "2026-10-15"
|
||||
state_hub_workstream_id: "d844c96e-152d-53fa-bff6-e072125ef66c"
|
||||
---
|
||||
|
||||
## Repair attended-login handoff
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0036-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "7eb8b9c9-1285-5ada-a17b-1d5bfbb8ba59"
|
||||
```
|
||||
|
||||
Allow a successful OpenBao login to proceed when its output is fully contained
|
||||
and the private mode-0600 token helper is populated. Continue failing closed on
|
||||
non-zero login, missing persistence, child output, revocation failure, or cleanup
|
||||
failure.
|
||||
|
||||
## Verify live contained operation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0036-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d22bab05-c38b-561f-95de-6c146ce7c6cf"
|
||||
```
|
||||
|
||||
Run the proxy regression suite, reinstall the CLI, and complete one governed
|
||||
OpenBao platform-admin operation with deterministic self-revocation.
|
||||
|
||||
Completed 2026-09-01. The installed CLI completed the governed Policy Nexus
|
||||
Forgejo source bootstrap with all child output contained, then revoked and
|
||||
removed its isolated helper session.
|
||||
|
||||
### 2026-09-28 contained-result correction (existing T01/T02)
|
||||
|
||||
Addressed the September 21 attended-login failure/audit report under the existing
|
||||
handoff repair and verification tasks. Failed envelopes now use distinct
|
||||
non-zero codes 10–14 for login, child failure, child output, unconfirmed revocation
|
||||
and cleanup failure. Both audit files retain the actual Warden exit code and
|
||||
phase outcome. Any child bytes, including whitespace, fail closed; the access
|
||||
advisory now states the silent-child requirement and the playbook documents codes,
|
||||
retry limits and the WSL tunnel/browser requirements.
|
||||
|
||||
The pre-change checkout already raised exit 5 on ProxyError, so the reported
|
||||
historical exit-zero failure was not reproduced here. The actual reproduced defect
|
||||
was unconditional success auditing; the new CLI regression covers failed login
|
||||
with returncode zero but missing persistence as well as non-zero login, start
|
||||
failures, child output/failure, revocation and cleanup. Revocation still checks
|
||||
revoke-self's exit status; it does not misinterpret an arbitrary failed lookup as
|
||||
proof. The September 23 platform return confirms revoke-self is already granted.
|
||||
|
||||
Validation: focused proxy suite 48 passed; full suite 483 passed, 4 integration
|
||||
tests deselected by repository default; changed Python files pass Ruff. No live
|
||||
OIDC, credential read or production operation was used. The earlier September 1
|
||||
live operation remains historical evidence, not a live validation of this change.
|
||||
Automated endpoint/browser preflight and OIDC URL presentation remain optional
|
||||
inbox suggestions, outside these completed handoff acceptance criteria.
|
||||
|
||||
### 2026-10-14 login-output fail-closed regression and fix (existing T01)
|
||||
|
||||
railiance-platform's RPF-WP-0017 re-acceptance review
|
||||
(`railiance-platform/reviews/RPF-WP-0017-ops-warden-reacceptance-2026-10-14.json`,
|
||||
decision `reject`) found that T01's commit `b4c1d39` (2026-09-01) dropped
|
||||
`login_output.strip()` from the login fail-closed condition. From then until this
|
||||
fix, a login that exited 0 with a populated helper proceeded to the child whatever
|
||||
it wrote to stdout/stderr. Output stayed contained (criterion 3 held) but
|
||||
criterion 4 (non-allowlisted output fails closed with self-revocation) and the
|
||||
criterion 5 unexpected-output coverage regressed; the existing unexpected-output
|
||||
test passed only through the empty-helper persistence path.
|
||||
|
||||
Fix: login output is still captured and never forwarded, and is now accepted only
|
||||
when allowlisted by structure (values are never logged, returned, stored, or put
|
||||
in exceptions/audit):
|
||||
|
||||
- stdout: empty, or exactly one JSON object with an `auth` object containing
|
||||
`client_token`; top-level keys limited to `request_id, lease_id,
|
||||
lease_duration, renewable, data, warnings, wrap_info, mount_type, auth`, auth
|
||||
keys to `client_token, accessor, policies, token_policies, identity_policies,
|
||||
metadata, orphan, entity_id, lease_duration, renewable, mfa_requirement,
|
||||
num_uses`, each type-checked; duplicate keys rejected.
|
||||
- stderr: empty, or exactly the OpenBao OIDC CLI prompt ("Complete the login via
|
||||
your OIDC provider. Launching browser to:" or "... Open the following link in
|
||||
your browser:", one `https://` URL, optional "Waiting for OIDC authentication to
|
||||
complete..."). These prompt strings were confirmed present in the local `bao`
|
||||
binary; this stderr allowlist entry is an ops-warden proposal pending
|
||||
railiance-platform review under RPF-WP-0017.
|
||||
|
||||
Anything else (extra text, other stderr, multiple objects, unexpected keys or
|
||||
types, parse/decoding failure) fails closed: self-revocation through the existing
|
||||
path, helper cleanup, exit 10 / `login_failed`, no retry. Added a parametrized
|
||||
populated-helper test for 13 non-allowlisted shapes and an allowlisted hand-off
|
||||
test; the success test now uses a full JSON shape plus the OIDC prompt. The
|
||||
September 1 T02 live operation was recorded in `9770d6a` (00:51 +0200), after
|
||||
`b4c1d39` (00:13 +0200) and `8f01eef` (00:24 +0200); `proxy.py` at that time
|
||||
contained the relaxed check (the installed CLI's exact revision was not recorded). No live OIDC, OpenBao call, or credential read was used for this fix.
|
||||
|
||||
Tightened the same day after an independent re-review (containment gap): stdout
|
||||
`wrap_info` must be null or absent (a wrapping token would survive `token revoke
|
||||
-self`), `data` null, absent or `{}`, and `auth.client_token` a non-empty string;
|
||||
the stderr OIDC prompt must start at the first byte (no leading whitespace;
|
||||
trailing newlines remain fine). The fail-closed and hand-off tests now run through
|
||||
the CLI and assert sentinel absence from both `access-audit.log` and `audit.jsonl`.
|
||||
|
||||
### 2026-10-15 CUST81 dependency correction (existing T01/T02)
|
||||
|
||||
Prepared source correction after the two CUST81 attended platform-admin attempts
|
||||
failed before child handoff. The strict login-output allowlist remains unchanged.
|
||||
Synthesized format flags now precede auth data; the recovery-only matcher handles
|
||||
OpenBao `s.` tokens; failure messages expose only fixed categories, client exit
|
||||
code and helper/output-shape booleans. No credential bytes or URLs are surfaced.
|
||||
|
||||
Do not attribute the observed 121-second failure to the argv order: Bao 2.5.5
|
||||
scans global format throughout argv. Actual callback/auth failure remains unknown.
|
||||
Browser profile initialization was verified from metadata only; server revocation
|
||||
remains unconfirmed and the failed attempts are retained. No login, admin token
|
||||
read, policy application or provisioning was performed by this correction.
|
||||
|
||||
Source verification is distinct from live verification. The already-approved
|
||||
CUST81 execution scope and its open attended gate remain with CUST-WP-0081-T02.
|
||||
Owner evidence: `docs/evidence/2026-10-15-cust81-attended-dependency-repair-r1.json`.
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
id: WARDEN-WP-0037
|
||||
type: workplan
|
||||
title: "Repoint the whynot-design npm lane to Forgejo"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: blocked
|
||||
flavor: planning
|
||||
owner: codex
|
||||
topic_slug: whynot-design-forgejo-npm-lane
|
||||
created: "2026-09-04"
|
||||
updated: "2026-10-03"
|
||||
state_hub_workstream_id: "42a097db-1c24-558e-a724-030bb2b4443e"
|
||||
---
|
||||
|
||||
## Verify the existing credential against Forgejo
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0037-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "afc4d325-1c6d-5c25-aaf7-2118aa8f86c6"
|
||||
```
|
||||
|
||||
Use only the governed execution transport to test the existing publish identity
|
||||
against the canonical Forgejo npm endpoint. Do not print or persist the token.
|
||||
|
||||
2026-09-04: `warden plan` classified the exact verification as autonomous and
|
||||
selected this lane. A contained login using the documented
|
||||
`whynot-design-workload-kv-read` role proved `read` on the exact OpenBao data
|
||||
path, and the governed child proved the secret is present. A real 0.4.2 publish
|
||||
through that credential then failed. No value was printed or persisted and each
|
||||
contained session self-revoked. The lane therefore needs token rotation, not an
|
||||
OpenBao policy repair.
|
||||
|
||||
## Repoint the catalog and playbook
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0037-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "7ceb2f74-496c-54e8-bf5a-3c49f994ff23"
|
||||
```
|
||||
|
||||
Replace the retired Gitea endpoint and discovery language with Forgejo while
|
||||
preserving the established OpenBao path, field, and least-privilege boundary.
|
||||
This delivers the npm facet of routed intake
|
||||
`01a06e07-f2f9-7586-9745-b359eb0025b6`; its inter-hub SSH facet remains separate.
|
||||
|
||||
Completed 2026-09-04. The catalog title, discovery keywords, rotation guidance,
|
||||
and worker playbook now name the canonical Forgejo registry at
|
||||
`https://forgejo.coulomb.social/api/packages/coulomb/npm/`. The OpenBao path,
|
||||
field, owner, native-exec pointer, and high-risk boundary are unchanged. A
|
||||
regression assertion prevents the retired Gitea discovery term and guidance
|
||||
from returning.
|
||||
|
||||
## Prove routing and publication
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0037-T03
|
||||
status: wait
|
||||
priority: high
|
||||
decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa
|
||||
depends_on: [SECRETS-WP-0006-T06]
|
||||
blocking_reason: "Hold kept by D3 until SECRETS-WP-0006-T06 moves publishing off the legacy whynot-design npm path; then rotate and prove a fresh publish."
|
||||
intervention_note: "HOLD (founder, 2026-09-21): do not rotate yet. secrets-engine exec reads the ungoverned legacy path secret/coulomb/whynot-design/npm/publish (field npm_token); this runbook writes the governed path platform/workloads/coulomb/whynot-design/npm-publish (NPM_AUTH_TOKEN). A rotation now would not reach the live publish path. Resume after SECRETS-WP-0006-T06 moves the lane. Then: rotate the dedicated Forgejo package token, and prove a fresh publish and exact npm view through this lane."
|
||||
state_hub_task_id: "a8b1b855-ab34-5835-b9fd-5f48bc0b6817"
|
||||
```
|
||||
|
||||
2026-10-11: requalified after founder decision D3 (trust root, build-mode default) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md.
|
||||
|
||||
Pass catalog and routing tests, verify the checkout route, and record the exact
|
||||
Forgejo package release proven through the lane.
|
||||
|
||||
2026-09-04: repo-local verification is complete: the checkout route ranks
|
||||
`whynot-design-npm-publish` first for a Forgejo npm publish need, reports the
|
||||
canonical Forgejo title and verification command, all focused
|
||||
routing/access/proxy tests pass (`145 passed`).
|
||||
|
||||
The sibling repo's `@whynot/design@0.4.2` release (105 files; IR
|
||||
`designVersion` 0.4.2; five visual tests pass) was published through the
|
||||
plan-authorized `forgejo-admin-api-token` one-time recovery lane. An
|
||||
authenticated exact-version lookup proved that Forgejo's remote integrity
|
||||
matches the local dry-run. T03 waits only on rotating the dedicated package
|
||||
token and proving the next fresh version through `whynot-design-npm-publish`;
|
||||
the package migration itself is complete.
|
||||
|
||||
**2026-09-09 — field claim corrected, path routed.** `secrets-engine` (msg
|
||||
`15f0c0ca`) corrected two things and declined a third, all correctly.
|
||||
|
||||
The KV field is `npm_token`. `NPM_AUTH_TOKEN` is the environment variable their
|
||||
publication-scope policy injects, and ops-warden had copied the env var in as the
|
||||
field name — so the catalog's `fetch_command` named a field that does not exist
|
||||
and could only ever have failed. Corrected in `registry/routing/catalog.yaml` and
|
||||
`wiki/playbooks/whynot-design-npm-publish.md` from the owner's statement rather
|
||||
than re-derived here. This was `ADR-0001`'s failure mode rather than a typo: a
|
||||
pointer layer restating an owner's procedure and getting a detail wrong.
|
||||
|
||||
The endpoint claim already agreed; `delivery_config.npm.registry` has been the
|
||||
Forgejo URL throughout.
|
||||
|
||||
The **path** is routed to `railiance-platform` and the catalog is unchanged pending
|
||||
their answer. Which location backs the lane for reads is custody state they own;
|
||||
`secrets-engine` has no lane read authority to confirm it and refused to rewrite a
|
||||
production lane pointer from a coordination message (`SECRETS-WP-0006-T06`). Their
|
||||
reasoning is right, and asserting our own pointer is authoritative because it is
|
||||
ours would route around it. The ask names a location only and flags that a
|
||||
`bao kv get` answer would be the 2026-07-16 disclosure vector on a `risk: high`
|
||||
lane.
|
||||
|
||||
`ready: false` is not being read as path evidence: a source checkout with no
|
||||
production authority reports not-ready regardless of which path the catalog names.
|
||||
|
||||
T03 still waits on the human rotation of the dedicated Forgejo package token; the
|
||||
path question does not block that, it determines whether the pointer is correct
|
||||
once it rotates.
|
||||
|
||||
**2026-09-21 — field reverted to `NPM_AUTH_TOKEN`; path confirmed; a second
|
||||
location found.** `railiance-platform`, who holds custody of the path, answered
|
||||
both halves (msgs `c6841bdb`, `79f3e047`) and the answer reverses the 2026-09-09
|
||||
change above.
|
||||
|
||||
An attended founder session enumerated the field names present at
|
||||
`platform/workloads/coulomb/whynot-design/npm-publish`: read-only, no mutation,
|
||||
no value emitted, `attended_identity` true. **Exactly one field is present, and
|
||||
it is `NPM_AUTH_TOKEN`.** Receipt: `railiance-platform
|
||||
docs/evidence/2026-09-10-npm-lane-field-resolution.json`, commit `9d24086`. The
|
||||
both-fields reconciliation offered the day before is ruled out by the same
|
||||
enumeration. `CCR-2026-0001` has carried two dated receipts naming that field
|
||||
since 2026-06-28, one of them an attended founder fetch that exited zero — which
|
||||
is itself proof the field exists.
|
||||
|
||||
So `npm_token` is wrong *for this path*, and the catalog and playbook are
|
||||
reverted to `NPM_AUTH_TOKEN`. Reverting is a correction back to the evidenced
|
||||
value, not a new lane change.
|
||||
|
||||
The lesson is the one this plan already recorded, one level in. On 2026-09-09
|
||||
this file wrote that adopting a correction from `secrets-engine` rather than
|
||||
re-deriving it was the right shape. It was the right *source* and the wrong
|
||||
*standard of evidence*: a correction adopted from a coordination message is
|
||||
still an unverified mutation, even when it is only a field name in a catalog,
|
||||
and this one would have failed at the rotation T03 is waiting for — the moment
|
||||
it is most expensive to discover. railiance-platform's phrasing, kept because it
|
||||
is better than ours: it will break "at the moment you least want it to".
|
||||
|
||||
**The second location, which is not ours to dispose of.**
|
||||
`secret/coulomb/whynot-design/npm/publish` exists — version 1, created
|
||||
2026-07-03T15:00:44Z, never updated, five days *after* the governed lane was
|
||||
verified. It sits outside this lane's exact-path policy and outside any CCR.
|
||||
railiance-platform read metadata only: field names were not enumerated, the
|
||||
value was not read, nothing was deleted, because a location holding real
|
||||
credential material is disposed of deliberately by its owner rather than tidied
|
||||
away by whoever finds it.
|
||||
|
||||
Their unconfirmed hypothesis, recorded because it changes what this lane's
|
||||
acceptance evidence means if true: `secrets-engine`'s lowercase field may belong
|
||||
to *that* path, their catalog may declare that location, and the proven pilot
|
||||
publish may have been reading the duplicate all along. If so, a working
|
||||
production lane has been running ungoverned and this lane's acceptance evidence
|
||||
describes a path its consumer does not use. Tracked as `RPF-WP-0035-T07`;
|
||||
railiance-platform has asked `secrets-engine` which location their publish
|
||||
reads, and ops-warden has asked the same about the native
|
||||
`secrets-engine exec` front door this catalog points at (`exec_owner`).
|
||||
|
||||
Recorded in the catalog and in `wiki/playbooks/whynot-design-npm-publish.md` as
|
||||
an explicit non-lane rather than deleted from the record. Not routed around: the
|
||||
governed path stays the pointer.
|
||||
|
||||
### 2026-09-27 owner follow-up
|
||||
|
||||
Consumed the September 21 secrets-engine source return: the active catalog
|
||||
still names `secret/coulomb/whynot-design/npm/publish`, field `npm_token`.
|
||||
The governed field remains `NPM_AUTH_TOKEN`; no pointer correction is needed
|
||||
in Warden. RPF-WP-0035-T07 now requires native governed-consumer proof before
|
||||
legacy destruction and no longer asks for comparison of secret values.
|
||||
|
||||
T03 remains wait and the founder's no-rotation hold remains effective.
|
||||
Resume only on the SECRETS-WP-0006-T06 migration receipt, then rotate through
|
||||
the dedicated package lane and prove a fresh publish plus exact npm view.
|
||||
Do not treat the September 16 OpenRouter key-check receipt as npm acceptance.
|
||||
|
||||
### 2026-09-28 loose-end review
|
||||
|
||||
Workplan state corrected to blocked to match T03's wait and the September 27
|
||||
owner return. The governed catalog field and path are already correct. The
|
||||
founder's no-rotation hold remains binding until SECRETS-WP-0006-T06 supplies
|
||||
native governed-consumer migration evidence; a dedicated token rotation and a
|
||||
fresh package publish/exact-version lookup then remain. No credential fetch,
|
||||
rotation or publication was attempted.
|
||||
|
||||
2026-10-03 (CUST-WP-0075): the gate was only in intervention_note. Encoded as blocking_reason, depends_on SECRETS-WP-0006-T06, and hub decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa (D3: trust root and secret custody), which also carries the matching RPF-WP-0035-T07 hold.
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
---
|
||||
id: WARDEN-WP-0038
|
||||
type: workplan
|
||||
title: "warden plan must distinguish reading a secret from mutating one"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0029
|
||||
created: "2026-09-08"
|
||||
updated: "2026-10-16"
|
||||
state_hub_workstream_id: "751ad530-e44b-52c4-b70e-cb47568a0179"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0038 — Read versus mutate intent in the policy front door
|
||||
|
||||
## The defect
|
||||
|
||||
`warden plan` scores a need against catalog lanes by keyword overlap and returns
|
||||
a verdict. It has no notion of what the caller wants to *do*. So a need that
|
||||
says *generate a successor secret and CAS-write it to two custodians* matches the
|
||||
lane that **reads** that path, scores well on the shared nouns, and returns:
|
||||
|
||||
```
|
||||
verdict: autonomous
|
||||
commands: warden access <lane> --exec / --out / --wrap
|
||||
```
|
||||
|
||||
Three read transports offered as the answer to a write, under the verdict that
|
||||
means "proceed without the founder". Reproduced 2026-09-08 against
|
||||
`rapp-qonto-keycape-client` (`ADHOC-2026-09-08-T04`).
|
||||
|
||||
## Why this is worse than a bad suggestion
|
||||
|
||||
`warden plan` is the documented first step before drafting any founder credential
|
||||
step (`.claude/rules/credential-routing.md`), and `autonomous` is consumed as an
|
||||
authorization signal by agents that have no other check. `WARDEN-WP-0029` shipped
|
||||
the verdict *because* instinct was not auditable; a verdict that is confidently
|
||||
wrong in the permissive direction is worse than no verdict.
|
||||
|
||||
key-cape hit this and refused to rely on it — "we are not treating a generic
|
||||
match as authorization" — which is the only reason it surfaced as a design
|
||||
question rather than as an unadmitted custody mutation. The control that caught
|
||||
it was a counterparty's caution. That is not a control.
|
||||
|
||||
`WARDEN-WP-0033-T06` is the same shape (rapp-postgres, generic
|
||||
`openbao-api-key` match → `paste_once_provision` for an act that could not work)
|
||||
and was fixed by adding one exact lane plus one regression. That fixed the
|
||||
instance. This is the class.
|
||||
|
||||
## Shape of the fix (to be designed, not assumed)
|
||||
|
||||
- Classify need intent — read / mutate / establish — before scoring, and never
|
||||
answer a mutate need with a read lane's transports.
|
||||
- A mutate need against a lane ops-warden does not own is `unroutable` with a CCR
|
||||
stub naming the custody owner, not `autonomous`. `ADR-0003`: cover gaps, never
|
||||
silently own them; a permissive verdict on someone else's custody act is a
|
||||
silent claim of ownership.
|
||||
- Consider whether `rotation.steps` should be reachable from `plan` at all, given
|
||||
they are advisory prose and several are explicitly not automatable.
|
||||
- Regression from the reproduced case, in the manner of T06.
|
||||
|
||||
## Open question for design
|
||||
|
||||
Whether intent belongs in the matcher or in the lane. A lane could declare which
|
||||
acts it admits (`read`, `rotate`, `provision`) and `plan` could refuse any act a
|
||||
lane does not declare — stricter, and it fails closed on lanes that say nothing,
|
||||
which is the majority today. That is a catalog schema change and needs its own
|
||||
argument.
|
||||
|
||||
## Confirmed independently, then fixed — 2026-09-09
|
||||
|
||||
`railiance-platform` hit the same defect from the other side while answering the
|
||||
Qonto custody routing question (msg `7c7228ac`). Having stated that the correct
|
||||
verdict is `founder_required` — attended OIDC via `netkingdom` `role=platform-admin`,
|
||||
through the governed `openbao-platform-admin-login` lane — they added:
|
||||
|
||||
> Note this is the same verdict your `warden plan` should have returned; it
|
||||
> returning `autonomous` and offering read transports for a write is a real
|
||||
> defect and WARDEN-WP-0038 is the right place for it. Until that is fixed, do
|
||||
> not let a plan result stand in for this answer.
|
||||
|
||||
Two counterparties reporting the same wrong verdict in two days, one of whom is
|
||||
the write authority being wrongly bypassed, moved this from proposed to shipped.
|
||||
|
||||
### What shipped
|
||||
|
||||
`_need_intent()` classifies a need as `mutate` or `read` by token match, and
|
||||
`_owns_write_authority()` tests `delegation.mode == "permanent"`. A mutating need
|
||||
on a lane ops-warden does not permanently own can no longer reach any branch that
|
||||
returns `autonomous`:
|
||||
|
||||
- lane declares a `rotation` → `founder_required`, with an `approve` act naming
|
||||
the write owner, the rotation method, whether it is automatable, and
|
||||
`warden rotate-guide` as guidance;
|
||||
- lane declares none → `unroutable` with a CCR stub whose `owner_hint` names the
|
||||
write authority.
|
||||
|
||||
**Commands are empty of read transports either way.** That is the half that made
|
||||
the wrong verdict actionable rather than merely wrong: `--out`, `--exec`,
|
||||
`--wrap` and a bare `bao kv get` were being offered as the answer to a write, and
|
||||
a test now asserts none of them appears.
|
||||
|
||||
### The design question in the plan, answered by use
|
||||
|
||||
The plan asked whether intent belongs in the matcher or in the lane. It went in
|
||||
the matcher, with the *ownership* test doing the work that a verb list cannot:
|
||||
SSH certificate issuance is itself a mutating act, and `warden sign` must stay
|
||||
`autonomous`. `delegation.mode: permanent` is what separates ops-warden's own
|
||||
front door from someone else's custody — not the absence of a verb from a list.
|
||||
A regression asserts the SSH lane still proceeds, because a guard that refuses
|
||||
our own lane would be a worse defect than the one it fixes.
|
||||
|
||||
The stricter alternative — lanes declaring which acts they admit, `plan` refusing
|
||||
anything undeclared — is not built. It is a catalog schema change that would fail
|
||||
closed on the majority of lanes, which say nothing today, and it needs its own
|
||||
argument rather than arriving as a side effect of this fix.
|
||||
|
||||
## Recognize explicit attended OpenBao platform administration
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0038-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
2026-10-16 source follow-up: the exact request "attended OpenBao platform
|
||||
administration for reviewed flex-auth signer custody CAS0 and fixed KV metadata"
|
||||
fell through to keyword ranking and selected `openbao-structure-survey` /
|
||||
`approve`. The configuration override required policy/auth-role nouns even
|
||||
though the caller explicitly named attended platform administration. Recognize
|
||||
that explicit intent before keyword ranking. The plan now selects
|
||||
`openbao-platform-admin-login` / `founder_required` / `oidc_login`; the governed
|
||||
reviewed-command transport and identity gate are unchanged. Survey requests
|
||||
remain metadata-only, and a missing administration lane stays unroutable.
|
||||
|
||||
Prepared and tested in an isolated checkout for independent review. This task
|
||||
records source repair only; it neither authorizes nor claims installation,
|
||||
attended login, signer provisioning or full16TSA native acceptance. Integration
|
||||
and the existing platform custody work retain those next actions.
|
||||
|
||||
### Not claimed
|
||||
|
||||
This narrows what `warden plan` will assert; it does not make the tool an
|
||||
authority on custody. railiance-platform's instruction stands and is the right
|
||||
standing posture: a plan result does not substitute for the owner's answer.
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
---
|
||||
id: WARDEN-WP-0039
|
||||
type: workplan
|
||||
title: "Preserve explicit policy caller refusals before credential and CA effects"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
flavor: residual
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
created: "2026-09-08"
|
||||
updated: "2026-10-03"
|
||||
origin: residual
|
||||
origin_ref: HFACT-WP-0001
|
||||
state_hub_workstream_id: "ae44a935-6fca-514c-a385-4550dd2b1fe8"
|
||||
---
|
||||
|
||||
The factory critical-path review reproduced a live HTTP 403 from the reachable
|
||||
PDP for the configured ops-warden caller and a railiance-platform secret read.
|
||||
`check_fetch_policy` treated it as evaluator unavailability and used unknown-zone
|
||||
fail-open. Caller-auth rejection is an explicit refusal, not a transport outage.
|
||||
|
||||
## Preserve explicit authentication and binding refusals
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0039-T01
|
||||
status: done
|
||||
flavor: residual
|
||||
priority: high
|
||||
assignee: the-custodian
|
||||
state_hub_task_id: "eaad08d9-ae47-5f50-8278-ea402a0e2869"
|
||||
```
|
||||
|
||||
HTTP 401 and 403 stop signing and credential fetch irrespective of the outage
|
||||
profile. Do not expose response bodies or alter system identity to bypass the
|
||||
refusal. Preserve configured behavior for genuine evaluator failures. Prove
|
||||
both permissive and closed outage profiles and refusal before child execution.
|
||||
|
||||
## Verify and publish the correction
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0039-T02
|
||||
status: done
|
||||
flavor: residual
|
||||
priority: high
|
||||
assignee: the-custodian
|
||||
state_hub_task_id: "ac85cf00-391c-5c63-b8f4-ed5bd57684e5"
|
||||
```
|
||||
|
||||
Run the policy and proxy suites, retain a value-free live refusal receipt,
|
||||
publish the reviewed source, and verify the installed CLI refuses before any
|
||||
credential transport. A refusal is not a successful credential-read admission.
|
||||
|
||||
The owner installer initially reused a cached wheel despite `--force`, leaving
|
||||
the pre-fix policy code installed. Both Makefile installation targets now use
|
||||
`--reinstall-package ops-warden` to refresh this package from the reviewed source.
|
||||
Verify the installed module as well as the checkout before the live refusal test.
|
||||
|
||||
## Resolve the credential proxy's admitted policy binding
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0039-T03
|
||||
status: done
|
||||
flavor: residual
|
||||
priority: high
|
||||
assignee: the-custodian
|
||||
state_hub_task_id: "8ca28b63-2e04-5333-b635-011b124c1806"
|
||||
```
|
||||
|
||||
Consume the existing native-lane handoff (WARDEN-WP-0033 / SECRETS-WP-0006)
|
||||
and flex-auth caller contract. Establish whether this interim transport needs an
|
||||
admitted dedicated policy route or must finish its native handoff. Retain the
|
||||
refusal until that contract yields positive and wrong-caller/owner/tenant
|
||||
negative evidence. No credential read, secret generation, or policy grant is
|
||||
authorized by this workplan alone. HFACT-WP-0001-T03 consumes this return.
|
||||
|
||||
Validation: 429 tests passed (4 integration tests deselected by the repository default); Ruff passed for changed Python files. Full tests used the declared phase-memory source and an isolated temporary memory store. The focused policy/proxy suite passed 69 tests. The existing authenticated SSH policy probe still returns HTTP 200/ALLOW, decision:f3f7c88f9585582a; the credential-owner request returns 403. No CA issue or credential read was performed by these probes.
|
||||
|
||||
Installed verification: source guard present after refreshed owner installation (`19bb75c`). `warden access forgejo-admin-api-token --exec --field API_TOKEN -- true` exits 4 with explicit HTTP 403 before credential transport or child execution. The previous fail-open warning is absent. The probe requested no output value; no credential was fetched. T01/T02 are complete; T03 owns the remaining exact policy-binding admission.
|
||||
|
||||
**T03 routed 2026-09-09.** Asked `flex-auth` whether an admitted contract exists
|
||||
for a delegated credential read where the caller (ops-warden) and the resource
|
||||
owner differ, since that is exactly the shape drawing the live 403. Three outcomes
|
||||
were named as equally acceptable answers, with no preference stated between the
|
||||
first two: an existing contract to conform to; no contract yet, making this a
|
||||
design question they should raise rather than one ops-warden invents a shape for;
|
||||
or that there should be **no** such contract — the interim proxy transport is
|
||||
itself the defect and the answer is to finish the native handoff
|
||||
(`WARDEN-WP-0033` / `SECRETS-WP-0006`).
|
||||
|
||||
The third is a real possibility and was not argued against. Eleven catalog lanes
|
||||
are ops-warden proxies with a named intended owner precisely because no owner
|
||||
front door exists; if delegated reads should not be made policy-admissible, that
|
||||
shortens WP-0033 rather than blocking it.
|
||||
|
||||
Two fixes were explicitly ruled out in the message rather than left unmentioned:
|
||||
broadening the ops-warden caller binding so it may read other systems' resources,
|
||||
and relabelling `resource.system` as ops-warden so the existing binding matches.
|
||||
The second is worse — it would make the audit trail assert ops-warden owns
|
||||
credentials it deliberately does not, which is the claim `ADR-0002` exists to
|
||||
prevent, achieved by editing a field instead of making an argument.
|
||||
|
||||
The refusal stays in place until an answer yields positive evidence plus
|
||||
wrong-caller, wrong-owner and wrong-tenant negatives. No grant was requested.
|
||||
`secrets-engine` was told this bears on SECRETS-WP-0007-T04 and on how many lanes
|
||||
stay proxied; `gate-house` was told it may reach how the signing lane's
|
||||
approval-consume is built (GH-DEC-2026-005).
|
||||
|
||||
### 2026-09-28 loose-end review
|
||||
|
||||
T03 remains wait and the workplan remains blocked. Re-read the owner's finished
|
||||
FLEX-WP-0026: no admitted delegated-read binding exists, and its native OpenRouter
|
||||
contract explicitly does not close WARDEN-WP-0039-T03. FLEX-DEC-2026-015 also
|
||||
confirms resource.system is runtime policy vocabulary, not a repository rename.
|
||||
Retain the explicit refusal. A native owner route's success does not grant this
|
||||
interim proxy general delegated-read authority; exact positive and caller/owner/
|
||||
tenant negative evidence is still required for the route that replaces it.
|
||||
|
||||
**T03 code side done 2026-10-03 (CUST-WP-0075, founder build-mode directive).**
|
||||
access-engine answered the contract question with a dedicated fetch evaluator:
|
||||
pin `flex-auth-ops-warden-fetch` (access-engine 02b15a7, `values/ops-warden-fetch.yaml`),
|
||||
same caller (ops-warden SA, audience flex-auth), owner systems bound per lane,
|
||||
request shape unchanged. ops-warden now sends `check_fetch_policy` only to the new
|
||||
key `policy.fetch_flex_auth_url`; signing keeps `policy.flex_auth_url`. An unset or
|
||||
unreachable fetch evaluator fails closed with a message naming it, with no fallback
|
||||
to the signing pin and no fail-open. 401/403 keep the existing refusal text.
|
||||
`warden access <need>` names the fetch evaluator on its `gate` (or `policy`) line. Tests:
|
||||
`tests/test_policy_fetch_evaluator.py`, plus updated proxy and refusal tests. Full
|
||||
suite: 494 passed, 4 deselected. Docs: `wiki/OpsWardenConfig.md` ("Two
|
||||
evaluators", tunnel example), `wiki/CredentialRouting.md`, production example.
|
||||
|
||||
Still open (founder go, `needs_human`): deploy the pin (access-engine
|
||||
ADHOC-2026-10-03-T02), add the ops-bridge tunnel (local 19091 → the pin's Service
|
||||
ClusterIP:8080), set `fetch_flex_auth_url: http://127.0.0.1:19091` in the live
|
||||
`~/.config/warden/warden.yaml`, then record exact positive evidence and
|
||||
wrong-owner/caller negative evidence before T03 closes. Until the key is set,
|
||||
every proxied fetch refuses with "secret-read evaluator not configured". Before
|
||||
that change, those fetches got a 403 from the signing pin.
|
||||
|
||||
**T03 done 2026-10-10.** access-engine reported the fetch pin
|
||||
`flex-auth-ops-warden-fetch` live since 2026-10-03 (Helm revision 1). The tunnel
|
||||
`flex-auth-ops-warden-fetch-railiance01` (127.0.0.1:19091) is connected, and the
|
||||
live `~/.config/warden/warden.yaml` carries
|
||||
`fetch_flex_auth_url: http://127.0.0.1:19091`. Receipts were taken with
|
||||
ops-warden's own caller token (SA `ops-warden/ops-warden`, audience
|
||||
`flex-auth`, 10m). The requests are access-engine's fixtures in
|
||||
`examples/ops-warden-fetch/`. Policy decisions only; no credential was read.
|
||||
|
||||
| Case | Result |
|
||||
| --- | --- |
|
||||
| Positive: `forgejo-admin-api-token`, owner railiance-platform | HTTP 200 allow `secret_read_lane_matched`, `decision:014afa428f776db5` |
|
||||
| Unknown need | HTTP 200 deny `unknown_need`, `decision:d792b0d6b1cb8122` |
|
||||
| Wrong owner: `resource.system` ops-warden | HTTP 403 |
|
||||
| Wrong tenant: `tenant:binky` on subject and resource | HTTP 200 deny `wrong_tenant`, `decision:71da3ff8b50dad74` |
|
||||
| Wrong caller: anonymous | HTTP 401 |
|
||||
|
||||
This is the exact positive evidence plus the caller, owner and tenant negatives
|
||||
this task required. The explicit refusal stays for anything the pin does not
|
||||
admit. access-engine closes its ADHOC-2026-10-03-T02 on this reply.
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
id: WARDEN-WP-0040
|
||||
type: workplan
|
||||
title: "Adopt unknown -> fail_closed behind signing-target classification coverage"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
flavor: residual
|
||||
depends_on:
|
||||
- WARDEN-WP-0032
|
||||
- WARDEN-WP-0034
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0032
|
||||
- WARDEN-WP-0034
|
||||
created: "2026-09-09"
|
||||
updated: "2026-09-28"
|
||||
state_hub_workstream_id: "c8ee441e-1be1-5219-910c-e79ff23cc9ec"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0040 — `unknown` → `fail_closed`, in the right order
|
||||
|
||||
security-layer-model v0.8 §6.4 obligation 3 (proposed, 2026-09-06) rules that
|
||||
`unknown` is not a zone and must resolve to `fail_closed`. ops-warden's
|
||||
`pep-stance.yaml` declares `unknown: fail_open` under `ADR-0009`.
|
||||
|
||||
**We agree with the rule.** `history/2026-09-09-layer-model-v08-review.md` records
|
||||
the assent and why our falsifier check failed: the cell governs certificate
|
||||
issuance, not a §5.1 read-only diagnostic, so nothing rescues it.
|
||||
|
||||
**We disagree with adopting it first.** Measured 2026-09-09: of four signing
|
||||
targets, zero resolve to a zone, three are `unknown`, one is `not-applicable`.
|
||||
Flipping the cell today makes flex-auth a hard dependency of essentially every
|
||||
certificate — `ADR-0006`'s rejected configuration, reached by a different route,
|
||||
including the continuity path needed to repair flex-auth itself.
|
||||
|
||||
So: coverage first, then the cell. That ordering is the whole holding of
|
||||
`ADR-0006` and the reason `ADR-0009` replaced a global switch with a zone map.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0040-T01
|
||||
status: wait
|
||||
blocked_on: message-from:ops-bridge
|
||||
blocking_reason: "Warden's own declaration cannot classify the repair-path target workloads; the owner must declare the continuity actor/target and its z2-continuity resolution (see 2026-09-28 review)."
|
||||
priority: high
|
||||
state_hub_task_id: "611f0901-9fb5-5954-8dd0-a860c5f0cbec"
|
||||
```
|
||||
2026-09-30: gate stated. The 2026-09-28 review found the classification is not ours to make (target workloads belong to ops-bridge, the Inter-Hub execution owner and the backup owner), so T01 waits on the owner declaration, same as T02. Qualified per Task Wait Qualifiers v0.1.
|
||||
|
||||
|
||||
**Classify the continuity path before anything else changes.**
|
||||
|
||||
The deadlock is specific and worth naming before it is designed around: flex-auth
|
||||
unreachable → operator needs an SSH certificate to reach the host → target is
|
||||
`unknown` because nobody classified the repair path → `fail_closed` denies it.
|
||||
|
||||
`z2-continuity` exists for this and its stance is `fail_open`, so the fix is
|
||||
classification, not an exception. Determine which actor(s) constitute the
|
||||
repair path, establish whether the declaration is ops-warden's to make (our own
|
||||
`tenancy.yaml` covers ops-warden as a workload; the actors' target workloads may
|
||||
not be ours), and route what is not.
|
||||
|
||||
Blocks T03. Converting the cell with the repair path unclassified is the one
|
||||
outcome this workplan exists to prevent.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0040-T02
|
||||
status: wait
|
||||
blocked_on: message-from:ops-bridge
|
||||
blocking_reason: "Owners of agt-codex-interhub-bootstrap (ops-hub) and agt-state-hub-bridge (ops-bridge) must publish authoritative workload identity declarations; atm-backup-daily declared by activity-core and compiled 2026-10-09 (z2-protected, admission unsatisfied: M1 below M2 floor)."
|
||||
priority: high
|
||||
state_hub_task_id: "54ad4864-7bcf-592e-a187-9239a81a0b11"
|
||||
```
|
||||
|
||||
**Raise signing-target coverage, by asking owners — never by inferring.**
|
||||
|
||||
Three actor resources report `workload_resolution_absent`:
|
||||
`agt-codex-interhub-bootstrap`, `agt-state-hub-bridge`, `atm-backup-daily`.
|
||||
Their owners (ops-bridge and the backup execution unit among them) have not
|
||||
published an authoritative workload identity declaration.
|
||||
|
||||
`ADR-0009` rule 3 forbids closing this with path or repository-name inference,
|
||||
and that prohibition holds under pressure from this workplan specifically —
|
||||
adopting a stricter stance is not a licence to manufacture the membership that
|
||||
makes it survivable.
|
||||
|
||||
Route to each owner with the concrete consequence: while the declaration is
|
||||
absent their actor cannot be issued a certificate during a flex-auth outage once
|
||||
the cell converts. That is a better ask than a generic request to publish a
|
||||
declaration, and it is true.
|
||||
|
||||
Report coverage with `scripts/report_workload_join.py`; this task is done when
|
||||
coverage is stated, not when it reaches a threshold — the threshold is T03's
|
||||
gate, and owners may legitimately decline.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0040-T03
|
||||
status: wait
|
||||
depends_on: [WARDEN-WP-0040-T01]
|
||||
blocking_reason: "Gated on T01 and on layer model v0.8 (or successor) reaching accepted; never convert against a proposed standard."
|
||||
priority: high
|
||||
state_hub_task_id: "93eaf1f2-daaa-5e22-8804-85ca9433571c"
|
||||
```
|
||||
|
||||
**Convert the cell and supersede `ADR-0009`'s unknown row.**
|
||||
|
||||
Gated on T01, and on v0.8 (or its successor) reaching `accepted`. Do not convert
|
||||
against a `proposed` standard.
|
||||
|
||||
`ADR-0009` is `owner: ops-warden`, so changing it means a superseding ADR, never
|
||||
an in-place edit (`.claude/rules/architecture.md`). The superseding record should
|
||||
carry the v0.8 argument rather than restate it: unknown is not a zone, so a §9.3
|
||||
per-zone trade was never made for that request.
|
||||
|
||||
`pep-stance.yaml` is asserted equal to `PolicyConfig.failure_modes` by
|
||||
`tests/test_layer_conformance.py`, so the map and the code convert in one commit
|
||||
or the test fails — which is the property that makes the map worth publishing.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0040-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "222a8c5d-0c0f-5a1d-98d8-02be7dca3358"
|
||||
```
|
||||
|
||||
**Return findings to gate-house and track the transition ask.**
|
||||
|
||||
Sent 2026-09-09 with the review. Two asks, in preference order: obligation 3
|
||||
names a dated transitional state gated on coverage; or failing that, §13.1
|
||||
records classification coverage alongside stance, so a register row cannot read
|
||||
`unknown: fail_closed` while every target is unknown.
|
||||
|
||||
If both are declined, that is an answer and this workplan proceeds unchanged —
|
||||
the cell stays a **declared gap** under §11 with this workplan as its route,
|
||||
which is what the `declared-gap` mark (our own v0.6 finding) exists to express.
|
||||
|
||||
**Answered 2026-09-09 — GH-DEC-2026-011.** Ask 1 declined, ask 2 adopted;
|
||||
standard amended at `net-kingdom@64394e9`.
|
||||
|
||||
Ask 1's refusal is correct and we are not appealing it: a sanctioned transitional
|
||||
`fail_open` is indistinguishable at runtime from the stance the rule forbids, and
|
||||
would make the rule optional at the only moment it costs anything. Ask 2 gave us
|
||||
what we actually needed — §13.1 carries a Coverage column with this repo's
|
||||
figures as its first entries, guarded so that coverage never softens a stance,
|
||||
never gates one, and never makes a non-conformant cell conformant.
|
||||
|
||||
The reversal condition on that column binds ops-warden first, since the column
|
||||
exists because we asked: if a row is ever argued conformant *because* its coverage
|
||||
is low, the column comes out. Our row reads non-conformant and low-coverage, and
|
||||
the second is not a defence of the first.
|
||||
|
||||
gate-house confirmed explicitly that they are **not** asking for the cell to be
|
||||
flipped before coverage exists, and that this workplan's order is right. The cell
|
||||
stays a declared gap under §11 with WP-0040 recorded as its route — the outcome
|
||||
this task named as acceptable if both asks were declined, reached with one of them
|
||||
adopted.
|
||||
|
||||
T01–T03 are unchanged and still gate the conversion. Coverage is now measured
|
||||
rather than asserted (`scripts/report_coverage.py`), so T02's reporting obligation
|
||||
has a tool behind it and the published figure cannot drift from the register's.
|
||||
|
||||
### 2026-09-28 loose-end review
|
||||
|
||||
T04 is done: GH-DEC-2026-011 already answered both transition asks on September 9;
|
||||
the accepted coverage column and declared-gap disposition are recorded above.
|
||||
No additional response is required to meet that task's acceptance criterion.
|
||||
|
||||
T01/T02 now wait; the workplan is blocked. Re-ran both coverage reports:
|
||||
signing targets = 0 resolved / 3 unknown / 1 not-applicable; routing lanes =
|
||||
3 resolved / 20 unknown / 15 not-applicable. Refreshed pep-stance.yaml's measured
|
||||
date. These figures describe the checked-in registry and local owner declarations,
|
||||
not a live PDP query. No zone membership was inferred or changed.
|
||||
|
||||
The exact missing workload resolutions are `ops-bridge-tunnel` for
|
||||
`agt-state-hub-bridge`, `codex-interhub-bootstrap` for
|
||||
`agt-codex-interhub-bootstrap`, and `backup-daily` for `atm-backup-daily`.
|
||||
The seed inventory's `adm-example` is not an admitted repair actor.
|
||||
Warden's own workload declaration cannot classify those target workloads.
|
||||
T01 needs an owner-declared continuity actor/target and its authoritative
|
||||
z2-continuity resolution; T02 retains the owner-routing/declaration follow-up
|
||||
(ops-bridge, the Inter-Hub execution owner and the backup execution owner).
|
||||
Without it, changing unknown to fail_closed would deny their issuance during a
|
||||
PDP outage. Coverage reporting is complete, but owner coordination is not.
|
||||
|
||||
T03 also remains gated on standard acceptance: the local authoritative
|
||||
net-kingdom/canon/standards/security-layer-model_v0.8.md still says proposed.
|
||||
No superseding ADR or runtime stance change is warranted before these gates.
|
||||
|
||||
### 2026-09-30 owner asks sent
|
||||
|
||||
Routed the concrete-consequence ask (T01 classification + T02 declaration) to `ops-bridge` (agt-state-hub-bridge), `ops-hub` (agt-codex-interhub-bootstrap; owner unconfirmed, asked to name the owner if not theirs) and `railiance-platform` (atm-backup-daily; same caveat). Declining is an accepted answer. No membership inferred. T01/T02 stay `wait` on these replies.
|
||||
|
||||
### 2026-10-08 owner replies recorded
|
||||
|
||||
`atm-backup-daily`: railiance-platform declined in its replies of 2026-10-02
|
||||
(msgs 53234ede, a3691df9). It declares only the credential lane
|
||||
`railiance-backup-offsite-lane`, and no workload in railiance-platform has that
|
||||
name. It names activity-core as the declaring owner, because activity-core is
|
||||
the source repo of `daily-cnpg-option-a-backup`. It classifies the actor as
|
||||
**ordinary**, not z2-continuity repair-path. activity-core will not declare
|
||||
without founder confirmation (ACTIVITY-WP-0042-T03, decision 89f1058f). So this
|
||||
actor now waits on that founder decision, not on railiance-platform. No
|
||||
membership is inferred. `agt-state-hub-bridge` (ops-bridge) and
|
||||
`agt-codex-interhub-bootstrap` (ops-hub) are still unanswered.
|
||||
|
||||
2026-10-08 (later): the founder confirmed in session that activity-core's
|
||||
`daily-cnpg-option-a-backup` worker is the `atm-backup-daily` unit, and that it
|
||||
is classed as ordinary. The confirmation was relayed to activity-core for
|
||||
ACTIVITY-WP-0042-T03. Decision 89f1058f (D2) was deliberately left open,
|
||||
because it also gates production ArgoCD go-aheads. `atm-backup-daily` now waits
|
||||
only on activity-core publishing its declaration.
|
||||
|
||||
### 2026-10-09 atm-backup-daily compiled
|
||||
|
||||
activity-core published `declarations/backup-daily/tenancy.yaml` (c1533fe).
|
||||
zone-engine's `resolve_zones.py` resolves it with the
|
||||
`netkingdom-build-v0.1` profile:
|
||||
|
||||
- declared zone: `z2-protected` (ordinary, not z2-continuity)
|
||||
- admission: `unsatisfied`, reason `M1_below_M2_zone_floor`
|
||||
- effective zone: `unknown`
|
||||
|
||||
The resolved view is committed as `registry/flex-auth/zone-resolutions.json`,
|
||||
and the snapshot was rebuilt from it. Resolution is no longer absent. The actor
|
||||
stays `unknown` because the owner declared M1, below the M2 floor, which is
|
||||
accurate rather than a gap ops-warden may close. Coverage, stated as T02
|
||||
requires: signing targets 0/3 resolved, 3 unknown, 1 not-applicable. The
|
||||
figure is unchanged because `report_coverage.py` counts effective zones.
|
||||
`atm-backup-daily` now waits on owner M2 evidence. It does not wait on a
|
||||
declaration. Still unanswered: `agt-state-hub-bridge` (ops-bridge) and
|
||||
`agt-codex-interhub-bootstrap` (ops-hub).
|
||||
|
||||
> 2026-10-11: demoted to `flavor: residual` / `backlog` by founder-authorized triage — off the
|
||||
> critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged;
|
||||
> promote back when demand or risk appears. See the-custodian
|
||||
> `history/20261011-netkingdom-security-progress-assessment.md`.
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
id: WARDEN-WP-0041
|
||||
type: workplan
|
||||
title: "Draft catalog lane scaffolding with platform-owned credential rendering"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
flavor: implementation
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
created: "2026-10-03"
|
||||
updated: "2026-10-04"
|
||||
depends_on: []
|
||||
state_hub_workstream_id: "eb42b59c-1e32-5e1b-917d-34625f7a041d"
|
||||
---
|
||||
|
||||
Accepts the ops-warden portion of P4 from CUST-WP-0075, proposal message
|
||||
`79549660-4fc8-44d5-989e-074f6c7b6f07`. The platform owns its renderer and
|
||||
CCR schema; no production act or approval is included here.
|
||||
|
||||
## Establish the catalog and platform seam
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0041-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "85bfd209-d2f1-59e4-aa02-e8e374598538"
|
||||
```
|
||||
|
||||
Reviewed existing catalog validation, plan CCR stub, promotion checklist and
|
||||
platform CCR rendering. The stub does not scaffold; platform rendering already
|
||||
exists for reviewed CCRs. Proposed exact owner seam, inputs, fail-safe draft
|
||||
outputs and offline acceptance in `wiki/CatalogLaneScaffoldContract.md`.
|
||||
Platform's matching owner task is `RPF-WP-0050-T04`.
|
||||
|
||||
## Implement offline draft catalog and playbook generation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0041-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "68bf72d8-a798-5e88-bfda-79b8910f7cda"
|
||||
```
|
||||
|
||||
Implement the ops-warden portion of the seam proposal: deterministic staging
|
||||
output, validated catalog fields, draft-only defaults, collision refusal,
|
||||
explicit workload unknowns and risk, no secret inputs, no credential execution.
|
||||
Add meaningful rejection/round-trip fixtures; reuse catalog validation. Do not
|
||||
write platform-owned artifacts or invent its CLI. The local fragment generator
|
||||
can progress independently while platform contract review is pending.
|
||||
|
||||
## Verify the accepted cross-owner scaffold
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0041-T03
|
||||
status: done
|
||||
priority: medium
|
||||
depends_on:
|
||||
- WARDEN-WP-0041-T02
|
||||
- RPF-WP-0050-T04
|
||||
state_hub_task_id: "33587361-2b8a-5540-9c4f-d7b4f8ef25e0"
|
||||
```
|
||||
|
||||
Integrate through reviewed owner references and demonstrate one exact KV-v2
|
||||
workload-read fixture end to end. Record both owner commits and validation
|
||||
results. Generation success alone does not admit or activate a lane. Update
|
||||
`warden plan`'s unroutable guidance only once a real supported command exists.
|
||||
|
||||
## Report owner uptake and gates
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0041-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "4bc926af-04d4-5a27-9578-d2f83c0ecf9c"
|
||||
```
|
||||
|
||||
Return the scoped P4 acceptance and this live owner record to the-custodian's
|
||||
original proposal thread. Existing admission, approval, identity confirmation,
|
||||
attended values and deployment evidence gates remain; no secret read or
|
||||
production action was taken. Source/knowledge receipt is in the seam document.
|
||||
|
||||
## Offline delivery acceptance — 2026-10-04
|
||||
|
||||
T02 and T03 completed the bounded draft-generation scope. Actual-source
|
||||
generator/routing/plan tests: 139 passed. Both actual owner CLIs staged the
|
||||
paired synthetic fixture; lane/consumer/owner/risk/CCR pointer and manifest
|
||||
digest match, unknown workload remains unknown, catalog execution is disabled,
|
||||
CCR remains proposed with empty review, auth claims unconfirmed, frontdoor
|
||||
pending/unresolvable and evidence not executed. Independent platform owner
|
||||
verification remains separately attributed in the receipt.
|
||||
|
||||
Source implementation commits: ops-warden `dfe436e4e05610cae96085dadd582e5a63525580`;
|
||||
railiance-platform `f5b7ff5118326f66be8ecd8330d4cda9e4d94520`.
|
||||
Evidence: `docs/evidence/2026-10-04-catalog-scaffold.json`.
|
||||
`warden plan` now names the supported offline command for unroutable needs.
|
||||
The workplan finishes its local draft scaffold contract; CCR approval, binding
|
||||
confirmation, attended values, deployment and actual capability receipts
|
||||
remain separate lane-activation work, never implied by fixture acceptance.
|
||||
No unfinished in-scope implementation or residual is parked by this closure.
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
id: WARDEN-WP-0042
|
||||
type: workplan
|
||||
title: "Route the OpenBao existing-structure survey to ops-mason"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
flavor: implementation
|
||||
owner: claude
|
||||
topic_slug: netkingdom
|
||||
created: "2026-10-05"
|
||||
updated: "2026-10-05"
|
||||
depends_on: []
|
||||
state_hub_workstream_id: "bd5edebd-2988-5685-881e-13931464f92f"
|
||||
---
|
||||
|
||||
ops-mason construction plans need an existing-structure survey (section 2)
|
||||
built from live OpenBao metadata. Founder decision: ops-warden routes,
|
||||
ops-mason surveys. ops-mason implements `scripts/plan-survey.py` under its
|
||||
own `ops-mason-build` grant (`ops-mason/MASON-WP-0008`). ops-warden gets no
|
||||
survey code and no token, per the no-double-source rule
|
||||
(`WARDEN-WP-0010`, `docs/adr/ADR-0001-catalog-is-a-pointer-layer.md`).
|
||||
|
||||
## Add the pointer-only catalog entry
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0042-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ca8cd3e9-83ac-5732-8ec4-525e5ce1b113"
|
||||
```
|
||||
|
||||
`registry/routing/catalog.yaml` entry `openbao-structure-survey`: owner
|
||||
`ops-mason`, `warden_executes: false`, `exec_capable: false`, no `steps`,
|
||||
native delegation to ops-mason, lane `ceremony` (the grant is a founder act),
|
||||
`risk: high` (the grant can write policies and auth roles), `auth_method`
|
||||
naming the ops-mason grant, `exec_owner`/`exec_command` pointing at the
|
||||
survey script, `canon_ref` at `ops-mason/docs/construction-plan-format.md`.
|
||||
Short pointer playbook `wiki/playbooks/openbao-structure-survey.md`.
|
||||
|
||||
## Verify routing offline
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0042-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "05bb75bd-2de9-55d5-8bc8-41b306ddcf16"
|
||||
```
|
||||
|
||||
`make test` passes, including catalog validation and layer conformance.
|
||||
`warden access "openbao structure survey"`, `warden access "construction
|
||||
plan section 2"` and `warden route find "existing policies auth roles
|
||||
survey"` resolve to the entry; `warden plan` returns `founder_required`
|
||||
with the survey command; `warden access ... --exec` refuses (not
|
||||
exec_capable).
|
||||
Loading…
Add table
Add a link
Reference in a new issue