Repository navigation
fix: ru-blocked WARP rule-sets, per-inbound artifacts, Caddy-edge HSTS/TLS issuer visibility, audit test hardening - #988
Conversation
…edge HSTS/TLS issuer visibility, and harden audit tests - renderer/warp: route geoip:ru-blocked and geosite:ru-blocked to the published runetfreedom russia-v2ray-rules-dat rule-sets instead of the nonexistent/misrouted SagerNet remaps (#763 #778 #779) - routing: EnsureDatSource provisions only the dat files enabled matchers consume; geoip:private now pulls geoip.dat (#764) - generatedconfig: per-inbound hysteria2/olcrtc artifacts use glob subpaths; exact generated-path and staged-path matching; ghost aggregate configs and bare @.service actions removed (#780 #855) - api/renderer: emit HSTS for the Caddy-managed panel TLS edge (#902) - api/runtime/caddycert: /api/tls reports managedBy/issuerSource/ issuerKind so ACME->internal fallback stays visible; spec + SDK regenerated (#906) - caddycapabilities: production Probe routes through parseModuleList (#882) - audit test hardening across settings/routing/renderer/protocols/ generatedconfig/livevalidation/bindregistry/api (#820-#971 set) Refs #763 #764 #778 #779 #780 #820 #821 #822 #823 #824 #836 #844 #845 Refs #846 #852 #853 #855 #856 #857 #861 #863 #882 #884 #894 #895 #901 Refs #902 #906 #915 #918 #920 #959 #962 #971
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head a5962df2)
Verdict: COMMENT — would APPROVE after the web client regen below. Own-PR blocks APPROVE.
Blocker
- Frontend generated-client drift (CI
frontendfailed).docs/openapi.yamlandsdk/gogainedTLSCertInfo.managedBy/issuerSource/issuerKind, but noweb/orval outputs were committed. CI regenerates and diffs:web/src/api/generated/models/tLSCertInfo.tsweb/src/api/generated/msw/models/tLSCertInfo.msw.tsweb/src/api/generated/zod/runtime/runtime.zod.ts
Zeroweb/files appear in this PR. Job: https://github.com/mikkelchokolate/Veil/actions/runs/35919208198/job/107378529893 — regenerate (orval/ the repo’s frontend generate step) and commit the outputs.
Looks good
- WARP
ru-blocked(#763/#778/#779):geoRuleSetURLcorrectly routes both kinds torunetfreedom/russia-v2ray-rules-datrelease.srsURLs; ordinary codes stay on SagerNet. Closes the 404/geoip-rumisroute. - DAT provisioning (#764):
EnsureDatSource/rulesNeedRouteDatattach only neededgeoip.dat/geosite.dat(incl.MatchPrivateIP→ geoip). - Artifact catalog (#780/#855): exact + glob
MatchesGeneratedPath/LivePathForStagedConfig; per-inbound hysteria2/olcrtc globs; installer reports the hysteria2 dir. - HSTS (#902): Caddyfile edge header + Go middleware
tlsEdgewhenpanelAccess=caddy; IP still skipped on the Go path. - /api/tls issuer visibility (#906):
managedBy/IssuerSource/IssuerKindwired throughtlsCertInfo+caddycert.Pair. - Caddy Probe (#882): production path goes through
parseModuleList. - Test hardening matches the stated false-green closures.
Mild (non-blocking)
- Caddy HSTS vs IP exclusion:
RenderPanelCaddyfilealways emits HSTS withpreload; Go middleware still skips IP hosts. If Domain were ever an IP literal underpanelAccess=caddy, the edge would still advertise HSTS (browsers usually ignore HSTS for IPs). Slight mismatch with “IP hosts remain excluded.” panelAccesscase: HSTS usesEqualFold(..., "caddy");tlsCertInfousesaccess != "caddy". Align to EqualFold.IssuerKind:HasPrefix(issuerName, "acme")covers Let’s Encrypt storage dirs; other ACME issuer dir names become"other"(acceptable).
CI (at review time)
- failure:
frontend(blocker above) - success: filesystem-faults, multi-process, sigkill, analyze (actions)
- in_progress: lint, image-build, analyze (go), analyze (javascript-typescript)
- skipped: package-smoke*, test, e2e, browser-e2e, install-acceptance, privilege-boundary
- CodeQL neutral
Fix the orval commit and this is merge-ready from a code-review standpoint (pending remaining checks).
| type: string | ||
| description: >- | ||
| Issuer classification — "acme", "internal" (Caddy local CA, an | ||
| untrusted fallback), or "other". |
There was a problem hiding this comment.
Blocker: OpenAPI/sdk/go were updated for these three fields, but the frontend orval outputs were not committed. CI frontend fails on generated-client drift for web/src/api/generated/models/tLSCertInfo.ts, the MSW twin, and web/src/api/generated/zod/runtime/runtime.zod.ts. Please regen and commit those files (see job 107378529893).
| # The panel is only ever served over HTTPS at this edge; pin HSTS here too — | ||
| # the Go handler behind reverse_proxy sees plain loopback HTTP and cannot | ||
| # detect the public TLS transport itself (#902). | ||
| header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" |
There was a problem hiding this comment.
Mild: This always emits HSTS (includeSubDomains; preload) for whatever Domain is. The Go middleware still skips IP hosts. If an IP literal can ever be the Caddy site address under panelAccess=caddy, consider matching that IP exclusion here for consistency with #902.
| access = strings.TrimSpace(settings.PanelAccess) | ||
| } | ||
| if access != "caddy" { | ||
| return info |
There was a problem hiding this comment.
Mild: Prefer strings.EqualFold(access, "caddy") here to match router_composition’s HSTS tlsEdge wiring.
The generated web client drifted from docs/openapi.yaml (source + issuerKind on TLSCertInfo) — the frontend drift gate regenerated dirty output. Commit the orval output. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 7c398494)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Prior blocker cleared
Frontend generated-client drift is fixed by commit 7c398494 ("Regenerate web client after TLSCertInfo OpenAPI additions"). Orval outputs now include managedBy / issuerSource / issuerKind on:
web/src/api/generated/models/tLSCertInfo.tsweb/src/api/generated/msw/models/tLSCertInfo.msw.tsweb/src/api/generated/zod/runtime/runtime.zod.ts
CI frontend on this head: success.
Looks good (re-checked)
- WARP
ru-blocked(#763/#778/#779):geoRuleSetURLroutes both kinds torunetfreedom/russia-v2ray-rules-dat.srsURLs; ordinary codes stay on SagerNet. Tests lock full URL + tag contract and forbid the old 404/geoip-rupaths. - DAT provisioning (#764): selective
geoip.dat/geosite.datattach still sound. - Artifact catalog (#780/#855): exact + glob
MatchesGeneratedPath/LivePathForStagedConfig; per-inbound hysteria2/olcrtc globs; bare template units not advertised as restartable. - HSTS (#902): Caddyfile edge header + Go middleware
tlsEdgewhenpanelAccess=caddy; Go path still skips IP hosts (tested). - /api/tls issuer visibility (#906):
ManagedBy/IssuerSource/IssuerKindwired throughtlsCertInfo+caddycert.Pair/IssuerKind. - Caddy Probe (#882): production path through
parseModuleList. - Test hardening matches the stated false-green closures.
Mild (non-blocking; same as prior review)
- Caddy HSTS vs IP exclusion:
RenderPanelCaddyfilealways emitsStrict-Transport-Securitywithpreload; Go middleware still skips IP hosts. If Domain were an IP literal underpanelAccess=caddy, the edge would still advertise HSTS (browsers usually ignore HSTS for IPs). Slight mismatch with “IP hosts remain excluded.” panelAccesscase: HSTS wiring usesEqualFold(..., "caddy");tlsCertInfostill usesaccess != "caddy". Align to EqualFold for consistency.IssuerKind:HasPrefix(issuerName, "acme")covers Let’s Encrypt storage dirs; other ACME issuer dir names become"other"(acceptable).- Branch currency:
mergeStateStatus=BEHIND— main is ahead by 2 commits (5eacacd3,8defe84d). No clash with this PR’s surface; update-branch when convenient.
CI (at review time, head 7c398494)
- success: frontend, lint, filesystem-faults, multi-process, sigkill, image-build, analyze (go/js-ts/actions), CodeQL
- queued (longer suite): test, e2e, browser-e2e, privilege-boundary, install-acceptance (amd64/arm64), package-smoke-matrix (amd64/arm64)
No code blockers. Merge-ready from a review standpoint once remaining checks settle (and after updating the branch if desired).
| if access == "" { | ||
| access = strings.TrimSpace(settings.PanelAccess) | ||
| } | ||
| if access != "caddy" { |
There was a problem hiding this comment.
Mild / non-blocking: HSTS edge detection uses strings.EqualFold(..., "caddy") while this gate is a case-sensitive access != "caddy". Aligning to EqualFold would keep panelAccess handling consistent if an operator ever stores a mixed-case value.
A dial-level helper failure proves the promote request never reached the helper, so no artifact could have been published. Previously such a job was retained in recovery_pending forever: exact-phase recovery cannot proceed without the helper, and the durable lease blocks every subsequent apply. Tag dial-phase failures in the socket client as undelivered, report the mutation as not-started on that path, and let the rollback marker consume the artifacts_prepared receipt so the job reaches a terminal failed state and releases the lease. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head b4e0e067)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Delta vs prior review (7c398494)
New commit b4e0e067 ("Finalize undelivered promote failures as terminal failed") closes a real lease-wedge: dial-level helper failures after MarkRuntimeMutationStarting previously left the job in recovery_pending forever because exact-phase recovery cannot proceed without the helper.
Wiring checked end-to-end:
privileged.SocketClient.call— only the unix dial failure is wrapped inundeliveredError; post-dial encode/decode/helper errors stay untagged (correct ambiguity).IsUndelivered—errors.As+Unwrapso%wwrappers still match; non-dial / helper-side*Errorrejected (unit tests cover dial, wrap, and rejection).management_apply_context.promoteStagedConfigs— returns the Promote error bare (return …, err), so the undelivered tag survives into applyflow.applyflow.Workflow— on promote error, skipsMutationStarted/Ambiguousonly whenIsUndelivered; other promote failures remain ambiguous.apply.markRuntimePublicationRolledBack—phase INnow includesartifacts_prepared(the phaseMarkRuntimeMutationStartingadvances to). Without this, safe-rollback hit "publication intent is missing" and fell intorecovery_pending.- Regression —
TestUndeliveredMutationFinalizesAsFailedasserts terminalfailed, consumed publication receipt, applied revision unchanged, and a follow-up apply is not lease-wedged.
Prior frontend blocker remains cleared (7c398494 orval regen); CI frontend on this head: success.
Looks good (re-affirmed)
- WARP
ru-blocked(#763/#778/#779): still onrunetfreedom/russia-v2ray-rules-dat.srs; ordinary codes on SagerNet. - DAT provisioning (#764), artifact catalog (#780/#855), HSTS (#902),
/api/tlsissuer fields (#906), Caddy Probe (#882): unchanged since last review; still sound. - Test hardening from the wave still matches the claimed false-green closures.
Blockers
None.
Mild (non-blocking)
- Caddy HSTS vs IP exclusion (still open):
RenderPanelCaddyfilealways emitsStrict-Transport-Securitywithpreload; Go middleware still skips IP hosts. Edge/Go mismatch if Domain were an IP literal underpanelAccess=caddy. panelAccesscase (still open): HSTS usesEqualFold(..., "caddy");tlsCertInfostill usesaccess != "caddy". Align to EqualFold.IssuerKind:HasPrefix(issuerName, "acme")covers LE storage dirs; other ACME issuer dir names become"other"(acceptable).- applyflow coverage gap:
TestWorkflowReturns500OnPromoteErroronly checks status/err for a plainpromoteErr. Worth assertingMutationStarted/Ambiguousfor anIsUndeliveredpromote error vs a post-dial/helper failure (the layered apply + socket tests already cover the pieces). - PR body: Summary does not yet mention the undelivered-promote finalize fix from
b4e0e067. - Branch currency:
behind_by=3/ diverged frommain. No obvious clash with this surface; update-branch when convenient.
CI (at review time, head b4e0e067)
- success: frontend, lint, filesystem-faults, multi-process, sigkill, image-build, analyze (go/js-ts/actions), CodeQL
- in_progress: test, e2e, browser-e2e, privilege-boundary, install-acceptance (amd64/arm64), package-smoke-matrix (amd64/arm64)
- failures: none observed
No code blockers. Merge-ready from a review standpoint once the longer suite settles (and after updating the branch if desired).
The root helper resolves promoted artifacts through its own VEIL_APPLY_ROOT/VEIL_LIVE_ROOT (packaged veil-helper.service exports them the same way). The harness launched it without them, so it fell back to /var/lib/veil/staging + /etc/veil/generated while the :2098 panel staged under /var/lib/veil/apply + /var/lib/veil/live, and once geo rules started promoting rules/geoip.dat the helper-side open() failed ENOENT and every :2098 apply wedged recovery_pending.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 21229060fca98ab8bc3766062c6bedca4d01162c) — would APPROVE
Own-PR: GitHub blocks APPROVE from the author, so COMMENT with explicit would-APPROVE.
Delta vs prior reviewed head b4e0e067553e7502910f8091dd7ac3fc3fd02e33
Not a merge-from-main. One new commit:
21229060— Align e2e helper roots with the helper-backed panel- Single file:
scripts/ci/browser-e2e.sh(+5/−0)
The root helper launch for the :2098 production-layout panel now exports:
VEIL_STATE_PATH / VEIL_KEY_PATH / VEIL_APPLY_ROOT=/var/lib/veil/apply / VEIL_LIVE_ROOT=/var/lib/veil/live
alongside the existing VEIL_BACKUP_MAX_BYTES bound. This matches the :2098 panel env a few lines later. Without it, privileged.DefaultPolicy falls back to …/staging + …/generated, so Promote cannot open panel-staged artifacts (ENOENT) and :2098 applies wedge recovery_pending once geo DAT promotion is in play. Correct, localized harness fix; comments explain the failure mode clearly.
Prior b4e0e067 undelivered-promote terminalization is unchanged by this delta.
Product issue coverage (re-verified; delta does not regress)
#763/#778/#779 ru-blocked rule-sets, #764 DAT provisioning, #780/#855 per-inbound artifacts, #902 HSTS at Caddy edge, #906 TLS issuer visibility, #882 Caddy capability probing, and the #820–#971 test-hardening set remain intact on this head. The e2e root alignment is a CI/harness correctness fix that supports exercising those paths under helper-backed apply.
Blockers
None.
Mild notes
- Comment precision (non-blocking): the new comment says packaged
veil-helper.service“exports them too.” The unit does exportVEIL_APPLY_ROOT/VEIL_LIVE_ROOT, but with production values/var/lib/veil/staging+/etc/veil/generated(same asveil.service). The harness intentionally usesapply/livefor :2098; the important invariant is panel↔helper parity inside the harness, which this commit restores. - Dir creation: production-layout setup
mkdirs/var/lib/veil/backupsbut notapply/liveexplicitly (isolated panels do). Pre-existing vs this delta; panel/helper usually create roots on first use — watch only if a race shows up before first write. - Carry-forward from prior review: undelivered dial-level promote terminalization on
b4e0e067still looks sound; no new concerns from this delta.
CI (21229060)
Run cancelled mid-flight when the branch advanced (merge main → newer tip). Observed on this SHA before cancel:
| Result | Jobs |
|---|---|
| success | multi-process, filesystem-faults, sigkill, image-build, analyze (actions) |
| neutral | CodeQL (config-not-found warning) |
| cancelled (superseded) | lint, frontend, test, e2e, browser-e2e, package-smoke, package-smoke-matrix, install-acceptance, privilege-boundary, analyze (go), analyze (javascript-typescript) |
No failed conclusions on this SHA. Full suite (esp. browser-e2e, which this commit targets) did not complete here — re-check on the post-merge tip.
Mergeability
At this head: behind main by 4 (5eacacd3, 8defe84d #972, 1aa5e6fb #975, a2282ae0 #977). mergeable_state was behind at review time for this SHA.
Verdict: would APPROVE — ship the e2e root alignment; update branch / re-run CI on the merged tip separately.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head c9c79770)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Delta vs prior review (b4e0e067)
21229060— Align e2e helper roots with the helper-backed panel.scripts/ci/browser-e2e.shnow exportsVEIL_STATE_PATH/VEIL_KEY_PATH/VEIL_APPLY_ROOT=/var/lib/veil/apply/VEIL_LIVE_ROOT=/var/lib/veil/liveon the root helper so they match the:2098panel. Without this, the helper fell back to packaged defaults (/var/lib/veil/staging+/etc/veil/generated) while the panel staged underapply/live, so Promote hit ENOENT on artifacts such asrules/geoip.datand wedged applies intorecovery_pending. Correct fix; comment explains the contract.c9c79770— Mergemainintofix/wave-zf. Brings#972/#975/#977.behind_by=0vsmain(a2282ae0). Spot-checked product surfaces still intact on this head:geoRuleSetURL→ runetfreedom forru-blocked, SagerNet otherwise (internal/renderer/warp.go);TLSCertInfo.managedBy/issuerSource/issuerKindin generated web client; undelivered-promote terminal-failed regression still present.
Product / prior findings
#763/#778/#779/#764/#780/#855/#902/#906/#882and undelivered-promote lease release: still OK.- Prior
b4e0e067blockers: none (unchanged).
Blockers
None.
Mild / nits
- Harness roots ≠ packaged unit roots (intentional).
:2098+ helper use/var/lib/veil/apply+/var/lib/veil/live, whilepackaging/systemd/veil{,-helper}.serviceuse/var/lib/veil/staging+/etc/veil/generated. Both sides of each pair stay matched; just don’t copy the e2e literals into packaging without aligning both units. - CI still settling on
c9c79770at review time (filesystem-faultssuccess;frontend/lint/multi-process/sigkill/image-build/ CodeQL matrix queued). Re-check before merge if anything reds.
CI (head c9c79770)
- success:
filesystem-faults - queued/in progress:
frontend,lint,multi-process,sigkill,image-build,analyze (go|javascript-typescript|actions)
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 59505d77)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Delta vs prior review (c9c79770)
Ahead_by=2, behind_by=0 vs that tip — merge-main only:
263bd7ec— Fix false-green CI/workflow/script contracts and harden their tests (#978)59505d77— Merge branchmainintofix/wave-zf
File delta is CI/workflow/script/contract-test focused (ci.yml, release.yml, Dockerfile, internal/cli/* contract helpers, scripts/ci/*, scripts/package-smoke.sh, packaging/docker/entrypoint.sh, runtimeinstall, etc.). No conflict markers on inspected overlaps. Overlap files that also existed on the prior tip (privilege-boundary.sh, install-acceptance.sh, package-smoke.sh, promotion/transactional-install regression tests, ci.yml) resolve cleanly to main/#978 (blob SHA == main). Diff prior→main for those scripts is #978 hardening only (exact-line grep -qxF unit contracts, install-acceptance binary stash/restore + probe_panel_healthz, package-smoke bulk try-restart completeness) — no wave-zf product surface lost.
behind_by=0 vs main (263bd7ec). mergeable=true.
Product / prior findings (re-verified at head; merge did not touch)
Blob SHA-identical vs c9c79770 for the wave-zf product surfaces spot-checked:
- #763/#778/#779 —
geoRuleSetURL→ runetfreedom forru-blocked; SagerNet otherwise (internal/renderer/warp.go) - #764 —
EnsureDatSourceselective geoip/geosite attach (internal/routing/source.go) - #780/#855 — per-inbound
hysteria2/*.yaml/olcrtc/*.yaml+ exact/globMatchesGeneratedPath(artifact_catalog.go) - #902 — Caddyfile HSTS (
panel_caddy.goheader Strict-Transport-Security … preload) + GotlsEdgemiddleware (router_security.go) - #906 —
TLSCertInfo.managedBy/issuerSource/issuerKind(OpenAPI +internal/runtime/tls.go+ web orvaltLSCertInfo.ts) - #882 —
Probe→parseModuleList(caddycapabilities/capabilities.go) - b4e0e06 — undelivered-promote terminal
failedregression still present - 2122906 — browser-e2e helper roots
VEIL_APPLY_ROOT=/var/lib/veil/applyVEIL_LIVE_ROOT=/var/lib/veil/liveintact
#978 carry-forward at head: install-acceptance stash/restore + package-smoke fail-closed / exact-line contracts intact (matches the favorable #978 review).
Blockers
None.
Mild (non-blocking; carry-forward unchanged by this merge)
- Caddy HSTS vs IP exclusion:
RenderPanelCaddyfilealways emits HSTS withpreload; Go middleware still skips IP hosts. panelAccessEqualFold inconsistency intlsCertInfovs HSTS wiring.IssuerKindHasPrefix("acme")— other ACME issuer dir names become"other"(acceptable).- Harness roots ≠ packaged unit roots (intentional) —
:2098uses apply/live; packaged units use staging/generated.
CI (head 59505d77, review time ~14:33 MSK / 11:33 UTC)
- success:
lint,image-build,filesystem-faults,multi-process,sigkill,analyze (go),analyze (javascript-typescript),analyze (actions),CodeQL - pending:
frontend - Longer matrix (
test,e2e,browser-e2e,privilege-boundary,install-acceptance,package-smoke*) not yet reported on this SHA — still settling; no failures observed.
No code blockers. Would APPROVE; merge-ready from review once remaining checks settle.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 45a29198)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Delta vs prior review (59505d77)
Not a merge-from-main. One new commit:
45a29198— Restore registerMux contract extraction and v1 bindings GET- Three files:
internal/api/client_v1_routes.go,internal/api/router_composition.go,internal/api/openapi_real_router_contract_test.go
What it does (checked end-to-end):
GET /api/v1/clients/{id}/bindings— implements the OpenAPI-documented list endpoint by returningClientView.Bindingsas{items: [...]}(nil → empty slice).methodNotAllowednow advertises GET+POST. Blob SHA identical tomain(#973).RouterComposition.registerMux— extracts the live mux registrations into one helper so contract tests can callmux.Handleron the exact production set (issue #923).Build()delegates to it.- Honest OpenAPI↔router contracts — rewrites
TestRealRouterCoversOpenAPIStageEndpoints/TestOpenAPIDocumentsEveryRegisteredStageRouteto:- derive the probe set from the full stage OpenAPI surface (not a hand-maintained subset),
- prove registration via
mux.Handler(resource-404 ≠ mux-miss), - scrape
mux.Handle(Func)registrations from package sources for the reverse check, - reject 405 and missing auth-policy 404s.
Blob SHA identical tomain(#973).
Intentional divergence from main in router_composition.go only (wave-zf product surfaces preserved inside registerMux / Build):
RuntimeRoutes{TLSInfo: state.tlsCertInfo}(#906 issuer visibility) — main still hasRuntimeRoutes{}securityHeadersMiddleware(..., EqualFold(panelAccess, "caddy"))(#902 HSTS at Caddy edge)
So this commit correctly backports the #973 contract/bindings restore onto fix/wave-zf without dropping TLS/HSTS wiring.
Product / prior findings (re-verified; blob-identical to 59505d77)
warp.go (ru-blocked), routing/source.go (DAT), artifact_catalog.go, panel_caddy.go + router_security.go (HSTS), runtime/tls.go + TLSCertInfo, caddycapabilities Probe→parseModuleList, undelivered-promote regression, browser-e2e helper roots — all untouched by this commit.
Blockers (code)
None.
Mergeability (process — not a code defect in this commit)
mergeable=false / mergeStateStatus=DIRTY / behind_by=1 vs main tip e1cd657d (#973). Conflicts are expected on the same three API files (plus other wave-zf overlaps). When resolving:
- keep this branch’s
RuntimeRoutes{TLSInfo: state.tlsCertInfo}and HSTSpanelAccess=caddywiring; - take main’s OpenAPI enrichment for
GET …/bindings200 (content/schemawithitems: BindingView) — this head’s OpenAPI still has description-only 200 for that path; client_v1_routes.go+openapi_real_router_contract_test.goare already blob-identical to main, so those sides should merge cleanly oncerouter_composition.gois resolved.
Mild (non-blocking)
- OpenAPI GET bindings 200 schema — still description-only on this head; main/#973 adds
items: BindingView. Comes in with the main merge. - CI not yet queued on
45a29198at review time (no Actions runs / check-runs / status contexts). Prior head59505d77CI+CodeQL were success. Re-check once workflows fire; dirty merge state may be delaying PR-triggered runs. - Carry-forward: Caddy HSTS vs IP exclusion mismatch;
panelAccessEqualFold inconsistency intlsCertInfo; harness apply/live roots ≠ packaged staging/generated (intentional).
CI (head 45a29198)
- this SHA: no runs observed yet
- prior tip
59505d77: ci + codeql success
Verdict: would APPROVE the commit itself. Update/rebase onto main (#973) and preserve TLSInfo + HSTS when resolving router_composition.go before merge.
# Conflicts: # internal/api/router_composition.go
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (own-PR → COMMENT only)
Verdict: would APPROVE
Delta vs prior head 45a29198
Merge-only: 4e3c8bc = merge origin/main (e1cd657 — #973 OpenAPI/SDK contract drift, web-base-path collisions, false-green test hardening) into fix/wave-zf. No new wave-zf feature commits after the prior review’s registerMux / bindings / OpenAPI contract restore.
Meaningful product delta from #973 (not merge noise):
webbasepath.Normalize: reserved first-segment set expands beyondsto root-mux collisions (api,metrics,healthz/livez/readyz,assets, favicon/robots) — correct for #765.- Settings/setup reads: empty
panelAccesswrite-sentinel surfaces as effective"local"; OpenAPI enums drop''; newopenapi_schema_drift_test.golocks ClientView / BindingCapability / ExpirationEnforcement / panelAccess / Redocly allowlist. GET /api/v1/clients/{id}/bindingsOpenAPI now documents{items: BindingView[]}matching the liveitemsenvelope.- Dead
isReadOnlyDiagnosticRequestremoved (never consulted; wrongly lumped/api/client-links/qrwith viewer diagnostics). - Regenerated SDK / web client / zod / msw for the #973 schema fixes.
Product surface status (wave-zf)
Blob-identical vs 45a29198 for the wave-zf cores:
- WARP
geoRuleSetURL/ru-blocked→ runetfreedom.srsURLs; ordinary codes stay SagerNet EnsureDatSource→ geoip/geosite/private/disabled/no-geo selection intactMatchesGeneratedPath/LivePathForStagedConfig→ exact +path.Matchper-inbound globs- HSTS /
tlsEdge→ still emitted underpanelAccess=caddy; IP hosts excluded TLSCertInfomanagedBy/issuerSource/issuerKind(+ OpenAPI) intactProbe→parseModuleListintactregisterMux+GET /api/v1/clients/{id}/bindings(itemsenvelope) + OpenAPI↔router contracts intact
Blockers
none
Mild / nits
- Several CI jobs still in progress at review time (
test,e2e,browser-e2e,install-acceptanceamd64/arm64,package-smoke-matrixamd64/arm64). Already green:lint,frontend,image-build,privilege-boundary,multi-process,filesystem-faults,sigkill, CodeQL analyze (go/js/actions). Not a code blocker; re-check before merge if any fail. mergeable_state=blockedis expected (own-PR cannot self-APPROVE; checks still settling).
CI summary (head 4e3c8bc1)
| Check | Status |
|---|---|
| lint / frontend / image-build | success |
| privilege-boundary / multi-process / filesystem-faults / sigkill | success |
| CodeQL analyze (go, js-ts, actions) | success |
| test / e2e / browser-e2e / install-acceptance / package-smoke | in_progress |
behind_by
0 vs main (compare 4e3c8bc1...main → main not ahead).
# Conflicts: # internal/api/router_composition.go # internal/api/runtime_routes.go # internal/api/tls_test.go # sdk/go/veilclient.gen.go
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head b8be193e)
Verdict: COMMENT — would APPROVE. Own-PR blocks APPROVE.
Delta vs prior review (4e3c8bc1)
Merge-only: ahead_by=2, behind_by=0 vs that tip.
dd4bc437— fix: wave-zc audit hardening — meaningful assertions, TLS via Caddy certs, token gating (#976)b8be193e— Merge remote-tracking branchorigin/mainintofix/wave-zf
behind_by=0 vs main (dd4bc437). mergeable=true / mergeStateStatus=BLOCKED (own-PR + checks settling).
Merge resolution (product-critical)
#976 rewired /api/tls from RuntimeRoutes{TLSInfo: state.tlsCertInfo} to RuntimeRoutes{State: state} + ReadTLSCertForDomain (#905 SAN/domain check). Conflict resolution on this branch correctly kept wave-zf #906 issuer visibility on top of that architecture:
router_composition.go:RuntimeRoutes{State: state}.Register(mux)(matches main) and HSTSsecurityHeadersMiddleware(..., EqualFold(panelAccess, "caddy"))(#902) still present vs main’s bare middleware.runtime_routes.govs main: addsservePanelAccessoverride, and setsManagedBy/IssuerSource/IssuerKindon the Caddy path (main’s #976 path hadSource: "caddy"only).internal/runtime/tls.go: gains #976Source+ReadTLSCertForDomain; ManagedBy/IssuerSource/IssuerKind fields remain.- OpenAPI + web orval
tLSCertInfostill exposemanagedBy/issuerSource/issuerKind(plus newsourcefrom #976).
Product surfaces (wave-zf) — re-verified
Blob-identical vs 4e3c8bc1 (unaffected by merge):
- #763/#778/#779 —
geoRuleSetURL→ runetfreedom forru-blocked; SagerNet otherwise (warp.go) - #764 —
EnsureDatSourceselective geoip/geosite (routing/source.go) - #780/#855 — per-inbound globs + exact/
path.Match(artifact_catalog.go) - #902 — Caddyfile HSTS (
panel_caddy.go) + GotlsEdge(router_security.go) - #882 —
Probe→parseModuleList(caddycapabilities) - 2122906 — browser-e2e helper
VEIL_APPLY_ROOT/VEIL_LIVE_ROOTapply/live roots - b4e0e06 — undelivered-promote terminal-failed regression blob-identical
#906 issuer visibility: preserved through the new RuntimeRoutes.State path (see above).
Blockers
None.
Mild (non-blocking)
- Caddy HSTS vs IP exclusion (carry-forward):
RenderPanelCaddyfilealways emits HSTS withpreload; Go middleware still skips IP hosts. Edge/Go mismatch if Domain were an IP literal underpanelAccess=caddy. panelAccessEqualFold — prior mild note is cleared by this merge:tlsCertInfonow usesstrings.EqualFold(access, "caddy")(aligned with HSTS).IssuerKindHasPrefix("acme")— other ACME issuer dir names become"other"(acceptable).- Harness roots ≠ packaged unit roots (intentional) —
:2098uses apply/live; packaged units use staging/generated. - Longer CI matrix still queued on this SHA — no failures observed; re-check before merge if anything reds.
CI (head b8be193e, review time ~16:00 MSK / 13:00 UTC)
| Result | Jobs |
|---|---|
| success | lint, frontend, image-build, multi-process, filesystem-faults, sigkill, analyze (javascript-typescript), analyze (actions) |
| in_progress | analyze (go) |
| queued | test, e2e, browser-e2e, privilege-boundary, install-acceptance (amd64/arm64), package-smoke-matrix (amd64/arm64) |
| neutral | CodeQL (config-not-found warning) |
| failures | none |
No code blockers. Would APPROVE; merge-ready from review once the longer suite settles.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head bf370336beb2f71adab6e1fb5344cc8647fb1842)
Verdict: would APPROVE (own-PR: GitHub blocks APPROVE → COMMENT).
Delta vs prior reviewed head b8be193ea3e079b0dce06bf61dcb94c08438bc58
Merge-main only. Compare b8be193e...bf370336:
- 2 commits:
d38f37c7chore(deps-dev): bump lighthouse (#989);bf370336Merge branchmainintofix/wave-zf - Files:
test/browser/package.json+package-lock.jsononly (lighthouse13.4.1→13.5.0) - No conflict resolutions on wave-zf product surfaces (
router_composition.go,runtime_routes.go,tls.go, openapi, web client untouched in this delta) behind_byvsmain: 0 (main tip =#989d38f37c7)
Product re-verify @ bf370336 (blob spot-checks)
| Surface | Status |
|---|---|
internal/renderer/warp.go — ru-blocked → runetfreedom geoRuleSetURL (#763/#778/#779) |
OK |
internal/routing/source.go — EnsureDatSource selective DAT (#764) |
OK |
internal/generatedconfig/artifact_catalog.go — per-inbound globs (#780/#855) |
OK |
internal/renderer/panel_caddy.go + internal/api/router_security.go — HSTS (#902) |
OK |
internal/api/runtime_routes.go + internal/runtime/tls.go + caddycert — ManagedBy/IssuerSource/IssuerKind (#906) atop RuntimeRoutes{State} (#976) |
OK |
internal/api/router_composition.go — RuntimeRoutes{State: state} + HSTS EqualFold(panelAccess, "caddy") |
OK |
internal/caddycapabilities/capabilities.go — Probe → parseModuleList (#882) |
OK |
scripts/ci/browser-e2e.sh — VEIL_APPLY_ROOT/VEIL_LIVE_ROOT helper roots |
OK |
undelivered-promote path (internal/apply/undelivered_promote_regression_test.go + related) |
OK |
Blockers
none
Mild (carry-forward; non-blocking)
- Caddy-edge HSTS pin vs IP/hostname exclusion edge cases (unchanged)
caddycert.IssuerKind:HasPrefix(issuerName, "acme")classification (unchanged; still correct for current Caddy storage names)- Harness
VEIL_APPLY_ROOT/LIVE_ROOT≠ packaged staging/generated layout (documented helper-root divergence; unchanged) - Prior mild
panelAccesscase-sensitivity: cleared onb8be193e(EqualFoldretained)
CI @ bf370336 (snapshot)
| Check | Status |
|---|---|
| lint / frontend / image-build / filesystem-faults / multi-process / sigkill | success |
| analyze (actions) / analyze (javascript-typescript) | success |
| CodeQL | completed (neutral) |
| analyze (go) | in_progress |
| test / e2e / browser-e2e / privilege-boundary / install-acceptance (amd64/arm64) / package-smoke-matrix (amd64/arm64) | queued |
No failures observed. Pending/queued checks are not treated as blockers unless they later show a code defect in this PR's product delta (here: lighthouse bump only).
Summary
Wave-zf product cores remain blob-intact after absorbing #989. Ready to merge once required checks settle green.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 870fb119db5c4d102065e3c74ca8800e95c94ed3)
Verdict: would APPROVE (own-PR: GitHub blocks APPROVE / REQUEST_CHANGES from the author account, so this is COMMENT).
Delta vs prior review (bf370336)
Merge-main only — four commits:
c6f24fe/ merge: #974 honest apply outcomes (pre-mutation failures + ambiguous history)888df6c/ merge: #991github/codeql-actioninit+analyze4.38.0→4.38.1(1c5b675)
No new wave-zf product commits on this branch.
Product wave-zf — blob-identical vs prior head
Checked against bf370336: docs/openapi.yaml, internal/caddycapabilities/capabilities.go, internal/caddycert/caddycert.go, internal/generatedconfig/{artifact_catalog,paths}.go, internal/installer/install_apply.go, internal/panel/panel_routing_card.go, internal/renderer/{panel_caddy,warp}.go, internal/routing/source.go, sdk/go/veilclient.gen.go — all unchanged. Prior findings on #763/#778/#779 ru-blocked rule-sets, #764 DAT selection, #780/#855 per-inbound artifacts, #902 HSTS at Caddy edge, #906 TLS issuer fields, #882 capability probing, and the audit-test hardening set still stand.
Merged #974 surface (spot-check)
PreMutationError/MarkPreMutationErrorkeep promote failures before mutation out of the ambiguous path; post-mutation failures setresponse.Ambiguousand stage"ambiguous"(#968).ApplyHistoryEntry.Ambiguous+ panel stage filter optionambiguouswired through.RoutingPresetApplication.Applydeep-copiesSource.Files(#947) — correct fix for shared backing-array leak; only routing touch in this delta besides tests.
Merged #991
Pin bump only on CodeQL actions; matches already-reviewed #991 on main.
Blockers
None for merge of wave-zf content.
Mild / notes
behind_by=0vsmain(12 commits ahead).- CI on this head still settling: CodeQL analyze (js-ts/actions) success + CodeQL neutral;
analyze (go)/sigkillin progress;frontend/lint/multi-process/filesystem-faults/image-buildqueued. No failures observed at review time.mergeStateStatus=BLOCKEDis expected until checks (and a non-author approval) settle. - Own-PR limitation unchanged: cannot leave a formal APPROVE from
mikkelchokolate.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 8e10a90d46951a8536e86640bebf33e5d1d725f6)
Verdict: would APPROVE (own-PR: GitHub blocks APPROVE / REQUEST_CHANGES from the author account, so this is COMMENT).
Delta vs prior review (870fb119db5c4d102065e3c74ca8800e95c94ed3)
Merge-main only — two commits:
b1a51c8bc255— #994 harden false-green assertions across api, serve, and e2e8e10a90d4695— Merge branch 'main' into fix/wave-zf
No new wave-zf product commits on this branch. Delta file set (15) is entirely #994: api/cli/serve/testguard/e2e test hardening plus a small behavior-preserving extract of resolvedHelperSocket() in internal/cliflow/serve/http_server.go (empty helper socket → privileged.DefaultSocketPath).
Product wave-zf — blob-identical vs prior head
Checked 24 PROD paths against 870fb119 (openapi, capability catalog / router security / runtime routes, apply finalize + workflow, caddycapabilities, caddycert, generatedconfig artifact_catalog+paths, installer, panel routing card, privileged socket client, renderer panel_caddy+warp, routing source, runtime tls, settings validation, browser-e2e script, sdk/go client, web TLSCertInfo models + zod) — all unchanged.
Prior findings still stand:
- #763 / #778 / #779 —
geoip:ru-blocked/geosite:ru-blocked→ runetfreedom rule-sets (not broken SagerNet remaps) - #764 —
EnsureDatSourceonly pulls dat files enabled matchers consume - #780 / #855 — per-inbound globs +
MatchesGeneratedPathexact/glob matching; bare template units not restartable - #902 — HSTS at Caddy edge when
panelAccess=caddy - #906 —
TLSCertInfomanagedBy/issuerSource/issuerKind - #882 — production
Probe→parseModuleList - Audit false-green test hardening set from the wave-zf body
Merged #994 surface (spot-check)
- False-green assertion hardening across api / serve / e2e — matches already-reviewed #994 on main (COMMENT would-APPROVE on that PR).
- Sole prod touch:
resolvedHelperSocket()extraction;Build()still wires the same default socket path. No wave-zf interaction.
Blockers
None for merge of wave-zf content.
Mild / notes
behind_by=0vsmain(13 commits ahead).- CI on this head still settling at review time: success lint, multi-process, sigkill, filesystem-faults, image-build, analyze (actions), analyze (javascript-typescript); in_progress frontend + analyze (go); CodeQL neutral (“2 configurations not found” vs main — known workflow-surface noise post-#991, not a product fail). No failures observed.
mergeStateStatus=BLOCKEDexpected until remaining checks (and a non-author approval) settle. - Own-PR limitation unchanged: cannot leave a formal APPROVE from
mikkelchokolate.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (re-check on merge-main head)
Head: 830b2758a3252e03142be9750f5964f47548077f
Prior review head: 8e10a90d46951a8536e86640bebf33e5d1d725f6
Event: COMMENT (own-PR — GitHub blocks APPROVE from the author; would APPROVE)
Delta vs prior review head
ahead_by=2,behind_by=0- Commits: merge
mainbringing#990(chore(deps-dev): bump the web-dependencies group in /web with 2 updates) + the merge commit itself - Files touched only:
web/package.json—@babel/parser8.0.5→8.0.6,orval^8.33.0→^8.35.0(blob238c56d1…)web/pnpm-lock.yaml(blobdfd01913…)web/src/api/generated/zod/clients/clients.zod.ts—PatchApiV1ClientsIdBody.quotaResetPolicyregenerated tozod.union([…literals…, zod.literal(null)]).nullish()(blobac875d0c…)
No wave-zf product / Go / OpenAPI / WARP / Caddy / generatedconfig paths in the delta.
Product verification (wave-zf)
Compared 24 curated PROD paths (WARP ru-blocked renderer + tests, EnsureDatSource / routing source, generatedconfig per-inbound artifact/paths/catalog, Caddy HSTS/TLS issuer + caddycapabilities Probe, panel_caddy, capability catalog, install_apply, related settings) vs last primary product tip a5962df2c359…:
product OK blob-identical 24/24
Also confirmed HEAD ≡ prior review head on those same 24 paths (merge #990 did not touch them).
CI snapshot (830b2758…)
- Completed success: analyze (javascript-typescript / actions / go), CodeQL, privilege-boundary, multi-process, frontend, image-build, filesystem-faults, lint, sigkill
- Still in_progress: test, e2e, browser-e2e, install-acceptance (amd64/arm64), package-smoke-matrix (amd64/arm64)
No failures observed on completed checks.
Blockers
none
Mild notes
quotaResetPolicyonPatchApiV1ClientsIdBodyremainszod.union([zod.literal('never'|'daily'|'weekly'|'monthly'), zod.literal(null)]).nullish()from the#990orval bump — redundant nullability (literal(null)inside a.nullish()union). Pre-existing from#990; not introduced by wave-zf product work; no merge blocker.
Verdict
Would APPROVE. Delta is merge-main / web-deps only; wave-zf product surface remains intact; no blockers.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 851e06f2)
Verdict: would APPROVE (own-PR blocks APPROVE → COMMENT).
Delta vs prior reviewed head 830b2758
Merge-main only (2 commits):
c1e3fb9— fix: metrics path labels, audit spool honesty, privileged fencing, and API mutation edge cases (#992)851e06f— Merge branchmainintofix/wave-zf
No new product commits on wave-zf itself.
Product wave-zf status
Re-verified core wave-zf themes still present and intact on this head:
- WARP ru-blocked:
internal/renderer/warp.goroutesru-blockedviarunetfreedom/russia-v2ray-rules-datsing-box rule-set URLs; presets/tests covergeoip:ru-blocked/geosite:ru-blocked. - EnsureDatSource:
internal/routing/source.go+ callers; geoip:private → geoip.dat coverage in tests. - Per-inbound artifacts:
hysteria2/*.yaml/olcrtc/*.yamlglobs inartifact_catalog.go. - HSTS / panelAccess=caddy: Caddyfile HSTS header in
panel_caddy.go; GosecurityHeadersMiddleware(..., panelAccess==caddy)retained inrouter_composition.go. - TLS issuer visibility:
managedBy/issuerSource/issuerKindin OpenAPI,runtime/tls.go,caddycert, generatedtLSCertInfo. - Probe → parseModuleList: production Probe in
caddycapabilitiesroutes throughparseModuleList(#882).
Blob check vs 830b2758: 72/73 PR paths identical. Sole diff is internal/api/router_composition.go (+6/−3 from the #992 merge): correctly wires state.metrics, moves MetricsMiddleware inside the post-strip path (issue #979), and keeps the wave-zf HSTS panelAccess=caddy gate. Clean merge — both waves preserved.
Spot-check of merged #992
runtime_fence.go lease acquire/release with dead-owner retry looks sound; fencing/audit-spool/expiration/binding-patch test additions are additive. No conflict residue that weakens wave-zf.
CI snapshot (851e06f2, filter=latest)
Success: lint, filesystem-faults, image-build, sigkill, multi-process, analyze (actions), analyze (javascript-typescript), CodeQL (no new alerts).
In progress: frontend, analyze (go).
No failures observed. mergeStateStatus=BLOCKED is expected (reviews/branch protection), not a product defect.
Blockers
None.
Mild (carry-forward from #990 merge; not introduced here)
web/src/api/generated/zod/clients/clients.zod.ts still has quotaResetPolicy: zod.union([...literals, zod.literal(null)]).nullish() — redundant nullability from orval; harmless generated noise, not a wave-zf regression.
Summary
Wave-zf product surface is unchanged and still correct; #992 merge is clean. Would APPROVE when own-PR policy allows.
mikkelchokolate
left a comment
There was a problem hiding this comment.
Review (head 4d7a0b0eeeff)
Verdict: would APPROVE (own-PR cannot APPROVE via this account) — COMMENT.
Delta vs prior review (851e06f2): merge main only — #993 (audit-hardening wave zb: honest regression tests + clone/health fixes). No new wave-zf product commits.
Merge integrity
- Wave-zf–only paths vs prior tip: 68/68 blob-identical (0 changed / 0 missing).
- Spot-checked product blobs unchanged:
internal/renderer/warp.go,internal/routing/{source,routing_presets}.go,internal/generatedconfig/{artifact_catalog,warp_renderer,warp_routing_rules}.go,internal/renderer/panel_caddy.go,internal/caddycert/caddycert.go,internal/caddycapabilities/capabilities.go,internal/runtime/tls.go,web/.../tLSCertInfo.ts. TLSCertInfoOpenAPI block (managedBy/issuerSource/issuerKind) SHA-identical across the merge; SDK still exposes the three fields.#993inbound overlap is test/hardening only (stronger goldens ininbound_renderer_more_test,warp_renderer_test, DAT retry attempt pin, healthcheck{"status":"ok"}contract, deepInboundCloneviamodel.CloneInbound) plus OpenAPI role/binding GET + generated clients — no conflict with wave-zf WARP/HSTS/TLS/catalog changes.
Product (unchanged, still OK)
- WARP
ru-blocked: runetfreedom rule-sets; ordinary geo keeps SagerNet. - DAT provisioning: attach only what enabled matchers consume.
- Artifacts: per-inbound globs; exact/
path.Match; bare@.servicenot restartable. - HSTS at Caddy edge + middleware when
panelAccess=caddy; IP hosts excluded. /api/tlsissuer visibility + OpenAPI/SDK.- Caddy
ProbeviaparseModuleList; HTTP3 fromhttpmodule. - Test hardening wave still honest (exact URL/tag/path/credential checks).
Blockers
None from this merge.
Mild (carry-forward, non-blocking)
web/src/api/generated/zod/clients/clients.zod.ts:quotaResetPolicypatch schema remainszod.union([..., zod.literal(null)]).nullish()(from earlier#990web-deps regen). Harmless; worth a follow-up if orval keeps emitting the null literal.
CI (head 4d7a0b0eeeff)
Settling after the push: CodeQL analyze (actions) success; analyze (go) / analyze (javascript-typescript) in_progress; ci workflow pending. Prior head 851e06f2 had CodeQL success and CI still running. behind_by=0 vs main.
Ship when CI is green.
Summary
Fixes a wave of confirmed audit issues across WARP routing, generated artifacts, panel TLS/HSTS handling, and test quality:
ru-blockedrule-sets ([P1] sagerNetRuleCode maps geosite:ru-blocked → geolocation-ru.srs (HTTP 404); test locks the dead URL (#191 residual) #763, [P1] Panel/tests promote geosite:geolocation-!ru for WARP but SagerNet rule-set 404s (veil-warp fail-close) #778, [P2] sagerNetRuleCode maps geoip:ru-blocked → geoip-ru.srs (live but wrong); tag still says ru-blocked (#191/#763 residual) #779):geoip:ru-blocked/geosite:ru-blockednow reference the publishedrunetfreedom/russia-v2ray-rules-datsing-box rule-sets. The previous SagerNet remaps pointed at a 404 artifact (geosite-geolocation-ru.srs) and atgeoip-ru(all Russian IP space, not the blocked subset), causingveil-warpto fail closed or misroute. Ordinary geo codes keep their SagerNet URLs. Panel placeholder examples updated togeosite:ru-blocked.EnsureDatSourcenow attaches only the dat files enabled matchers actually consume —geoip:*/geoip:private→geoip.dat,geosite:*→geosite.dat; disabled rules and no-geo rule sets download nothing.hysteria2/*.yaml/olcrtc/*.yamlglobs (aggregateserver.yamlis gone);MatchesGeneratedPath/LivePathForStagedConfiguse exact orpath.Matchglob matching, rejecting sibling/suffix/nested lookalikes; bare template units likeveil-hysteria2@.serviceare never advertised as restartable actions; installer reports the per-inbound Hysteria2 directory.Strict-Transport-Securityand the Go security middleware emits HSTS whenpanelAccess=caddy(the public edge is TLS even though the inner listener sees loopback HTTP); IP hosts remain excluded./api/tlsissuer visibility ([P3] Panel Caddyfile silent issuer internal fallback — no /api/tls or status honesty when ACME fails #906): responses now carrymanagedBy,issuerSource, andissuerKind(acme/internal/other), so a Caddy ACME failure that silently fell back to the internal CA is distinguishable in status.docs/openapi.yamlupdated andsdk/goregenerated.Proberoutes throughparseModuleList, so the tested parser is the live path; HTTP3 derives from the basehttpmodule.Test plan
go vet ./...— clean;gofmt— clean;git diff --check— clean;go mod tidy— no drift.go teston all touched packages:internal/{bindregistry,caddycapabilities,caddycert,generatedconfig,inbounds,installer,livevalidation,managementstate,panel,protocols/...,renderer,routing,runtime,settings}— all pass (naiveproxy/protocols verified with a stubcaddy list-modules --jsonbinary; CI supplies the pinned real one).internal/api(~918 tests) run as unprivileged uid in 6 shards + targeted re-runs — every test passes in isolation. Known environment limitations identical on the base commitf01442ce:TestClientPatchOpenAPIAndGeneratedContractIncludesEveryDurableField,TestConstantTimePasswordEqualDoesNotHashPasswords,TestTrackedAutoApplyUsesSnapshotIsolationOutsideGlobalMutex— fail on clean base (pre-existing).TestPublicSubscriptionUsesLastAppliedImmutableSnapshot,TestAuthenticatedLinksConvergeAfterSuccessfulApply,TestManagementApplyStagesWarpOutboundWhenEnabled— require live network/traffic endpoints unavailable in this sandbox; fail identically on base.TestNaiveGeneratedConfig*— require acaddybinary on PATH (pinned in CI); verified passing with a stub.go generate ./sdk/go+go test ./sdk/go/...— regenerated SDK includes the newTLSCertInfofields; tests pass.Closes #763
Closes #764
Closes #778
Closes #779
Closes #780
Closes #855
Closes #882
Closes #902
Closes #906
Closes #820
Closes #821
Closes #822
Closes #823
Closes #824
Closes #836
Closes #844
Closes #845
Closes #846
Closes #852
Closes #853
Closes #856
Closes #857
Closes #861
Closes #863
Closes #884
Closes #894
Closes #895
Closes #901
Closes #915
Closes #918
Closes #920
Closes #959
Closes #962
Closes #971