Skip to content
Merged
6 changes: 3 additions & 3 deletions scripts/auth_live_canary/config.example.env
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
AUTH_LIVE_GOOGLE_ACCESS_TOKEN=
AUTH_LIVE_GOOGLE_REFRESH_TOKEN=
AUTH_LIVE_GOOGLE_SCOPES=gmail.modify gmail.compose calendar.events
# Set to 0 to skip forced refresh on first probe.
AUTH_LIVE_FORCE_GOOGLE_REFRESH=1
# Space-separated full scope URLs; defaults to GOOGLE_SCOPE_DEFAULT in
# run_live_canary.py when unset.
AUTH_LIVE_GOOGLE_SCOPES=https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/gmail.modify https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events

# GitHub
AUTH_LIVE_GITHUB_TOKEN=
Expand Down
86 changes: 50 additions & 36 deletions scripts/ci/reborn-coverage-int-tier-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,68 @@
# Integration-tier (task T0-COV) is the set of in-process suites under
# tests/integration/ (post-restructure home of the roadmap integration suite;
# see docs/superpowers/specs/2026-06-26-reborn-integration-test-framework-design.md):
# - tests/integration/<name>.rs (flat [[test]] binaries; Cargo `name` is
# reborn_integration_<name>)
# - tests/integration/group_<x>/ ([[test]] binaries; Cargo `name` is
# reborn_group_<x>)
# - tests/integration/<name>.rs (flat bins; `name = reborn_integration_<name>`)
# - tests/integration/group_<x>/ (group bins; `name = reborn_group_<x>`)
# - tests/integration/<domain>/<n>.rs (domain-folder bins, e.g. auth/;
# `name = reborn_integration_<n>`)
#
# Discovery is dynamic so coverage automatically picks up new int-tier suites
# as they land (mirrors scripts/ci/run-reborn-group-tests.sh's dir->name
# rewrite and scripts/ci/run-reborn-root-partition.sh's overall shape).
# Discovery is registration-driven: the workspace Cargo.toml's `[[test]]`
# entries are the single source of truth, and every entry whose `path` sits
# under tests/integration/ is selected. Deriving candidates from a filesystem
# walk instead has already burned us once: the previous `find -maxdepth 1`
# walk could not see domain-folder bins, so the six tests/integration/auth/
# suites (oauth_connect, oauth_popup_journeys, oauth_refresh, auth_gate,
# auth_failure, reopen_resume_through_gate) ran in NO PR or merge-queue lane
# — their only executor was the push-to-main coverage workflow. Selecting
# from the registration makes a new suite impossible to register without
# also being selected, whatever directory shape it uses, and a registered
# entry whose file was deleted fails the lane loudly ("couldn't read the
# file") instead of being silently skipped.
#
# Candidate names are filtered against Cargo.toml's `[[test]] name = "..."`
# entries: not every flat tests/integration/<name>.rs file is its own binary
# — a file can be a #[path]-mounted shared-fixture sibling included by two or
# more real suites instead (see slack_pairing_fixtures.rs, mounted by
# slack_pairing_redeem.rs / slack_pairing_actor_resolution.rs), and such
# siblings have no `[[test]]` entry of their own. Without this filter, a bare
# directory scan derives a nonexistent `--test reborn_integration_<sibling>`
# arg and `cargo llvm-cov ... test` fails outright with "no test target
# named" before running anything in the lane.
# `#[path]`-mounted shared-fixture siblings (auth/common.rs,
# slack_pairing_fixtures.rs, support/) have no `[[test]]` entry and are
# therefore never selected — same reason the old walk filtered its
# candidates against the registration.

set -euo pipefail

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "${repo_root}"

