Skip to content

test(gateway): add the port a ZT domain needs, and cover the CAA guard rerun - #1146

Merged
kvinwang merged 1 commit into
feat/e2e-resolve-challenge-recordsfrom
fix/e2e-zt-domain-port
Aug 27, 2026
Merged

test(gateway): add the port a ZT domain needs, and cover the CAA guard rerun#1146
kvinwang merged 1 commit into
feat/e2e-resolve-challenge-recordsfrom
fix/e2e-zt-domain-port

Conversation

@kvinwang

Copy link
Copy Markdown
Collaborator

Draft. The port fix is right and the CAA case is written and proven to
discriminate, but the suite is not green yet — see Status.

The suite's dns-01 half has not been running

Phase 4 adds the dns-01 domains without a port:

-d '{"domain": "'"${domain}"'"}' > /dev/null || true

The server refuses that — proto_to_zt_domain_config requires 1..65535 — and
|| true swallowed it. So test0.local and friends were never configured, and
every assertion downstream of them failed. The gateway says so plainly once you
look:

CAA records reconciled for 0 domains (3 on dns-persist-01 left to the operator)

Three domains, all the dns-persist-01 ones added by Phase 10. That is 22 of
the suite's assertions failing for long enough that the count reads as a
property of the environment. It is not — there was nothing there to fail.

This is pre-existing: the port check is on next, not from this stack.

The port is supplied, and the swallow becomes a warning so the next breakage
announces itself.

What that unblocks

A SetCaa run that dies between installing the ; guards and dropping them
leaves them behind, and the operator is told to rerun. The rerun has to work,
and it has to get there without ever lifting the deny-all — a name with no
issuer CAA is not "denied" but "any CA may issue".

Both reusing the stranded guard and deleting it to add a fresh one end with the
same records. Only one of them stays denied throughout, and the gap is
invisible once the replacement finishes. So the mock records names whose issuer
CAA set emptied out, and the test asserts the domain is not among them.

The stranded state is planted directly — that is exactly what a dead run left —
so this needs no way to kill a run midway.

Status

  • The port fix is verified against the gateway's own log.
  • The CAA case fails against delete-then-add and passes against adoption
    when driven by hand, so it discriminates rather than passing vacuously.
  • It is not yet green inside the full suite. Reviving 22 assertions that
    have never run turns up more than one layer, and the remaining ones are still
    being unwound. Draft until it is.

Base

Third in a stack: #1132#1144 → this. Merge in order.

…d rerun

Phase 4 has been adding the dns-01 domains without a port, which the server
refuses -- `proto_to_zt_domain_config` requires 1..65535 -- and the call
swallowed the error with `|| true`. So `test0.local` and friends were never
configured, and everything downstream of them failed:

    CAA records reconciled for 0 domains (3 on dns-persist-01 left ...)

That is 22 of the suite's assertions, reported as failures for long enough to
read as the environment. They are not: nothing had been added to fail on. The
port is supplied and the swallow becomes a warning, so the next time this
breaks it says so.

With a dns-01 domain that exists, the CAA guard sequence can be exercised. A
run that dies between installing the `;` guards and dropping them leaves them
behind, and the operator is told to rerun; the rerun has to work, and has to
get there without ever lifting the deny-all, because a name with no issuer CAA
is one any CA may issue for. The stranded state is planted directly -- it is
exactly what the dead run left -- so this needs no way to kill a run midway.

The half that matters is the second one. Both reusing the stranded guard and
deleting it to add a fresh one end with the same records, and only one of them
stays denied throughout, so the gap is invisible in the result. The mock
therefore records names whose issuer CAA set emptied out, and the test asserts
the domain is not among them. Reverting to delete-then-add fails it.
@kvinwang
kvinwang marked this pull request as ready for review August 27, 2026 01:15
Copilot AI lite review requested due to automatic review settings August 27, 2026 01:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@kvinwang
kvinwang merged commit 5a82564 into feat/e2e-resolve-challenge-records Aug 27, 2026
@kvinwang
kvinwang deleted the fix/e2e-zt-domain-port branch August 27, 2026 01:16
kvinwang added a commit that referenced this pull request Aug 27, 2026
…appened (#1144)

* test: resolve challenge records through the mock, and check that it happened

certbot resolves each challenge name itself before telling the CA to look, so
that a record which has not propagated is reported by name rather than as an
order failure. Nothing in the suite exercised that: the gateway resolved
through Docker's embedded DNS, which has never heard of the test zones, so
every self-check ran its full budget, warned, and proceeded -- for dns-01 too,
seconds after certbot itself wrote the record.

    WARN no authoritative nameserver for _acme-challenge.test0.local,
         using the system resolver
    DEBUG challenge not found, waiting for 500ms tries=2 max_wait=30s

Pointing the gateways at the mock needs the mock to stop being a black hole for
everything else: a name it does not know was answered NOERROR with no records,
which a resolver reads as authoritative and does not retry elsewhere, so the
gateway would lose the other containers. It now forwards those upstream, which
is what makes it usable as a client's only resolver rather than only as a CA's
`-dnsserver`.

The check is advisory, so nothing downstream reveals whether it worked -- an
order succeeds either way. The mock therefore logs every question it is asked
and serves them at /api/dns-queries, and the two cases are asserted directly:

- Answered, for a record the suite published. Observed rather than triggered:
  the periodic renewal picks a domain up as soon as it is added, so forcing one
  races it and can find nothing left to do.
- Asked repeatedly and never answered, for a name with no record. Polling is
  the point -- a record may still be propagating -- and giving up must not stop
  the order.

Each keys off a name nothing else asks for, so they need no clearing and do not
depend on running in any order.

Incidentally the suite gets its time back: a self-check that resolves settles
in seconds instead of spending the whole advisory wait on every order.

* test(gateway): add the port a ZT domain needs, and cover the CAA guard rerun (#1146)

Phase 4 has been adding the dns-01 domains without a port, which the server
refuses -- `proto_to_zt_domain_config` requires 1..65535 -- and the call
swallowed the error with `|| true`. So `test0.local` and friends were never
configured, and everything downstream of them failed:

    CAA records reconciled for 0 domains (3 on dns-persist-01 left ...)

That is 22 of the suite's assertions, reported as failures for long enough to
read as the environment. They are not: nothing had been added to fail on. The
port is supplied and the swallow becomes a warning, so the next time this
breaks it says so.

With a dns-01 domain that exists, the CAA guard sequence can be exercised. A
run that dies between installing the `;` guards and dropping them leaves them
behind, and the operator is told to rerun; the rerun has to work, and has to
get there without ever lifting the deny-all, because a name with no issuer CAA
is one any CA may issue for. The stranded state is planted directly -- it is
exactly what the dead run left -- so this needs no way to kill a run midway.

The half that matters is the second one. Both reusing the stranded guard and
deleting it to add a fresh one end with the same records, and only one of them
stays denied throughout, so the gap is invisible in the result. The mock
therefore records names whose issuer CAA set emptied out, and the test asserts
the domain is not among them. Reverting to delete-then-add fails it.
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.

2 participants