Skip to content

ci: migrate e2e tests from EKS/Kubernetes to GitHub runners#927

Merged
scarmuega merged 11 commits into
mainfrom
ci/e2e-github-runners
Jun 13, 2026
Merged

ci: migrate e2e tests from EKS/Kubernetes to GitHub runners#927
scarmuega merged 11 commits into
mainfrom
ci/e2e-github-runners

Conversation

@scarmuega

@scarmuega scarmuega commented Jun 12, 2026

Copy link
Copy Markdown
Member

PR 3 of 3 in the e2e-on-GitHub-runners sequence: ① work_stats filter (#928) → ② pipeline termination exit code (#929) → ③ this. Based on #929; retarget to main as the stack merges.

Context

The e2e suite ran on an external EKS cluster: build an image, assume an AWS role, kubectl apply a Job per test, gate on kubectl wait. This migrates it to run entirely on GitHub-hosted runners and deletes the cluster dependency. The configs are also rewritten for the oura v2 schema — they had rotted on v1 (peers/socket_path, top-level [chain]/[intersect], filter pipelines).

Changes

  • Workflow: drop the prepare job (EKS kubeconfig/namespace/IRSA). Each leg runs the release image via docker run + timeout; exit 0 = pass (WorkStats finalize, feat: add work_stats filter with finalization policy #928 + fix: bump gasket to 0.10 and derive exit code from finalization #929), non-zero = fail (Assert panic), 124 = hang.
  • Configs: extracted from k8s ConfigMaps into .github/e2e/configs/*.toml, v2 schema, WorkStats finalization per leg; n2n legs point at the per-network Demeter relays (:3000 mainnet / :3002 preview).
  • Scripts: run/dmtrcli logic lives in .github/e2e/scripts/ instead of inlined YAML.
  • u5c legs (mainnet/preprod/preview): the manual tmp_u5c_test checks, converted to the standard gate; doubles as a x=grpc error when using u5c demeter source #921 regression test. Keys parameterized as ${DMTR_UTXORPC_KEY_*} secrets. Includes the rustls default-CryptoProvider fix the u5c TLS path needs in multi-provider builds.
  • n2c legs use a Demeter dmtrcli socket port-forward (placeholder commands; DMTR_API_KEY secret) and are continue-on-error until that path is finalized.

Secrets required

DMTR_UTXORPC_KEY_{MAINNET,PREPROD,PREVIEW}, DMTR_API_KEY, and working AWS creds for the OuraE2ETest role (the last live run failed role-assumption: "security token invalid").

Verification

  • All 12 configs parse and bootstrap against the current binary; fmt/clippy/tests green.
  • Live workflow_dispatch run validated the mechanics (build + image + streaming); the remaining reds were the AWS creds above, the Assert sink on Conway-era blocks (separate issue), and the placeholder n2c legs.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Chores

    • Migrated end-to-end testing infrastructure from Kubernetes/EKS to GitHub-hosted runners with containerized test execution.
    • Consolidated test configuration into TOML files for improved maintainability.
  • New Features

    • Added support for U5C (UTXORPC) data source across mainnet, preprod, and preview networks.
    • Integrated Rustls TLS provider for secure UTXORPC connections.

@scarmuega scarmuega requested a review from paulobressan as a code owner June 12, 2026 19:30
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates E2E testing infrastructure from Kubernetes manifests to TOML-based scenario configurations and GitHub runner execution, while adding rustls TLS crypto provider initialization for the U5C feature. Eight Kubernetes YAML manifests are removed and replaced with fourteen TOML scenarios and three helper scripts. The workflow shifts from EKS-based orchestration to runner-based matrix execution.

Changes

E2E Infrastructure Migration

Layer / File(s) Summary
Scenario TOML configurations
.github/e2e/configs/assert-n2c-*.toml, .github/e2e/configs/assert-n2n-*.toml, .github/e2e/configs/aws-*.toml, .github/e2e/configs/u5c-*.toml
Fourteen new TOML files define E2E scenarios: N2C/N2N assertion tests for preview and mainnet (origin and tip blocks), AWS sink integrations (Lambda/S3/SQS), and U5C UTXORPC tip-block tests with configurable sources, intersections, filters, and sinks.
Test execution and tunnel scripts
.github/e2e/scripts/run-test.sh, .github/e2e/scripts/setup-dmtr-socket.sh, .github/e2e/scripts/stop-dmtr-tunnel.sh
run-test.sh renders per-scenario TOML config and executes containerized tests with conditional AWS/n2c mounts. setup-dmtr-socket.sh installs dmtrcli, authenticates with DMTR_API_KEY, creates a background tunnel, and polls for socket readiness. stop-dmtr-tunnel.sh performs best-effort tunnel cleanup.
GitHub Actions workflow refactor
.github/workflows/e2e.yaml
Workflow now builds and publishes a single GHCR image with GitHub Actions cache, runs E2E matrix scenarios directly on ubuntu-latest runners, conditionally configures AWS credentials only for aws scenarios and n2c setup only for n2c scenarios, executes run-test.sh with scenario-specific environment variables, and performs n2c cleanup in an always() step.

U5C TLS Crypto Provider Initialization

Layer / File(s) Summary
Cargo feature and dependency setup
Cargo.toml
The u5c feature definition now includes the optional rustls dependency (with ring feature enabled and default-features = false) alongside existing utxorpc and futures dependencies.
Rustls crypto provider initialization
src/bin/oura/main.rs
An early startup #[cfg(feature = "u5c")] block installs Rustls's default ring crypto provider via install_default() before any other logic runs, preventing panics during first TLS handshake in builds that include multiple Rustls crypto providers.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • paulobressan

🐰 The runners race to replace the pods,
TOML configs whisper where YAML once flowed,
Rustls claims the TLS crown with a ring so bright,
E2E dreams now dance on GitHub's light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: migrating the e2e test infrastructure from EKS/Kubernetes to GitHub runners, which is the core focus of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/e2e-github-runners

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
src/filters/work_stats.rs (3)

64-66: ⚡ Quick win

Cloning ChainEvent on every message may cause performance overhead.

Every event is cloned before being forwarded downstream. Since ChainEvent::Record can contain large payloads like CborBlock or ParsedBlock, this clone operation may become a bottleneck in high-throughput scenarios.

Consider measuring the performance impact in production. If cloning proves expensive, a potential optimization would be to refactor the filter to operate on gasket::messaging::Message<ChainEvent> directly (forwarding the message itself rather than extracting and re-wrapping the payload), though this may require changes to the gasket worker pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/filters/work_stats.rs` around lines 64 - 66, The current execute method
clones every ChainEvent before forwarding
(stage.output.send(unit.clone().into()).await...), which is costly for
ChainEvent::Record payloads like CborBlock/ParsedBlock; change the filter to
forward the existing gasket::messaging::Message<ChainEvent> (or otherwise
borrow/move the payload) instead of cloning: update the worker signature or
wiring so execute receives and forwards the Message<ChainEvent> directly (or
uses into_inner/move semantics) and replace the unit.clone().into() call with a
send of the original message, ensuring no extra copies of large payloads are
made.

97-126: ⚡ Quick win

Consider adding unit tests for WorkStats filter logic.

The WorkStats filter contains non-trivial stateful logic—tracking block counts, enforcing finalization policy, and coordinating pipeline shutdown—but has no dedicated unit tests. While framework/mod.rs tests the should_finalize function, the filter's integration of metrics, state management, and the finished-flag lifecycle remains untested.

Consider adding tests that:

  • Verify block counting increments only on Apply events
  • Confirm the filter forwards events unchanged
  • Validate that WorkSchedule::Done is returned after finalization
  • Test that Undo/Reset events don't increment block_count but do participate in slot-based finalization
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/filters/work_stats.rs` around lines 97 - 126, Add unit tests for the
WorkStats filter to cover its stateful behaviors: use Config::bootstrapper to
construct a Stage (or directly instantiate Stage/FinalizeConfig with fields
until_hash, max_block_slot, max_block_quantity) then simulate sequences of
events to assert that (1) block_count only increments on Apply events, (2)
events are forwarded unchanged by the filter, (3) after the finalization
conditions the filter returns WorkSchedule::Done, and (4) Undo/Reset events do
not increment block_count but still participate in slot-based finalization
checks; create test cases that drive Stage/WorkStats through Apply/Undo/Reset
and slot changes and assert the expected block_count, forwarded outputs, and
finalization result.

71-80: ⚡ Quick win

Observability gap: latest_slot gauge excludes Undo/Reset events.

The latest_slot gauge is only updated when processing Apply events (line 75), but the finalization policy at line 84 evaluates the point from all event types including Undo and Reset. This inconsistency means the gauge won't reflect the actual "latest point" that the finalization logic considers, reducing observability during rollbacks or resets.

📊 Proposed fix to update gauge for all event types
         let point = match unit {
             ChainEvent::Apply(point, _) => {
                 self.blocks += 1;
                 stage.block_count.inc(1);
-                stage.latest_slot.set(point.slot_or_default() as i64);
                 point.clone()
             }
             ChainEvent::Undo(point, _) => point.clone(),
             ChainEvent::Reset(point) => point.clone(),
         };
 
+        stage.latest_slot.set(point.slot_or_default() as i64);
+
         stage.ops_count.inc(1);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/filters/work_stats.rs` around lines 71 - 80, The latest_slot gauge is
only updated in the ChainEvent::Apply branch but the variable point (used later
by the finalization policy) can come from Apply, Undo, or Reset; update
stage.latest_slot for all branches so the gauge reflects the actual point the
finalization logic uses—i.e., after you set point in the match over ChainEvent
(variants ChainEvent::Apply, ChainEvent::Undo, ChainEvent::Reset), call
stage.latest_slot.set(point.slot_or_default() as i64) in each branch (keep
self.blocks increment and stage.block_count.inc(1) only in the ChainEvent::Apply
branch).
.github/e2e/configs/aws-lambda-10-blocks.toml (1)

22-25: ⚡ Quick win

Consider parameterizing the AWS account ID in the Lambda ARN.

The Lambda function ARN contains a hardcoded AWS account ID (295114534192). While this may be acceptable for E2E test configurations, consider using an environment variable or GitHub Actions secret to avoid hardcoding infrastructure details in version control.

This improves maintainability if the test account changes and reduces exposure of account identifiers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/e2e/configs/aws-lambda-10-blocks.toml around lines 22 - 25, The
Lambda ARN in the [sink] block for type "AwsLambda" hardcodes the AWS account ID
(295114534192) in the function_name value; replace that hardcoded account ID
with a parameter sourced from an environment variable or CI secret (e.g.,
interpolate a variable like ${AWS_ACCOUNT_ID} or use a GitHub Actions secret) so
the function_name ARN is constructed at runtime instead of committed with the
literal account number.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e.yaml:
- Around line 115-119: The socket-wait loop around the path
"${RUNNER_TEMP}/sockets/node0.socket" can exit after retries without the socket
actually existing, delaying failure until later; after the for loop that checks
-S and sleeps (the loop using seq 1 30), add a post-loop test that fails the job
immediately if the socket still doesn't exist (e.g., check [ -S
"${RUNNER_TEMP}/sockets/node0.socket" ] and exit 1 with a clear error message)
so the broken tunnel setup errors fast rather than consuming downstream
timeouts.
- Around line 70-72: The job-level continue-on-error: ${{ matrix.kind == 'n2c'
}} hides all n2c failures; remove that job-level setting and instead apply
continue-on-error only to the specific step that performs the Demeter `dmtrcli`
port-forward/bootstrap (e.g., the step named like "start dmtrcli port-forward"
or "wait for dmtrcli"); update that step to include continue-on-error: true and
keep the job failing for any other step errors so real regressions (image pulls,
daemon panics, test assertions) still mark the workflow red.
- Around line 17-23: CI workflow uses floating action tags and runs a remote
install script insecurely; update every `uses:` entry (e.g.,
actions/checkout@v4, docker/setup-buildx-action@v3, docker/login-action@v3,
docker/build-push-action@v6, aws-actions/configure-aws-credentials@v4) to pinned
commit SHAs, replace the `curl .../demeter-run/cli/.../install.sh | sh`
invocation with a download of a specific release/commit and verify via
checksum/signature before executing, change `continue-on-error: ${{ matrix.kind
== 'n2c' }}` from job-level to a narrowly scoped step-level flag or remove it so
failures bubble unless only the specific tunnel/socket step is expected to be
flaky, and after the `seq 1 30` loop that waits for
${RUNNER_TEMP}/sockets/node0.socket add an explicit existence check that fails
the job immediately with a clear error if the socket file was not created (to
avoid burning full timeout in subsequent `timeout 1800 docker run ...`).
- Around line 108-113: Replace the unsafe pipe to shell invocation "curl -fsSL
https://raw.githubusercontent.com/demeter-run/cli/main/install.sh | sh" with a
pinned download + integrity check: fetch a specific release/tag/commit URL (or
its tarball) into a temp file, verify its SHA256 (or GPG) checksum, and only
then run it (or use a packaged release binary); update the workflow step that
currently runs that curl|sh line to download to
"${RUNNER_TEMP}/demeter_install.sh", verify the checksum against a stored value
(or fetch a signed checksum and verify signature), and exec the vetted file
instead of piping directly to sh.

---

Nitpick comments:
In @.github/e2e/configs/aws-lambda-10-blocks.toml:
- Around line 22-25: The Lambda ARN in the [sink] block for type "AwsLambda"
hardcodes the AWS account ID (295114534192) in the function_name value; replace
that hardcoded account ID with a parameter sourced from an environment variable
or CI secret (e.g., interpolate a variable like ${AWS_ACCOUNT_ID} or use a
GitHub Actions secret) so the function_name ARN is constructed at runtime
instead of committed with the literal account number.

In `@src/filters/work_stats.rs`:
- Around line 64-66: The current execute method clones every ChainEvent before
forwarding (stage.output.send(unit.clone().into()).await...), which is costly
for ChainEvent::Record payloads like CborBlock/ParsedBlock; change the filter to
forward the existing gasket::messaging::Message<ChainEvent> (or otherwise
borrow/move the payload) instead of cloning: update the worker signature or
wiring so execute receives and forwards the Message<ChainEvent> directly (or
uses into_inner/move semantics) and replace the unit.clone().into() call with a
send of the original message, ensuring no extra copies of large payloads are
made.
- Around line 97-126: Add unit tests for the WorkStats filter to cover its
stateful behaviors: use Config::bootstrapper to construct a Stage (or directly
instantiate Stage/FinalizeConfig with fields until_hash, max_block_slot,
max_block_quantity) then simulate sequences of events to assert that (1)
block_count only increments on Apply events, (2) events are forwarded unchanged
by the filter, (3) after the finalization conditions the filter returns
WorkSchedule::Done, and (4) Undo/Reset events do not increment block_count but
still participate in slot-based finalization checks; create test cases that
drive Stage/WorkStats through Apply/Undo/Reset and slot changes and assert the
expected block_count, forwarded outputs, and finalization result.
- Around line 71-80: The latest_slot gauge is only updated in the
ChainEvent::Apply branch but the variable point (used later by the finalization
policy) can come from Apply, Undo, or Reset; update stage.latest_slot for all
branches so the gauge reflects the actual point the finalization logic
uses—i.e., after you set point in the match over ChainEvent (variants
ChainEvent::Apply, ChainEvent::Undo, ChainEvent::Reset), call
stage.latest_slot.set(point.slot_or_default() as i64) in each branch (keep
self.blocks increment and stage.block_count.inc(1) only in the ChainEvent::Apply
branch).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0ac7801-b0ad-4255-8170-28d746ea7dac

📥 Commits

Reviewing files that changed from the base of the PR and between a6a1cac and 3d25eb2.

📒 Files selected for processing (24)
  • .github/e2e/assert-n2c-preview-origin-blocks.yaml
  • .github/e2e/assert-n2c-preview-tip-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-origin-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-tip-blocks.yaml
  • .github/e2e/assert-n2n-preview-origin-blocks.yaml
  • .github/e2e/assert-n2n-preview-tip-blocks.yaml
  • .github/e2e/aws-lambda-10-blocks.yaml
  • .github/e2e/aws-s3-500-blocks.yaml
  • .github/e2e/aws-sqs-10-blocks.yaml
  • .github/e2e/configs/assert-n2c-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2c-preview-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-tip-blocks.toml
  • .github/e2e/configs/aws-lambda-10-blocks.toml
  • .github/e2e/configs/aws-s3-500-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
  • .github/e2e/gcp-pubsub-10-blocks.yaml
  • .github/e2e/serviceaccount.yaml
  • .github/workflows/e2e.yaml
  • src/filters/mod.rs
  • src/filters/work_stats.rs
  • src/framework/mod.rs
💤 Files with no reviewable changes (11)
  • .github/e2e/assert-n2n-mainnet-origin-blocks.yaml
  • .github/e2e/assert-n2n-preview-tip-blocks.yaml
  • .github/e2e/gcp-pubsub-10-blocks.yaml
  • .github/e2e/aws-s3-500-blocks.yaml
  • .github/e2e/aws-lambda-10-blocks.yaml
  • .github/e2e/aws-sqs-10-blocks.yaml
  • .github/e2e/assert-n2n-preview-origin-blocks.yaml
  • .github/e2e/assert-n2c-preview-origin-blocks.yaml
  • .github/e2e/serviceaccount.yaml
  • .github/e2e/assert-n2n-mainnet-tip-blocks.yaml
  • .github/e2e/assert-n2c-preview-tip-blocks.yaml

Comment on lines 17 to 23
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
- name: Login to GHCR
uses: docker/login-action@v3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the referenced workflow with line numbers around the build/test jobs.
echo "=== .github/workflows/e2e.yaml (lines 1-220) ==="
nl -ba .github/workflows/e2e.yaml | sed -n '1,220p'

echo "=== Search for unpinned uses: (actions/*) and specific actions mentioned ==="
rg -n "uses:\s*(actions/checkout|docker/setup-buildx-action|docker/login-action|aws-actions/configure-aws-credentials|aws-actions/|docker/)[`@a-zA-Z0-9_./-`]*" .github/workflows/e2e.yaml

echo "=== Search for remote script execution patterns (curl | sh, bash -c, pipe to sh) ==="
rg -n "(curl|wget)\s+.*\|\s*(sh|bash)" .github/workflows/e2e.yaml
rg -n "raw\.githubusercontent\.com.*\|\s*(sh|bash)" .github/workflows/e2e.yaml
rg -n "run:\s*.*\|\s*(sh|bash)" .github/workflows/e2e.yaml

echo "=== Check continue-on-error usage and where it is applied ==="
rg -n "continue-on-error" .github/workflows/e2e.yaml

echo "=== Inspect any socket wait loop / timeout handling ==="
rg -n "(socket|wait|nc -z|nc |/dev/tcp|localhost|timeout|sleep)" .github/workflows/e2e.yaml

Repository: txpipe/oura

Length of output: 165


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Repo tree for workflow files ==="
ls -R .github/workflows || true

echo "=== Show .github/workflows/e2e.yaml (with line numbers) ==="
awk '{print NR "\t" $0}' .github/workflows/e2e.yaml | sed -n '1,260p'

echo "=== Search for unpinned uses: (actions/* and docker/aws actions) ==="
rg -n "uses:\s*(actions/checkout|docker/setup-buildx-action|docker/login-action|aws-actions/configure-aws-credentials|aws-actions/|docker/)[`@a-zA-Z0-9_./-`]*" .github/workflows/e2e.yaml || true

echo "=== Search for remote script execution patterns (curl|wget piped to sh/bash) ==="
rg -n "(curl|wget)\s+.*\|\s*(sh|bash)" .github/workflows/e2e.yaml || true
rg -n "raw\.githubusercontent\.com.*\|\s*(sh|bash)" .github/workflows/e2e.yaml || true
rg -n "run:\s*.*\|\s*(sh|bash)" .github/workflows/e2e.yaml || true

echo "=== Search for continue-on-error usage and where it is applied ==="
rg -n "continue-on-error" .github/workflows/e2e.yaml || true

echo "=== Inspect any socket wait loop / timeout handling ==="
rg -n "(socket|wait|nc -z|nc |/dev/tcp|localhost|timeout|sleep)" .github/workflows/e2e.yaml || true

Repository: txpipe/oura

Length of output: 7909


Pin CI GitHub Actions to immutable commit SHAs (and harden remote script execution).

  • Unpinned uses: tags: actions/checkout@v4, docker/setup-buildx-action@v3, docker/login-action@v3, docker/build-push-action@v6, and aws-actions/configure-aws-credentials@v4 (both build and test jobs) should be pinned to commit SHAs.
  • curl .../demeter-run/cli/.../install.sh | sh executes a mutable remote script in CI—pin to a fixed commit/release and verify integrity (checksum/signature).
  • continue-on-error: ${{ matrix.kind == 'n2c' }} at the job level suppresses all n2c regressions; scope it narrowly (e.g., step-level) or fail the job when the tunnel/socket can’t be established.
  • The n2c socket wait loop (seq 1 30 with sleep 2) doesn’t assert socket existence after the loop; if the socket never appears, timeout 1800 docker run ... can burn the full 30 minutes—add a post-loop failure when ${RUNNER_TEMP}/sockets/node0.socket isn’t created.
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 20-20: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yaml around lines 17 - 23, CI workflow uses floating
action tags and runs a remote install script insecurely; update every `uses:`
entry (e.g., actions/checkout@v4, docker/setup-buildx-action@v3,
docker/login-action@v3, docker/build-push-action@v6,
aws-actions/configure-aws-credentials@v4) to pinned commit SHAs, replace the
`curl .../demeter-run/cli/.../install.sh | sh` invocation with a download of a
specific release/commit and verify via checksum/signature before executing,
change `continue-on-error: ${{ matrix.kind == 'n2c' }}` from job-level to a
narrowly scoped step-level flag or remove it so failures bubble unless only the
specific tunnel/socket step is expected to be flaky, and after the `seq 1 30`
loop that waits for ${RUNNER_TEMP}/sockets/node0.socket add an explicit
existence check that fails the job immediately with a clear error if the socket
file was not created (to avoid burning full timeout in subsequent `timeout 1800
docker run ...`).

Source: Linters/SAST tools

Comment thread .github/workflows/e2e.yaml Outdated
Comment thread .github/workflows/e2e.yaml Outdated
Comment thread .github/workflows/e2e.yaml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml:
- Around line 3-7: The peers array named "peers" currently lists a single host
("relay.cnode-m1.demeter.run:3000"), which is a single point of failure; update
the peers array to include at least one additional independent hostname/provider
(different domain) and port (e.g., another relay host) so the N2N leg has
redundancy; modify the peers value (the peers array) to contain multiple entries
on different hosts/providers and ensure entries use the same port format as
existing entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00ffcb96-fdb1-44c0-acc5-1742bf553b50

📥 Commits

Reviewing files that changed from the base of the PR and between 3d25eb2 and ea0f484.

📒 Files selected for processing (5)
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • .github/e2e/configs/aws-lambda-10-blocks.toml
  • .github/e2e/configs/aws-s3-500-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
✅ Files skipped from review due to trivial changes (1)
  • .github/e2e/configs/aws-s3-500-blocks.toml
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
  • .github/e2e/configs/aws-lambda-10-blocks.toml

Comment on lines +3 to +7
peers = [
"relay.cnode-m1.demeter.run:3000",
"relay.cnode-m1.demeter.run:3001",
"relay.cnode-m1.demeter.run:3002",
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether N2N config redundancy is host-diverse across E2E scenarios.
# Expected: For resilient setups, each scenario should ideally contain >1 unique hostname.

set -euo pipefail

fd -p '.github/e2e/configs/*.toml' | while read -r f; do
  if rg -n '^\[source\]' "$f" >/dev/null && rg -n 'type\s*=\s*"N2N"' "$f" >/dev/null; then
    echo "=== $f ==="
    rg -n 'relay|peers|type\s*=\s*"N2N"' "$f" -A6 -B1
    python - "$f" <<'PY'
import re,sys
p=sys.argv[1]
txt=open(p).read()
hosts=re.findall(r'"([^":]+):\d+"', txt)
u=sorted(set(hosts))
print("unique_hosts:", u)
print("unique_host_count:", len(u))
PY
    echo
  fi
done

Repository: txpipe/oura

Length of output: 37


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== File contents: .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml ==="
nl -ba .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml | sed -n '1,120p'

echo
echo "=== Peer host extraction for N2N configs under .github/e2e/configs ==="
# List all TOML files, then filter to those with N2N source.type; for each, extract peer hostnames (host:port)
python3 - <<'PY'
import pathlib, re
root = pathlib.Path(".github/e2e/configs")
files = sorted(root.glob("*.toml"))
n2n = []
for p in files:
    txt = p.read_text(encoding="utf-8")
    if re.search(r'^\s*type\s*=\s*"N2N"\s*$', txt, re.M):
        n2n.append(p)
def hosts_from_peers(txt):
    # Capture hostname part of "hostname:port"
    return re.findall(r'"([^":]+):\d+"', txt)
for p in n2n:
    txt = p.read_text(encoding="utf-8")
    hs = sorted(set(hosts_from_peers(txt)))
    print(p.relative_to(pathlib.Path(".")))
    print("  unique_hosts_count:", len(hs))
    print("  unique_hosts:", hs)
PY

echo
echo "=== Exact peers list for the target file ==="
rg -n '^\s*peers\s*=\s*\[|relay\.cnode-m1\.demeter\.run|\"[^\"]+:\d+\"' .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml

Repository: txpipe/oura

Length of output: 194


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== File contents (numbered): .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml ==="
awk '{printf "%5d %s\n", NR, $0}' .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml | sed -n '1,140p'

echo
echo "=== Exact peers-related lines in target file ==="
rg -n '^\s*peers\s*=\s*\[|relay\.cnode-m1\.demeter\.run|\"[^\"]+:\d+\"' .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml || true

echo
echo "=== Unique peer hostnames for all N2N configs under .github/e2e/configs ==="
python3 - <<'PY'
import pathlib, re
root = pathlib.Path(".github/e2e/configs")
files = sorted(root.glob("*.toml"))

def is_n2n(txt: str) -> bool:
    return re.search(r'^\s*type\s*=\s*"N2N"\s*$', txt, re.M) is not None

def hosts_from_peers(txt: str):
    # hostname portion of "hostname:port"
    return re.findall(r'"([^":]+):\d+"', txt)

for p in files:
    txt = p.read_text(encoding="utf-8")
    if not is_n2n(txt):
        continue
    hs = sorted(set(hosts_from_peers(txt)))
    print(p.relative_to(pathlib.Path(".")))
    print("  unique_hosts_count:", len(hs))
    print("  unique_hosts:", hs)
PY

Repository: txpipe/oura

Length of output: 1771


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import glob, re, pathlib

def parse_n2n_peers(path: str):
    txt = pathlib.Path(path).read_text(encoding="utf-8")
    if 'type = "N2N"' not in txt:
        return None
    pairs = re.findall(r'"([^":]+):(\d+)"', txt)  # [(host, port), ...]
    endpoints = [f"{h}:{p}" for h,p in pairs]
    hosts = [h for h,_ in pairs]
    return {
        "file": path,
        "peer_entries": len(endpoints),
        "unique_endpoints": len(set(endpoints)),
        "unique_hosts": len(set(hosts)),
        "hosts": sorted(set(hosts)),
        "endpoints": sorted(set(endpoints)),
    }

paths = sorted(glob.glob(".github/e2e/configs/*.toml"))
for p in paths:
    r = parse_n2n_peers(p)
    if not r:
        continue
    print(f"\n=== {r['file']} ===")
    print(f"peer_entries: {r['peer_entries']}")
    print(f"unique_hosts: {r['unique_hosts']} ({r['hosts']})")
    print(f"unique_endpoints: {r['unique_endpoints']} ({r['endpoints']})")
    if r["peer_entries"] < 2 or r["unique_hosts"] < 2:
        print("FLAG: insufficient redundancy/failover (add more peers, ideally on different hostnames/providers)")
PY

Repository: txpipe/oura

Length of output: 2023


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import glob, re, pathlib

for p in sorted(glob.glob(".github/e2e/configs/*.toml")):
    txt = pathlib.Path(p).read_text(encoding="utf-8")
    if 'type = "N2N"' not in txt:
        continue
    pairs = re.findall(r'"([^":]+):(\d+)"', txt)  # (host, port)
    hosts = sorted(set(h for h,_ in pairs))
    print(f"{p}: peer_entries={len(pairs)}, unique_hosts={len(hosts)}, hosts={hosts}")
PY

Repository: txpipe/oura

Length of output: 903


Diversify N2N peers across independent hosts/providers (no failover today)

In .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml (lines 3-7), peers contains a single endpoint (relay.cnode-m1.demeter.run:3000). A host/domain incident can take down the entire N2N leg and make CI flaky. Add at least one additional peers entry on a different hostname/provider.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml around lines 3 - 7,
The peers array named "peers" currently lists a single host
("relay.cnode-m1.demeter.run:3000"), which is a single point of failure; update
the peers array to include at least one additional independent hostname/provider
(different domain) and port (e.g., another relay host) so the N2N leg has
redundancy; modify the peers value (the peers array) to contain multiple entries
on different hosts/providers and ensure entries use the same port format as
existing entries.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/e2e/configs/aws-s3-500-blocks.toml (1)

16-17: ⚠️ Potential issue | 🟠 Major

Align aws-s3-500-blocks.toml with SplitBlock+ParseCbor cloud-sink pipeline (or document why S3 differs).

AWS filter pipelines are inconsistent:

  • .github/e2e/configs/aws-lambda-10-blocks.toml: WorkStats → SplitBlock → ParseCbor
  • .github/e2e/configs/aws-sqs-10-blocks.toml: WorkStats → SplitBlock → ParseCbor
  • .github/e2e/configs/aws-s3-500-blocks.toml (lines 16-17): WorkStats → ParseCbor (no SplitBlock)

If SplitBlock is required per the PR objectives, add [[filters]] type = "SplitBlock" to the S3 config before ParseCbor; otherwise add an explicit note explaining why S3 should omit it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/e2e/configs/aws-s3-500-blocks.toml around lines 16 - 17, The
pipeline for the S3 config is missing the SplitBlock filter before ParseCbor;
update the filters so the sequence is WorkStats → SplitBlock → ParseCbor by
inserting a [[filters]] block with type = "SplitBlock" immediately before the
existing ParseCbor filter, or if S3 must intentionally omit SplitBlock, add a
short comment/documentation in that config explaining why SplitBlock is not
applicable; reference the filter types "SplitBlock" and "ParseCbor" to locate
the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/e2e/configs/aws-s3-500-blocks.toml:
- Around line 16-17: The pipeline for the S3 config is missing the SplitBlock
filter before ParseCbor; update the filters so the sequence is WorkStats →
SplitBlock → ParseCbor by inserting a [[filters]] block with type = "SplitBlock"
immediately before the existing ParseCbor filter, or if S3 must intentionally
omit SplitBlock, add a short comment/documentation in that config explaining why
SplitBlock is not applicable; reference the filter types "SplitBlock" and
"ParseCbor" to locate the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de440e07-3eb3-4a0b-bdd9-26821f8b998f

📥 Commits

Reviewing files that changed from the base of the PR and between ea0f484 and 82eb01d.

📒 Files selected for processing (7)
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-tip-blocks.toml
  • .github/e2e/configs/aws-lambda-10-blocks.toml
  • .github/e2e/configs/aws-s3-500-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/e2e/configs/aws-sqs-10-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-origin-blocks.toml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/e2e/scripts/setup-dmtr-socket.sh:
- Around line 25-28: The wait loop that polls for the socket at
"${RUNNER_TEMP}/sockets/node0.socket" can exit after the retries without the
socket actually existing; add a post-loop assertion that checks if the socket
file exists and if not prints an error to stderr and exits non-zero (e.g., with
exit 1) so the CI fails fast instead of letting downstream scripts like
run-test.sh hang; update the block around the seq loop to perform this existence
check and failure path immediately after the loop.

In `@src/bin/oura/run_daemon.rs`:
- Around line 99-101: When Arc::try_unwrap(daemon) returns Err the current code
silently skips calling daemon.teardown(), risking resource leaks; update the
block around Arc::try_unwrap(daemon) so that on Err(e) you log a warning
(including the Arc strong_count and/or debug info) indicating teardown could not
be performed and why, and keep the existing path that calls daemon.teardown()
when try_unwrap succeeds (referencing Arc::try_unwrap, the local variable
daemon, and daemon.teardown()). Ensure the warning uses the project's logger
(e.g., tracing::warn! or the existing logger) and includes enough context to
debug remaining references.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12d3e203-9280-494c-83f4-9288062fb5f3

📥 Commits

Reviewing files that changed from the base of the PR and between 82eb01d and 4b32d49.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .github/e2e/configs/u5c-mainnet-tip-blocks.toml
  • .github/e2e/configs/u5c-preprod-tip-blocks.toml
  • .github/e2e/configs/u5c-preview-tip-blocks.toml
  • .github/e2e/scripts/run-test.sh
  • .github/e2e/scripts/setup-dmtr-socket.sh
  • .github/e2e/scripts/stop-dmtr-tunnel.sh
  • .github/workflows/e2e.yaml
  • Cargo.toml
  • src/bin/oura/console.rs
  • src/bin/oura/dump.rs
  • src/bin/oura/main.rs
  • src/bin/oura/run_daemon.rs
  • src/bin/oura/watch.rs
  • src/daemon/mod.rs
✅ Files skipped from review due to trivial changes (2)
  • .github/e2e/scripts/stop-dmtr-tunnel.sh
  • .github/e2e/configs/u5c-preview-tip-blocks.toml

Comment on lines +25 to +28
for _ in $(seq 1 30); do
if [ -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then break; fi
sleep 2
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add a post-loop check to fail fast if the socket never appears.

The wait loop exits after ~60 seconds regardless of whether the socket was created. Without an assertion, run-test.sh will consume its full 30-minute timeout on a broken tunnel.

🛠️ Proposed fix
 for _ in $(seq 1 30); do
   if [ -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then break; fi
   sleep 2
 done
+
+if [ ! -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then
+  echo "ERROR: socket did not appear within 60 seconds" >&2
+  exit 1
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for _ in $(seq 1 30); do
if [ -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then break; fi
sleep 2
done
for _ in $(seq 1 30); do
if [ -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then break; fi
sleep 2
done
if [ ! -S "${RUNNER_TEMP}/sockets/node0.socket" ]; then
echo "ERROR: socket did not appear within 60 seconds" >&2
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/e2e/scripts/setup-dmtr-socket.sh around lines 25 - 28, The wait loop
that polls for the socket at "${RUNNER_TEMP}/sockets/node0.socket" can exit
after the retries without the socket actually existing; add a post-loop
assertion that checks if the socket file exists and if not prints an error to
stderr and exits non-zero (e.g., with exit 1) so the CI fails fast instead of
letting downstream scripts like run-test.sh hang; update the block around the
seq loop to perform this existence check and failure path immediately after the
loop.

Comment thread src/bin/oura/run_daemon.rs Outdated
@scarmuega scarmuega force-pushed the ci/e2e-github-runners branch from 4b32d49 to 5a7f492 Compare June 12, 2026 23:28
@scarmuega scarmuega changed the title ci: migrate e2e tests to GitHub runners + add work_stats finalization filter ci: migrate e2e tests from EKS/Kubernetes to GitHub runners Jun 12, 2026
@scarmuega scarmuega changed the base branch from main to fix/pipeline-finalize-exit June 12, 2026 23:28
@scarmuega scarmuega force-pushed the ci/e2e-github-runners branch from 5a7f492 to 5aab106 Compare June 12, 2026 23:39
@scarmuega scarmuega force-pushed the fix/pipeline-finalize-exit branch from 7073f41 to f540063 Compare June 12, 2026 23:39
@scarmuega scarmuega force-pushed the ci/e2e-github-runners branch from 5aab106 to 2401151 Compare June 13, 2026 14:10
@scarmuega scarmuega changed the base branch from fix/pipeline-finalize-exit to refactor/run-daemon-stop-reason June 13, 2026 14:10
Base automatically changed from refactor/run-daemon-stop-reason to main June 13, 2026 14:22
scarmuega and others added 5 commits June 13, 2026 11:23
Replaces the EKS-backed e2e workflow with one that runs entirely on
github-hosted runners. Each leg runs the release image via `docker run` +
`timeout` and gates on the process exit code; the new WorkStats filter gives
each test a finalization policy so oura self-terminates after N blocks
(exit 0), the Assert sink panics on a bad block (non-zero), and `timeout`
guards a hang (124).

- delete the `prepare` job (EKS kubeconfig / namespace / IRSA service account)
- extract each config from its k8s ConfigMap into .github/e2e/configs/*.toml,
  rewritten for the oura v2 schema (peers/socket_path, top-level
  chain/intersect, LegacyV1 filter for the Assert sink, SplitBlock+ParseCbor
  for cloud sinks, RollbackBuffer for min_depth, WorkStats for finalization)
- AWS creds via aws-actions/configure-aws-credentials (assuming the
  OuraE2ETest role) injected into the container instead of EKS IRSA
- n2c uses a Demeter dmtrcli socket port-forward (placeholder; DMTR_API_KEY
  secret) and is continue-on-error until that path is finalized

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The three relay.cnode-m1.demeter.run endpoints map to different networks:
:3000 = Mainnet, :3001 = PreProd, :3002 = Preview. Mainnet legs use :3000,
preview n2n legs use :3002 (replacing the public IOG/world relays).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the run/dmtrcli logic out of e2e.yaml into .github/e2e/scripts/
(run-test.sh, setup-dmtr-socket.sh, stop-dmtr-tunnel.sh), invoked from the
workflow steps. Scripts read the same env vars the steps already set; committed
with the executable bit so they run after checkout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The U5C source connects over TLS via tonic/rustls. In builds that pull more
than one rustls crypto provider (e.g. the `aws` feature brings in aws-lc-rs
alongside ring), rustls has no process-default provider and panics on the
first TLS handshake (`no process-level CryptoProvider available`). Install the
ring provider once at startup, gated on the `u5c` feature.

This only surfaced now because nothing exercised U5C in a multi-provider build;
the manual u5c tests built `--features u5c` alone (single provider).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the manual u5c checks into the e2e suite as three `kind: u5c` legs
against the Demeter utxorpc endpoints, using the standard exit-code gate via
a WorkStats finalization policy (3 blocks -> exit 0); a #921-style regression
(reset loop, no apply events) never finalizes -> timeout -> fail.

API keys are parameterized as ${DMTR_UTXORPC_KEY_*} and resolved by envsubst
from GitHub secrets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scarmuega scarmuega force-pushed the ci/e2e-github-runners branch from 2401151 to 7998fa5 Compare June 13, 2026 14:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/e2e/scripts/run-test.sh:
- Around line 17-19: The script currently prints the fully resolved daemon.toml
(the echo/cat block that outputs "${RUNNER_TEMP}/daemon.toml"), which can leak
secrets; either remove that debug output entirely or replace it with a redaction
step that reads the resolved file, strips or masks known sensitive keys (e.g.,
dmtr-api-key and other credential fields) and then prints only the redacted
result or non-sensitive metadata (config path, test name, kind); update the
echo/cat block to call the redaction logic (or to be deleted) so CI logs never
contain raw secret values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbba5fd0-0d65-48cf-8fdf-8eb87636aaaa

📥 Commits

Reviewing files that changed from the base of the PR and between 4b32d49 and 7998fa5.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (29)
  • .github/e2e/assert-n2c-preview-origin-blocks.yaml
  • .github/e2e/assert-n2c-preview-tip-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-origin-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-tip-blocks.yaml
  • .github/e2e/assert-n2n-preview-origin-blocks.yaml
  • .github/e2e/assert-n2n-preview-tip-blocks.yaml
  • .github/e2e/aws-lambda-10-blocks.yaml
  • .github/e2e/aws-s3-500-blocks.yaml
  • .github/e2e/aws-sqs-10-blocks.yaml
  • .github/e2e/configs/assert-n2c-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2c-preview-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-tip-blocks.toml
  • .github/e2e/configs/aws-lambda-10-blocks.toml
  • .github/e2e/configs/aws-s3-500-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
  • .github/e2e/configs/u5c-mainnet-tip-blocks.toml
  • .github/e2e/configs/u5c-preprod-tip-blocks.toml
  • .github/e2e/configs/u5c-preview-tip-blocks.toml
  • .github/e2e/gcp-pubsub-10-blocks.yaml
  • .github/e2e/scripts/run-test.sh
  • .github/e2e/scripts/setup-dmtr-socket.sh
  • .github/e2e/scripts/stop-dmtr-tunnel.sh
  • .github/e2e/serviceaccount.yaml
  • .github/workflows/e2e.yaml
  • Cargo.toml
  • src/bin/oura/main.rs
💤 Files with no reviewable changes (11)
  • .github/e2e/aws-s3-500-blocks.yaml
  • .github/e2e/gcp-pubsub-10-blocks.yaml
  • .github/e2e/assert-n2n-preview-origin-blocks.yaml
  • .github/e2e/aws-sqs-10-blocks.yaml
  • .github/e2e/assert-n2n-preview-tip-blocks.yaml
  • .github/e2e/aws-lambda-10-blocks.yaml
  • .github/e2e/assert-n2c-preview-tip-blocks.yaml
  • .github/e2e/assert-n2c-preview-origin-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-origin-blocks.yaml
  • .github/e2e/assert-n2n-mainnet-tip-blocks.yaml
  • .github/e2e/serviceaccount.yaml
✅ Files skipped from review due to trivial changes (5)
  • .github/e2e/configs/u5c-preview-tip-blocks.toml
  • .github/e2e/configs/assert-n2c-preview-origin-blocks.toml
  • .github/e2e/configs/aws-s3-500-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-origin-blocks.toml
  • .github/e2e/configs/assert-n2n-preview-tip-blocks.toml
🚧 Files skipped from review as they are similar to previous changes (10)
  • .github/e2e/configs/assert-n2c-preview-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-origin-blocks.toml
  • .github/e2e/configs/u5c-preprod-tip-blocks.toml
  • .github/e2e/scripts/stop-dmtr-tunnel.sh
  • .github/e2e/configs/u5c-mainnet-tip-blocks.toml
  • .github/e2e/configs/assert-n2n-mainnet-tip-blocks.toml
  • src/bin/oura/main.rs
  • .github/e2e/configs/aws-lambda-10-blocks.toml
  • .github/e2e/configs/aws-sqs-10-blocks.toml
  • .github/e2e/scripts/setup-dmtr-socket.sh

Comment on lines +17 to +19
echo "----- resolved daemon.toml -----"
cat "${RUNNER_TEMP}/daemon.toml"
echo "--------------------------------"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid printing resolved config that may contain embedded secrets.

After envsubst substitution, the daemon.toml may contain literal secret values (e.g., dmtr-api-key for u5c legs). Printing the full config to CI logs risks leaking credentials if GitHub's masking fails or if secrets appear in an unexpected format.

Consider redacting known sensitive keys before printing, or removing the debug output entirely in favor of logging only non-sensitive metadata (config path, test name, kind).

🔒 Suggested fix: redact sensitive fields or remove debug output
 envsubst < ".github/e2e/configs/${TEST_NAME}.toml" > "${RUNNER_TEMP}/daemon.toml"
-echo "----- resolved daemon.toml -----"
-cat "${RUNNER_TEMP}/daemon.toml"
-echo "--------------------------------"
+echo "----- resolved daemon.toml (${TEST_NAME}) -----"
+# Redact sensitive keys before printing to avoid leaking secrets
+sed -E 's/(dmtr-api-key\s*=\s*)"[^"]*"/\1"***REDACTED***"/g' "${RUNNER_TEMP}/daemon.toml"
+echo "------------------------------------------------"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/e2e/scripts/run-test.sh around lines 17 - 19, The script currently
prints the fully resolved daemon.toml (the echo/cat block that outputs
"${RUNNER_TEMP}/daemon.toml"), which can leak secrets; either remove that debug
output entirely or replace it with a redaction step that reads the resolved
file, strips or masks known sensitive keys (e.g., dmtr-api-key and other
credential fields) and then prints only the redacted result or non-sensitive
metadata (config path, test name, kind); update the echo/cat block to call the
redaction logic (or to be deleted) so CI logs never contain raw secret values.

scarmuega and others added 6 commits June 13, 2026 18:15
The n2c legs depended on a placeholder Demeter dmtrcli socket port-forward
that isn't wired up yet. Remove them and their artifacts (the two configs, the
setup/stop dmtrcli scripts, the socket mount and `continue-on-error` guard) so
the suite is all-green and fails honestly on the remaining n2n/aws/u5c legs.
Will reintroduce once the dmtrcli infra is in place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The OuraE2ETest role's trust path no longer matches static IAM user keys (the
`security token invalid` failures). Switch the aws legs to keyless OIDC:
add `id-token: write` and drop `aws-access-key-id`/`aws-secret-access-key` so
configure-aws-credentials uses AssumeRoleWithWebIdentity.

Requires (AWS side): an IAM OIDC provider for token.actions.githubusercontent.com
and a trust policy on OuraE2ETest allowing this repo's workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The AwsS3 sink stores raw block CBOR and only accepts Record::CborBlock;
the ParseCbor filter (copied from a stale example) turned it into a
ParsedBlock, so the sink failed with 'config error'. S3 takes the CborBlock
straight from the source — no parse filter. (SQS/Lambda keep SplitBlock +
ParseCbor since those sinks consume per-tx ParsedTx records.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With OIDC the credential env is set by configure-aws-credentials; run-test.sh
now forwards any AWS_* vars present rather than hardcoding
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/etc. Drops the now-unused KIND env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The default-provider install was gated behind the u5c feature, but the
multi-provider panic affects any TLS path that relies on rustls' process
default (gcp/elasticsearch/hydra/mithril via reqwest/tungstenite), not just
u5c. Make rustls a non-optional dep and run the install for every build so no
feature combination can hard-crash on the first TLS handshake. The install is
idempotent (the Result is ignored), so it's a no-op when a provider is already
set, and the AWS SDK still uses its own provider.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These macOS junk files were swept in by an earlier `git add -A`. Untrack all
five and add a .gitignore rule so they don't return.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scarmuega scarmuega merged commit f8d19a2 into main Jun 13, 2026
11 checks passed
@scarmuega scarmuega deleted the ci/e2e-github-runners branch June 13, 2026 22:19
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