Skip to content

cloud-env-check: reconcile --verify-domains against per-entry expect (#27) - #28

Merged
bdelanghe merged 1 commit into
mainfrom
claude/verify-scope-domains-x6uazr
Aug 7, 2026
Merged

cloud-env-check: reconcile --verify-domains against per-entry expect (#27)#28
bdelanghe merged 1 commit into
mainfrom
claude/verify-scope-domains-x6uazr

Conversation

@bdelanghe

Copy link
Copy Markdown
Contributor

Closes #27.

What changed

--verify-domains goes from reporting raw reachability to reconciling observation against expectation. Each allowedDomains entry may carry "expect": "reachable" | "blocked" (default reachable); red now means the record and the proxy disagree, in either direction:

expect probe result
reachable HTTP status green (unchanged)
reachable 000 red (unchanged)
blocked 000 green — was red-until-dialog-change; a deliberate recorded-but-absent entry no longer holds the gate red
blocked HTTP status red — the .github-private#316 drift, machine-caught

Design constraints honored, each proven by a test:

  • expect is repo-side annotation like reason and probe — excluded from the digest, so adopting it moves no handshake value and needs no dialog edit (test_expect_excluded_from_digest).
  • Invalid values are refused loudly (exit 1) rather than falling back to the default and un-failing the check — same posture as the typo'd-container-key refusal (test_invalid_expect_refused).
  • The dead-network INCONCLUSIVE guard narrows to expected-reachable probes: a 000 that matches expect: blocked cannot distinguish the proxy refusing from the network being gone, so it neither triggers nor vetoes the guard (test_dead_network_inconclusive_not_mass_failure).
  • Default reachable means no flag-day: every existing record (infra, front-desk-scheduler, .github-private) behaves identically until it opts in.

One posture note, per discussion: nothing here probes past anyone's block. The "blocked" in expect: blocked is our own environment's egress allowlist — the check asks our proxy "would you let me through," one GET per domain per explicit invocation, no retries, and a mismatch is fixed by editing the dialog or the record, never by circumvention. The check-3 comment now says so explicitly.

Files

  • tools/cloud-env-check.mjs — the reconcile logic, expect validation, updated check-3 header docs
  • test/test_verify_domains.py — new; 7 hermetic cases via a shimmed curl (the reachable-but-recorded-blocked direction can't be produced on demand against real hosts, and it's the direction this change exists for)
  • .github/workflows/self-test.yml — new verify-domains job running the tests, asking for the new direction by name
  • .github/workflows/env-check-drift.ymlCANONICAL_SHA256 bumped in step with the script, per the README bump procedure

Verification

test_verify_domains.py     7 tests OK  (hermetic, shimmed curl)
test_env_record.py         6 tests OK  (no regression)
check_env_check_digest.py  pin matches (ee7db97b…, 15524 bytes)

Smoke-tested against .github-private's real record with the modified script: --print-digest still yields 840af7c900b1 (digest unmoved, as designed) and a live --verify-domains still reports allowlist ✓ 5/5.

Not in this PR

Step 4 of the bump procedure — re-vendoring into each adopter and bumping caller pins — follows per-repo after merge, which is exactly the drift env-check-drift.yml makes visible in the meantime. .github-private initially adopts with no expect: blocked entries (both formerly-absent hosts are now carried); the field is for the next deliberate recorded-but-absent entry, which is the state the convention exists for.


Generated by Claude Code

…27)

The check reported what each host answered; it had no notion of what the
record claimed the answer would be, so claim and observation could invert
silently — .github-private#316 exactly: two entries recorded as blocked kept
probing green after a dialog update, caught by a human reading prose.

Each allowedDomains entry may now carry "expect": "reachable" | "blocked"
(default "reachable", so every existing record behaves identically until it
opts in). Red means the record and the proxy disagree, in either direction:

  expect      probe   result
  reachable   status  green (unchanged)
  reachable   000     red   (unchanged)
  blocked     000     green (was red-until-dialog-change — a deliberate
                      recorded-but-absent entry no longer holds the gate red)
  blocked     status  red   (the #316 drift, machine-caught)

"expect" is repo-side annotation like "reason" and "probe": excluded from
the digest, so adopting it moves no handshake value and needs no dialog
edit — proven by test. An invalid value is refused loudly rather than
falling back to the default and un-failing the check, same posture as the
typo'd-container-key refusal. The dead-network INCONCLUSIVE guard narrows
to expected-reachable probes: a 000 matching expect: blocked can neither
trigger nor veto it.

Tests run hermetically via a shimmed curl — the reachable-but-recorded-
blocked direction cannot be produced on demand against real hosts, and it
is the direction the change exists for. New self-test job asks for it by
name. CANONICAL_SHA256 bumped in step with the script per README; step-4
re-vendor into adopters follows separately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015u76VQjvDnvZVAX8pcM9m6
@bdelanghe
bdelanghe marked this pull request as ready for review August 7, 2026 20:05
@bdelanghe
bdelanghe merged commit fabeb10 into main Aug 7, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Front Desk Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

cloud-env-check: --verify-domains should reconcile against a per-entry expect, not report raw reachability

2 participants