mapfile -t names < <(
{
find tests/integration -maxdepth 1 -type f -name '*.rs' \
| sed -E 's#^tests/integration/#reborn_integration_#; s#\.rs$##'
find tests/integration -mindepth 1 -maxdepth 1 -type d -name 'group_*' \
-exec sh -c 'test -f "$1/main.rs"' _ {} ';' -print \
| sed -E 's#^tests/integration/group_#reborn_group_#'
} | LC_ALL=C sort -u | while IFS= read -r candidate; do
if awk -v name="${candidate}" '
/^\[\[test\]\]/ { in_test=1; next }
/^\[/ { in_test=0 }
in_test && $0 == "name = \"" name "\"" { found=1; exit }
END { exit !found }
' Cargo.toml; then
printf '%s\n' "${candidate}"
fi
done
)
# Plain string + while-read (no `mapfile`): macOS dev machines ship bash 3.2,
# and the guardrail must be runnable where it is written, not only on CI.
#
# The manifest is parsed with Python's stdlib `tomllib` (python3 is already a
# hard dependency of this lane's sibling scripts, e.g.
# scripts/ci/lib/reborn_coverage_lcov.py) so the selector accepts exactly what
# Cargo accepts — key order, spacing, and trailing comments can never drop a
# registration the way a line-regex parser could (pinned by harness case D6's
# reversed-order and compact stanzas).
names="$(
python3 - <<'PY'
import tomllib

with open("Cargo.toml", "rb") as manifest:
data = tomllib.load(manifest)

names = {
entry["name"]
for entry in data.get("test", [])
if isinstance(entry, dict)
and isinstance(entry.get("name"), str)
and isinstance(entry.get("path"), str)
and entry["path"].startswith("tests/integration/")
}
for name in sorted(names):
print(name)
PY
)"

if [ "${#names[@]}" -eq 0 ]; then
if [ -z "${names}" ]; then
echo "No Reborn integration-tier test binaries discovered" >&2
exit 1
fi

for name in "${names[@]}"; do
printf '%s\n' "${names}" | while IFS= read -r name; do
printf -- '--test\n%s\n' "${name}"
done
23 changes: 12 additions & 11 deletions scripts/ci/reborn-coverage-lane-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
# Run one instrumented Reborn integration-tier coverage lane and produce that
# lane's lcov tracefile.
#
# The 34 tests/integration/ suites (see reborn-coverage-int-tier-tests.sh for
# the canonical enumeration) are split across 5 lanes in
# The tests/integration/ suites (see reborn-coverage-int-tier-tests.sh for
# the canonical, registration-driven enumeration — flat, domain-folder, and
# group bins alike) are split across 5 lanes in
# .github/workflows/reborn-tests.yml's `reborn-integration-coverage` matrix
# job: 4 modulo-partitions of the 27 flat `reborn_integration_*` suites, plus
# one dedicated lane for all 7 `reborn_group_*` suites.
# job: 4 modulo-partitions of the `reborn_integration_*` suites, plus one
# dedicated lane for the `reborn_group_*` suites.
#
# This script is the SINGLE execution of the 34 int-tier suites for pass/fail
# This script is the SINGLE execution of the int-tier suites for pass/fail
# purposes too: `cargo llvm-cov ... test` has the same pass/fail semantics as
# `cargo test`, so there is no separate uninstrumented run of the 27 flat
# suites. (The 7 group suites also still have their own uninstrumented
# `reborn-group-tests` job via run-reborn-group-tests.sh, which stays as the
# `cargo test`, so there is no separate uninstrumented run of the
# `reborn_integration_*` suites. (The group suites also still have their own
# uninstrumented `reborn-group-tests` job via run-reborn-group-tests.sh, which stays as the
# fast low-contention pass/fail signal for that suite; this lane additionally
# runs them once more, instrumented, for coverage.)
#
Expand All @@ -36,12 +37,12 @@
# reborn_group_* rewrite rules), so this script never re-derives that mapping.
#
# Modes (REBORN_COV_LANE_MODE):
# flat-partition Modulo-partitions the 27 reborn_integration_* suites
# flat-partition Modulo-partitions the reborn_integration_* suites
# across REBORN_COV_LANE_PARTITIONS lanes; REBORN_COV_LANE_INDEX
# (0-based) selects this lane's slice — mirrors
# scripts/ci/run-reborn-root-partition.sh's partitioning.
# group Runs all reborn_group_* suites (7 total) — the one
# dedicated group coverage lane.
# group Runs all reborn_group_* suites — the one dedicated
# group coverage lane.
#
# Usage: REBORN_COV_LANE_MODE=... [other env] reborn-coverage-lane-run.sh <output-lcov-path>

