Skip to content

Perf/multiplatform build speedup#93

Merged
mikeappsec merged 6 commits into
mainfrom
perf/multiplatform-build-speedup
Jul 12, 2026
Merged

Perf/multiplatform build speedup#93
mikeappsec merged 6 commits into
mainfrom
perf/multiplatform-build-speedup

Conversation

@mikeappsec

Copy link
Copy Markdown
Owner

No description provided.

mikeappsec and others added 3 commits July 12, 2026 12:44
docs.yaml has been failing on main for over a week (confirmed via
`gh run list` and reproduced locally with `mkdocs build --strict`), from
issues introduced in a 2026-07-02 batch commit that never made it into
CI's radar:

- 5 broken links: one relative path to scripts/verify-phase-c.sh that
  doesn't resolve from its page's depth (now an absolute GitHub URL, per
  the project's own stated convention for source-tree references), and 4
  stale heading anchors -- each assumed an em-dash in the heading
  slugifies to a double hyphen, but mkdocs' actual slugifier collapses it
  to one. Verified the real generated anchor IDs by building the site and
  grepping the rendered HTML rather than guessing.
- 6 orphaned pages that existed on disk but were never added to
  mkdocs.yml's hand-curated nav, so were unreachable from the published
  site: architecture-separation.md, uiinteraction.md,
  cookbook/install-lwauth-mcp-server.md, design/cache-layer-redesign.md,
  design/mcp-enterprise-auth.md, design/mcp-server.md. All six are
  genuine, substantive documentation, not scratch notes -- added to nav
  under Architecture/Cookbook as appropriate. Notably,
  cache-layer-redesign.md is marked "Accepted ... implemented" and
  explicitly supersedes cache-architecture.md (which *was* in nav) --
  added a superseded-by pointer at the top of the older doc so the
  published architecture section doesn't read as current when it isn't.

`mkdocs build --strict` is fully clean after these fixes (was previously
aborting with 7 warnings).

Separately, closed a real accuracy gap in supply-chain.md: it documented
`cosign verify ghcr.io/mikeappsec/lightweightauth:1.2.0` as if the
data-plane image were signed, but neither build.yaml nor release.yaml
ever actually signed it -- the example would have failed for anyone who
ran it. Added cosign signing to both the stock and FIPS data-plane image
builds (matching the pattern already used for the control-plane image),
and added the control-plane image's own verification example, which the
doc was missing entirely.

Also added docs/modules/saml.md and docs/modules/scim.md -- both modules
had pkg-level READMEs but no corresponding site-published reference page,
unlike every other identifier module.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found by an audit cross-checking docs/modules/*.md against the actual Go
source (config structs, validation logic) rather than trusting the docs'
own claims:

- apikey.md: hashed.entries example used field name `digest:`; the code
  reads `hash:` -- following the doc as written would break.
- hmac.md: YAML example put identifier-specific fields at the wrong
  nesting level (outside `config:`); ModuleSpec only recognizes
  name/type/config, so the example as written wouldn't parse. Also
  documented an unstated validation: decoded secrets must be >= 16 bytes.
- jwt.md: removed a false claim that `issuerUrl` "auto-discovers JWKS via
  /.well-known/openid-configuration" -- no such discovery exists in code;
  `jwksUrl` is unconditionally required, `issuerUrl` only pins the `iss`
  claim.
- jwt-issue.md: the example's own `algorithm: ES256` doesn't work --
  parseAlg only implements HS256/384/512 and RS256/384/512. Also fixed a
  commented-out EC PEM key example that would fail to parse (`key:` is
  HS*-only raw secret, `privateKeyFile:` is RS*-only and requires
  PKCS#1/PKCS#8 RSA specifically) and removed a references-section
  pointer to EdDSA (RFC 8037), which isn't supported either.
- mtls.md: default `header` value shown in lowercase; actual Go default
  is `X-Forwarded-Client-Cert` (cosmetic, headers are case-insensitive,
  but the literal value was wrong).
- dpop.md: `pinnedKeys` (proof key pinning independent of the token's own
  `cnf.jkt` claim) is fully implemented but was entirely undocumented.

Also: docs/modules/README.md's index tables were missing 6 registered
modules -- saml, scim, spicedb, and wasm already had page files, just
never linked from the index; idjag and assurance had no doc page at all.
Added docs/modules/idjag.md and docs/modules/assurance.md, and while
fixing the tables noticed grpc-plugin (registered as identifier +
authorizer + mutator) was also missing from the authorizers and mutators
tables, not just wasm -- fixed both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d-code claims

Systemic fix: the top-level AuthConfig YAML key is `response`, not
`mutators` (internal/config/config.go) - corrected across every doc
still using the old name.

Cookbook: replaced a nonexistent `lwauthctl hash-apikey`/`apikey hash`
command with the real go run + apikey.HashKey approach; rewrote
apikey-static-backend.md's fabricated config schema (keys/store/claims
don't exist - real shape is static/hashed.{entries,file,dir});
corrected fabricated lwauthctl audit/validate/diff/explain output
formats; removed a fabricated Go-template engine ({{ .Claims }}/
joinClaims) from header-add/header-remove docs - the real mutator only
supports ${sub}/${claim:x} literal substitution; fixed the admin
revoke body shape and status code (200->202) and documented that the
API has no field to target kid:/serial:/sid: revocation keys directly;
fixed wrong AuthConfig keys in install-lwauth-mcp-server.md.

Operations: removed three fake Prometheus metrics and a fake
/admin/key-states endpoint; fixed caBundlePath -> trustedCAFiles;
documented that HMAC/API-key "rotatable key with notBefore/notAfter"
support is fully implemented but never wired into the running
identifier (dead code); fixed fips.md's build-vs-verify stage
description; fixed envoy.md's stale references to the removed
lightweightauth-proxy component; fixed three fabricated test citations
and cleaned up widespread mojibake in security/v1.0-review.md.

Design: fixed README.md's garbled leftover commit-message text;
updated CONTRIBUTING.md's stale "early M0" status; fixed swapped file
names and a stale function signature in ARCHITECTURE.md; fixed
DEPLOYMENT.md's CRD count (found a real 4th CRD, PolicyBinding) and
removed Helm values that don't exist; added status notes to DESIGN.md
G10 and UIDESIGN.md clarifying the management UI / control plane is
shipped, not a future proposal.

Also added env/extraVolumes/extraVolumeMounts passthrough to the
data-plane Helm chart, mirroring the control-plane chart's existing
pattern, since several cookbook recipes already assumed it existed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@strix-security

strix-security Bot commented Jul 12, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for 3f682e5.


Reviewed by Strix
Re-run review · Configure security review settings

mikeappsec and others added 3 commits July 12, 2026 22:27
Continuation of the documentation audit. Every one of these 18
module docs had verified drift from the code they describe:

- composite.md: entire config schema was fabricated (mode/children
  don't exist; real shape is anyOf/allOf lists, only two modes not
  four)
- opa.md: fabricated bundle-loading (disk/HTTP) that doesn't exist;
  wrong field name (module: vs real rego:)
- openfga.md: check.{user,relation,object} are Go text/template
  strings, not CEL as claimed; fabricated decision-caching layer that
  doesn't exist in the authorizer
- spicedb.md: wrong field casing (resourceID/subjectID vs real
  resourceId/subjectId), fabricated template methods
  (PathSegment/Header/Query), fabricated tls: block
- rbac.md: fabricated rolesFrom prefixes (source/subject don't exist),
  fabricated "*" wildcard, wrong deny-reason text
- cel.md: fabricated variables: config block, wrong header binding
  type, misleading runtime-error-denies claim (actually maps to 503)
- bundle.md: CLI examples used positional args that don't work (real
  CLI is flag-only); fabricated Helm bundleRef/bundlePullSecret
  feature; fabricated registry-inspect capability
- federation.md: reframed as implemented-but-not-wired-in (pkg/federation
  is real and tested but nothing in cmd/lwauth or cmd/lwauth-controlplane
  ever constructs it, and there's no federation: key on AuthConfig);
  fixed missing peers[].clusterId and the federationKey yaml:"-" issue
- wasm.md: maxFuel/maxMemoryMB are parsed but never enforced (fuel
  metering doesn't exist; memory is a hardcoded global 16MiB, not
  per-module); missing pluginBaseDir restriction
- plugin-grpc.md: corrected the signing-default claim (TCP addresses
  without insecure:true silently default to verify, not disabled)
- session.md: primary config example was entirely broken (session:
  should be cookie:, ttl should be maxAge, {fromEnv:...} syntax
  doesn't exist anywhere, cookieMaxBytes isn't exposed by oauth2,
  wrong error sentinel for tampered cookies)
- oauth2.md: wrong field names (ttl->maxAge, refreshLeeway mis-nested,
  postLogoutRedirectUrl->postLogoutPath), wrong userinfo response
  shape, fabricated MemoryStore swap capability
- revocation.md: missing enabled:true, wrong negativeCache shape (real
  field is flat negCacheTTL), dead maxEntries field, fake admin API
  "key" field, wrong reaper interval and Valkey command, wrong metric
  name/labels
- upstream.md: fabricated flat resilience: schema - budget fields are
  nested inside retries:, not a separate block; corrected unverifiable
  chaos-test numbers
- ratelimit.md: fabricated metric label (real counter is dedicated
  lwauth_ratelimit_denied_total, not lwauth_decisions_total); fabricated
  lwauthctl explain rate-limit output (explain has no rate-limit stage)
- cache-memory.md: fabricated config fields (maxEntries/defaultTtl/
  decisionTtl/introspectionTtl don't exist), wrong source path, wrong
  default size (10k not 50k)
- cache-valkey.md: wrong source path, wrong keyPrefix/key defaults
- configstream.md: wrong proto field numbers, stale claim about an
  unresolved concurrency bug that was actually fixed in v1.1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Final phase of the documentation audit. Every one of these package
READMEs had verified drift from the code they describe, ranging from
compile bugs in "Usage" examples to entire fabricated APIs.

Systemic bug fixed across ~15 files: module.Build{Identifier,
Authorizer,Mutator} examples had type name and instance name
swapped (real signature is (typeName, instanceName, cfg, ...) —
would fail with "unknown type" as originally written.

Severely fabricated (entire APIs/schemas invented, not just field
drift):
- buildinfo: Get()/Info struct don't exist; real API is package-level
  vars + zero-arg funcs (FIPSEnabled(), GoVersion(), Summary())
- lwauthd: Run() doesn't take a context (blocks on OS signals
  instead); ~20 of the real ~30 Options fields were undocumented,
  4 documented fields (MetricsAddr/HealthAddr/CRDWatch/TLS) don't exist
- pkg/module: fabricated `lwauth:` struct-tag validation/defaulting
  system (required/default=/min=/max=) - DecodeConfig only does
  unknown-key rejection + JSON type coercion, no defaulting
- observability/audit: fabricated Emit()/AsyncSinkConfig/NewStdoutSink/
  Event fields/EventType enum; fabricated sinks/sampling config schema
  (the real, wired AuthConfig audit: key only has redaction/dataResidency)
- observability/tracing: fabricated NewProvider/ProviderConfig/Shutdown
  (real API is two functions: Tracer(), TraceIDFromContext()); fabricated
  tracing: config block, not wired into AuthConfig at all; 3 of 4 span
  attribute names were wrong
- upstream: fabricated flat resilience: schema (real shape nests the
  retry budget inside retries:), wrong Do() signature, fabricated
  backoff jitter claim (deterministic, no jitter)

Also fixed: dead-code rotation features documented as live (apikey,
hmac, introspection, oauth2 - keyrotation.KeySet fully implemented but
never wired into factory()); mtls's CA-bundle-hot-reload claim (same
dead-code pattern - CABundleWatcher exists but factory() never uses
it); dpop's real, live pinnedKeys feature was undocumented; several
pointer-vs-value and argument-count compile bugs (session, ratelimit,
revocation, keyrotation, connpool, configstream, client/go, federation,
bundle); wrong field names/casing (plugin/grpc's hmacSecret vs secret,
federation's clusterId/revocationTtl/tlsCaFile casing, apikey's argon2
memory figure off by 1024x); a stray top-level `mutators:` key in
mutator/jwtissue and mutator/headers examples (same systemic bug fixed
throughout docs/ earlier in this audit).

pkg/observability/metrics/README.md was the one file in this batch
with zero verified drift - confirmed as the trustworthy canonical
metrics reference.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…odule docs

lwauth performs no \${VAR} environment-variable expansion anywhere in
AuthConfig - confirmed by inspecting internal/config/loader.go and
pkg/secrets: the only real secret-injection mechanisms are (1)
secretRef: "<scheme>://<path>[#field]" (currently only vault://),
resolved at compile time by resolveMapSecrets, which recursively
walks every identifier/authorizer/response module's config map plus
cache.password/cache.sharedHmacKey/revocation.password/caches[].password
specifically, or (2) templating the AuthConfig YAML itself at the
deployment-pipeline layer (Helm/Kustomize/CI) before lwauth ever
parses it. Notably rateLimit.distributed.password is NOT covered by
secretRef - that top-level block is never walked by the resolver, so
only pipeline-templating works there.

Added an accurate warning at each affected field across 20 files
(14 cookbook recipes, module docs for cache-valkey, oauth2,
oauth2-introspection, openfga, ratelimit, revocation, saml, scim,
spicedb, plus QUICKSTART.md and design/cache-architecture.md),
pointing at the real secretRef mechanism where it applies and calling
out the rateLimit exception where it doesn't.

While fixing these, found and fixed several adjacent bugs in the same
blocks: dpop-sender-binding.md's entire replayCache: config was
fabricated (real field is replayCacheSize, which is itself parsed but
never read - the actual cache comes from a named "replay" pool in the
top-level caches: block); header-stamping-identity-forwarding.md's
jwt-issue examples used audiences:/expiry: instead of the real
audience:/ttl:; spicedb-rebac-authorization.md had the same
resourceID/subjectID casing and fake tls:/PathSegment-method bugs
already fixed in the module doc, plus a consistency-level table
listing an unsupported third mode; oauth2-introspection-caching.md's
entire config schema was wrong throughout (introspectionUrl should be
url, a fabricated header:/scheme:/timeout: trio, a fabricated nested
cache: block with per-tier MaxSize fields that don't exist, wrong
resilience.retries.maxRetries vs the real .max, fabricated
lwauth_introspection_* metrics, and fake lwauthctl explain output);
docs/operations/dpop-key-rotation-runbook.md had the same
introspectionUrl bug nested inside a dpop identifier's inner config.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mikeappsec
mikeappsec merged commit c83b21b into main Jul 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant