Skip to content

[MATTER-4641] Phase 2: Build and publish renode simulation - #1094

Open
Michael Duggan (miduggan24) wants to merge 19 commits into
matter-4641-inputsfrom
matter-4641-pipeline
Open

Michael Duggan (miduggan24) wants to merge 19 commits into
matter-4641-inputsfrom
matter-4641-pipeline

Conversation

@miduggan24

@miduggan24 Michael Duggan (miduggan24) commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Issue Link:
MATTER-4641

Description of Problem/Feature:
Phase 2 of Matter Renode CI artifact work. Phase 1 checks in the guest and simulation inputs.

This PR builds inputs and publishes bundles that CI and local development workflows fetch. Matter app binaries are left out and will come from CI or a local build.

Description of Fix/Solution:
Introduce manual workflow renode-sim-artifacts (along with accompanying python scripts):

  • Builds Thread & BLE RCP binaries from sisdk with generation overrides in sim-manifest.json to disable flow control (since we don't emulate WPK in renode)
  • Builds matter-rootfs.ext2 from pinned antmicro rootfs plus overlay files from phase 1 implementation
  • Compiles zynqmp-matter-linux.dtb from device tree in phase 1
  • Builds matter-tools.ext2 on arm linux runner (simulated Matter Hub runs on Linux Arm platform)
  • Assembles common bundle (rootfs, tools image, DTB, RCP binaries, renode test_lib, and resc files)
  • Builds host runtime for linux (CI) and mac (local development)
    • portable renode executable plus checkpoint from linux boot and thread network initialization
  • Optionally publishes artifacts to GHCR

Also add some documentation to outline implementation and directions on how to use

Testing Done:
Tested the following in fork repo:

  • Creating artifacts: https://github.com/miduggan24/matter_extension/actions/runs/38596748715
  • Pulling artifacts from GHCR per README description (python3 scripts/fetch_bundle.py)
  • Local development flow using GHCR artifacts
    • matter-sim-full.resc (full linux boot process, thread initialization, etc)
    • matter-sim.resc (start from snapshot after boot and thread init)

Linux testing will be done in later PR to introduce commissioning tests to CI

@miduggan24
Michael Duggan (miduggan24) added this pull request to stack #1095 September 25, 2026 15:14
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor

cursor Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Introduces a large multi-runner build/publish pipeline and versioned GHCR artifacts that downstream CI will depend on; failures or bad bundles affect simulation and future commissioning tests, but no production auth or data paths.

Overview
Adds Phase 2 Matter Renode CI: a manual renode-sim-artifacts workflow and Python tooling under renode_integration/ to build, bundle, and optionally publish simulation assets to GHCR via ORAS (Matter app ELFs stay out of the bundle).

The workflow runs parallel jobs for Thread/BLE RCPs (Simplicity SDK), guest matter-rootfs.ext2 + DTB, and matter-tools.ext2 (Ubuntu arm64, ot-br-posix + chip-tool), then assembles a common bundle (rootfs, tools, DTB, RCPs, resc, test_lib). A runtime matrix (linux-x64, osx-arm64) builds portable Renode, uses the pyrenode3 harness to create linux-booted-thread.save, smoke-tests checkpoint load on macOS, and packages per-host runtime tarballs. publish=true pushes vN-common and vN-runtime-* tags.

Local/CI consumers get fetch_bundle.py to pull common + host runtime; README.md documents quickstart, maintainer rebuild, and future commissioning CI steps.

Reviewed by Cursor Bugbot for commit 1e5f31b. Configure here.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for all 3 issues found in the latest run.

  • ✅ Fixed: Login wait ignores prompt text
    • Modified wait_for_line to check buffer content without requiring newline termination, allowing it to detect prompts like 'buildroot login:' and '#'.
  • ✅ Fixed: Smoke test can hang forever
    • Replaced blocking readline() with select() to properly respect the 180s timeout while reading Renode output.
  • ✅ Fixed: Chip-tool job missing build packages
    • Added installation of libgirepository, libglib2.0-dev, and libevent-dev packages before chip-tool build step.

Create PR

Or push these changes by commenting:

@cursor push a37318aa82
Preview (a37318aa82)
diff --git a/.github/workflows/renode-sim-artifacts.yaml b/.github/workflows/renode-sim-artifacts.yaml
--- a/.github/workflows/renode-sim-artifacts.yaml
+++ b/.github/workflows/renode-sim-artifacts.yaml
@@ -104,6 +104,14 @@
           cd third_party/matter_sdk
           ./scripts/checkout_submodules.py --platform linux
 
+      - name: Install build dependencies
+        run: |
+          sudo apt-get update -qq
+          sudo apt-get install -y -qq --no-install-recommends \
+            libgirepository-1.0-1 libgirepository1.0-dev \
+            libglib2.0-dev libglib2.0-dev-bin \
+            libevent-dev
+
       - name: Bootstrap Matter build env
         uses: SiliconLabsSoftware/matter_build_action/bootstrap@v2
 

diff --git a/renode_integration/harness/renode_harness.py b/renode_integration/harness/renode_harness.py
--- a/renode_integration/harness/renode_harness.py
+++ b/renode_integration/harness/renode_harness.py
@@ -128,6 +128,10 @@
                 line, self.buffer = self.buffer.split("\n", 1)
                 if regex.search(line):
                     return line
+            if regex.search(self.buffer):
+                match = self.buffer
+                self.buffer = ""
+                return match
             self._read_more()
             time.sleep(0.1)
         raise TimeoutError(f"timed out waiting for /{pattern}/ in console output")

diff --git a/renode_integration/harness/smoke_test_checkpoint.py b/renode_integration/harness/smoke_test_checkpoint.py
--- a/renode_integration/harness/smoke_test_checkpoint.py
+++ b/renode_integration/harness/smoke_test_checkpoint.py
@@ -5,6 +5,7 @@
 
 import argparse
 import re
+import select
 import subprocess
 import sys
 import time
@@ -50,14 +51,15 @@
             if proc.poll() is not None:
                 output = "".join(output_lines)
                 raise RuntimeError(f"Renode exited with code {proc.returncode}\n{output}")
-            line = proc.stdout.readline()
-            if line:
-                output_lines.append(line)
-                if re.search(r"Starting emulation", line):
-                    print(f"Checkpoint loaded: {checkpoint}")
-                    return 0
-            else:
-                time.sleep(0.1)
+            timeout = max(0, deadline - time.time())
+            ready, _, _ = select.select([proc.stdout], [], [], min(timeout, 0.1))
+            if ready:
+                line = proc.stdout.readline()
+                if line:
+                    output_lines.append(line)
+                    if re.search(r"Starting emulation", line):
+                        print(f"Checkpoint loaded: {checkpoint}")
+                        return 0
         raise TimeoutError("checkpoint load did not complete within 180s")
     finally:
         proc.terminate()

You can send follow-ups to the cloud agent here.

Comment thread renode_integration/harness/renode_harness.py Outdated
Comment thread renode_integration/harness/smoke_test_checkpoint.py Outdated
Comment thread .github/workflows/renode-sim-artifacts.yaml
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Monitor reads swallow command timeouts
    • Modified _read_until_prompt to raise TimeoutError when socket timeout occurs without receiving a monitor prompt, preventing incomplete checkpoint saves from being treated as successful.
  • ✅ Fixed: Runtime publish allows missing checkpoint
    • Modified stage function to require linux-booted-thread.save file existence before allowing runtime bundle publication, preventing incomplete bundles from reaching GHCR.

Create PR

Or push these changes by commenting:

@cursor push f680f71e38
Preview (f680f71e38)
diff --git a/renode_integration/harness/renode_harness.py b/renode_integration/harness/renode_harness.py
--- a/renode_integration/harness/renode_harness.py
+++ b/renode_integration/harness/renode_harness.py
@@ -84,6 +84,9 @@
             try:
                 data = sock.recv(4096)
             except socket.timeout:
+                combined = "".join(chunks)
+                if not _MONITOR_PROMPT.search(combined):
+                    raise TimeoutError("monitor prompt not received before timeout")
                 break
             if not data:
                 break

diff --git a/renode_integration/scripts/publish_bundle.py b/renode_integration/scripts/publish_bundle.py
--- a/renode_integration/scripts/publish_bundle.py
+++ b/renode_integration/scripts/publish_bundle.py
@@ -46,10 +46,13 @@
         return
     if kind == "runtime":
         copy_tree(os.path.join(bundle, "renode"), os.path.join(staging, "renode"))
-        for name in ("linux-booted-thread.save", "runtime-manifest.json"):
-            src = os.path.join(bundle, name)
-            if os.path.isfile(src):
-                shutil.copy2(src, os.path.join(staging, name))
+        checkpoint_src = os.path.join(bundle, "linux-booted-thread.save")
+        if not os.path.isfile(checkpoint_src):
+            common.die("linux-booted-thread.save is required for runtime bundle")
+        shutil.copy2(checkpoint_src, os.path.join(staging, "linux-booted-thread.save"))
+        manifest_src = os.path.join(bundle, "runtime-manifest.json")
+        if os.path.isfile(manifest_src):
+            shutil.copy2(manifest_src, os.path.join(staging, "runtime-manifest.json"))
         return
     common.die(f"unknown kind: {kind}")

You can send follow-ups to the cloud agent here.

Comment thread renode_integration/harness/renode_harness.py Outdated
Comment thread renode_integration/scripts/publish_bundle.py Outdated
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

Stale Bugbot comment from a previous run.

@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Portable Renode missing CoreCLR runtime
    • Added PYRENODE_RUNTIME=coreclr environment variable in MatterSim.init to ensure pyrenode3 uses the correct runtime for portable Renode builds.

Create PR

Or push these changes by commenting:

@cursor push 816251dfe4
Preview (816251dfe4)
diff --git a/renode_integration/harness/matter_sim.py b/renode_integration/harness/matter_sim.py
--- a/renode_integration/harness/matter_sim.py
+++ b/renode_integration/harness/matter_sim.py
@@ -41,8 +41,9 @@
 
     def __init__(self, bundle_dir: Path) -> None:
         self.bundle_dir = bundle_dir.resolve()
-        # pyrenode3 reads PYRENODE_PATH at import time.
+        # pyrenode3 reads PYRENODE_PATH and PYRENODE_RUNTIME at import time.
         os.environ["PYRENODE_PATH"] = str(resolve_renode(self.bundle_dir))
+        os.environ["PYRENODE_RUNTIME"] = "coreclr"
         from pyrenode3.wrappers import Emulation, Monitor, TerminalTester
 
         self._terminal_tester = TerminalTester

You can send follow-ups to the cloud agent here.

Comment thread renode_integration/harness/matter_sim.py Outdated
@miduggan24
Michael Duggan (miduggan24) force-pushed the matter-4641-pipeline branch 8 times, most recently from d1864c8 to a05b3e5 Compare October 2, 2026 17:33
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Publish runtime ignores needed results
    • Added dependency result checks to publish-runtime job to ensure build-runtime succeeded and publish-common succeeded before running, preventing execution when dependencies fail or are skipped.

Create PR

Or push these changes by commenting:

@cursor push 2ddc95c60e
Preview (2ddc95c60e)
diff --git a/.github/workflows/renode-sim-artifacts.yaml b/.github/workflows/renode-sim-artifacts.yaml
--- a/.github/workflows/renode-sim-artifacts.yaml
+++ b/.github/workflows/renode-sim-artifacts.yaml
@@ -297,7 +297,13 @@
     needs:
       - build-runtime
       - publish-common
-    if: inputs.publish
+    if: >-
+      ${{
+        inputs.publish &&
+        !cancelled() &&
+        needs.build-runtime.result == 'success' &&
+        needs.publish-common.result == 'success'
+      }}
     strategy:
       fail-fast: false
       matrix:

You can send follow-ups to the cloud agent here.

Comment thread .github/workflows/renode-sim-artifacts.yaml
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

Stale Bugbot comment from a previous run.

@miduggan24
Michael Duggan (miduggan24) marked this pull request as draft October 14, 2026 15:49
@miduggan24

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1e5f31b. Configure here.

@miduggan24
Michael Duggan (miduggan24) marked this pull request as ready for review October 14, 2026 17:36
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