Expand Down
49 changes: 44 additions & 5 deletions scripts/ci/test-reborn-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -828,11 +828,13 @@ fi
#
# The script derives its repo root from its own path and `cd`s there, so
# each case copies it into a fresh temp tree's scripts/ci/ and builds a
# tests/integration/ subtree alongside it, then invokes the copy. It also
# filters candidates against a `[[test]] name = "..."` entry in Cargo.toml
# (see that script's header comment), so every case seeds a fake Cargo.toml
# with one `[[test]]` block per fixture suite the case constructs — mirrors
# the real repo root always having a `[[test]]` entry per suite.
# tests/integration/ subtree alongside it, then invokes the copy. Discovery
# is registration-driven (see that script's header comment): every `[[test]]`
# entry in Cargo.toml whose `path` sits under tests/integration/ is selected,
# so each case seeds a fake Cargo.toml with one `[[test]]` block per fixture
# suite it constructs — mirrors the real repo root always having a `[[test]]`
# entry per suite. The on-disk fixture files are kept for tree realism; an
# unregistered file must never be selected (D6).

setup_int_tier_case() {
local case_dir="$1"
Expand Down Expand Up @@ -917,6 +919,43 @@ assert_exit_code "D5: support/ dir alongside flat suites exits 0" 0 "${CAP_RC}"
assert_eq "D5: support/ dir is not discovered as a suite" \
"$(printf -- '--test\nreborn_integration_only')" "${CAP_OUT}"

# D6: domain-folder bins (tests/integration/auth/oauth_connect.rs) are
# selected via their [[test]] registration, while a #[path]-mounted sibling
# with no [[test]] entry (auth/common.rs) is not. Pins the #6520-audit blind
# spot: the retired `find -maxdepth 1` walk could not see domain-folder bins,
# so the six tests/integration/auth/ suites ran in no PR coverage lane.
# The third stanza writes `path` BEFORE `name` and the fourth uses compact
# `key="value"` spacing with a trailing comment: Cargo accepts all of these,
# so the selector must too — a line-regex parser keyed to one formatting
# style would silently skip such stanzas and recreate the blind spot this
# case pins.
d6="${tmp_root}/d6"
setup_int_tier_case "${d6}" reborn_integration_flat
: > "${d6}/tests/integration/flat.rs"
mkdir -p "${d6}/tests/integration/auth"
: > "${d6}/tests/integration/auth/oauth_connect.rs"
: > "${d6}/tests/integration/auth/common.rs"
: > "${d6}/tests/integration/auth/pathfirst_probe.rs"
: > "${d6}/tests/integration/auth/compact_probe.rs"
cat >>"${d6}/Cargo.toml" <<'EOF'
[[test]]
name = "reborn_integration_oauth_connect"
path = "tests/integration/auth/oauth_connect.rs"

[[test]]
path = "tests/integration/auth/pathfirst_probe.rs"
name = "reborn_integration_pathfirst_probe"

[[test]]
name="reborn_integration_compact_probe" # compact TOML: no spaces, trailing comment
path="tests/integration/auth/compact_probe.rs"
EOF
Comment thread
coderabbitai[bot] marked this conversation as resolved.
capture "${d6}/scripts/ci/reborn-coverage-int-tier-tests.sh"
assert_exit_code "D6: domain-folder bin exits 0" 0 "${CAP_RC}"
assert_eq "D6: registered domain-folder bins (any key order or spacing) are selected; unregistered sibling is not" \
"$(printf -- '--test\nreborn_integration_compact_probe\n--test\nreborn_integration_flat\n--test\nreborn_integration_oauth_connect\n--test\nreborn_integration_pathfirst_probe')" \
"${CAP_OUT}"

# ---------------------------------------------------------------------------
# R. reborn-coverage-ratchet.sh (coverage-floor ratchet gate)
# ---------------------------------------------------------------------------
Expand Down
9 changes: 6 additions & 3 deletions scripts/live-canary/ACCOUNTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,16 @@ Required when enabling Gmail or Calendar probes:
- `AUTH_LIVE_GOOGLE_ACCESS_TOKEN`
- `AUTH_LIVE_GOOGLE_REFRESH_TOKEN`
- `AUTH_LIVE_GOOGLE_SCOPES`
- `AUTH_LIVE_FORCE_GOOGLE_REFRESH`

Notes:

- `AUTH_LIVE_GOOGLE_ACCESS_TOKEN` is required if a refresh token is provided.
- The runner seeds the token, then can deliberately expire the access token so
refresh is exercised on first use.
- The runner refreshes the access token harness-side before the gateway
starts (`_preflight_refresh_google_token`) so a stale CI-stored token is
fresh when seeded; the canary never reaches into persistence to expire
tokens. (The former `AUTH_LIVE_FORCE_GOOGLE_REFRESH` deliberate-expiry
flow was removed with `expire_secret_in_db`; a product-side
refresh-under-expiry proof is a tracked follow-up.)
- Gmail and Calendar share `google_oauth_token`.

Recommended scopes:
Expand Down
8 changes: 7 additions & 1 deletion tests/e2e/scenarios/test_reborn_private_tool_installs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import httpx

from reborn_webui_harness import (
client_action_id,
create_thread,
enable_reborn_global_auto_approve,
reborn_bearer_headers,
Expand Down Expand Up @@ -62,7 +63,12 @@ async def _import_tool(client: httpx.AsyncClient, base_url: str, zip_path) -> No
async def _install(client: httpx.AsyncClient, base_url: str, tool_id: str) -> None:
install = await client.post(
f"{base_url}{EXTENSIONS_BASE}/install",
json={"package_ref": _package_ref(tool_id)},
json={
"package_ref": _package_ref(tool_id),
# #6520 install contract: one distinct install gesture = one
# stable client action id (reborn_webui_harness.client_action_id).
"client_action_id": client_action_id(),
},
timeout=15,
)
assert install.status_code == 200, install.text
Expand Down
12 changes: 12 additions & 0 deletions tests/integration/extension_delivery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,18 @@ async fn telegram_update_becomes_a_turn_and_a_coordinated_reply_impl(storage: St
#[tokio::test]
async fn unbound_telegram_actor_pairs_via_web_minted_code_then_turns_attribute_to_the_paired_user(
#[case] storage: StorageMode,
) {
// Boxed like `telegram_update_becomes_a_turn_and_a_coordinated_reply`
// above: inline, this journey's future overflows the 2 MiB test-thread
// stack under llvm-cov instrumentation (main's Coverage lanes).
Box::pin(
unbound_telegram_actor_pairs_via_web_minted_code_then_turns_attribute_to_the_paired_user_impl(storage),
)
.await;
}

async fn unbound_telegram_actor_pairs_via_web_minted_code_then_turns_attribute_to_the_paired_user_impl(
storage: StorageMode,
) {
let group = RebornIntegrationGroup::builder()
.storage(storage)
Expand Down
11 changes: 11 additions & 0 deletions tests/integration/group_extensions/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod support;
// Modules are alphabetical (rustfmt reorders `mod` decls); execution order is
// set by the `report.record(...)` sequence below, not declaration order.
mod scenario_credential_extension_lifecycle_state_machine;
mod scenario_existing_member_reinstall_reconciles_to_active;
mod scenario_extension_install_github_normal_gate;
mod scenario_extension_install_instance_not_configured;
mod scenario_extension_install_reauth_gate;
Expand Down Expand Up @@ -195,6 +196,16 @@ async fn extensions_group_e2e_inner() {
scenario_google_family_install_gate_and_shared_account::run(&g).await,
);

// Scenario 11: the retired Activate action's structural successor — an
// EXISTING member's idempotent install retry reconciles setup_needed →
// active on the shared store (distinct actor via `with_actor_id`, so no
// scenario-order coupling; no remove in between; positively pins the
// intermediate setup_needed phase cross-thread).
report.record(
"existing_member_reinstall_reconciles_to_active",
scenario_existing_member_reinstall_reconciles_to_active::run(&g).await,
);

report.assert_all_passed();
}

Expand Down
Loading
Loading