From 44b8aa6205d486cb65bda6da5091296bfc0ee6ba Mon Sep 17 00:00:00 2001 From: aimendj Date: Fri, 22 May 2026 01:42:56 +0100 Subject: [PATCH 1/3] feat: bootstrap peers from user-config initial_peers only --- config/user_config.yaml | 197 +++++++++++++++++++++++++ logos_chain/conf.nim | 15 +- logos_chain/deployment/user_config.nim | 50 +++++++ logos_chain/networking/discovery.nim | 48 ++---- logos_chain/networking/network.nim | 10 +- 5 files changed, 272 insertions(+), 48 deletions(-) create mode 100644 config/user_config.yaml create mode 100644 logos_chain/deployment/user_config.nim diff --git a/config/user_config.yaml b/config/user_config.yaml new file mode 100644 index 0000000..596206c --- /dev/null +++ b/config/user_config.yaml @@ -0,0 +1,197 @@ +network: + backend: + swarm: + host: 0.0.0.0 + port: 3000 + node_key: e23ddddb2e2e0ff2cf27517cc2241f6bd8a7bb03c4083ab5271ffe400ceba51e + gossipsub: + history_length: 5 + history_gossip: 3 + mesh_n: 6 + mesh_n_low: 5 + mesh_n_high: 12 + retain_scores: 4 + gossip_lazy: 6 + gossip_factor: 0.25 + heartbeat_initial_delay: + secs: 5 + nanos: 0 + heartbeat_interval: + secs: 1 + nanos: 0 + fanout_ttl: + secs: 60 + nanos: 0 + check_explicit_peers_ticks: 300 + duplicate_cache_time: + secs: 60 + nanos: 0 + validate_messages: false + allow_self_origin: false + do_px: false + prune_peers: 0 + prune_backoff: + secs: 60 + nanos: 0 + unsubscribe_backoff: + secs: 10 + nanos: 0 + backoff_slack: 1 + flood_publish: true + graft_flood_threshold: + secs: 10 + nanos: 0 + mesh_outbound_min: 2 + opportunistic_graft_ticks: 60 + opportunistic_graft_peers: 2 + gossip_retransimission: 3 + max_messages_per_rpc: null + max_ihave_length: 5000 + max_ihave_messages: 10 + iwant_followup_time: + secs: 3 + nanos: 0 + published_message_ids_cache_time: + secs: 10 + nanos: 0 + kademlia: + query_timeout_secs: null + replication_factor: null + parallelism: null + disjoint_query_paths: null + max_packet_size: null + kbucket_inserts: null + caching: null + periodic_bootstrap_interval_secs: null + identify: + agent_version: null + interval_secs: null + push_listen_addr_updates: null + cache_size: null + hide_listen_addrs: true + chain_sync: + peer_response_timeout: 5000 + nat: + type: traversal + autonat: + max_candidates: null + probe_interval_millisecs: null + retest_successful_external_addresses_interval: + secs: 60 + nanos: 0 + mapping: + timeout: '1.000000000' + lease_duration: + secs: 7200 + nanos: 0 + max_retries: 3 + renewal_delay_fraction: 0.8 + retry_interval: + secs: 30 + nanos: 0 + gateway_monitor: + check_interval: + secs: 300 + nanos: 0 + initial_peers: + - /ip4/209.38.241.182/udp/3000/quic-v1/p2p/12D3KooW9wycYQTk8HPKHHyVzF2tUEpVSu4WHu8ySAbTmXGreuV5 + - /ip4/65.109.51.37/udp/3000/quic-v1/p2p/12D3KooWFrouXfmrR4nsLMtE7wu15DoMJ6VtoUtHinREZCvbWHar + - /ip4/65.109.51.37/udp/3001/quic-v1/p2p/12D3KooWJRGau8M1rjT7R5e4YYsgdFhsMX35nRDtMwCDjxQkXAHz + - /ip4/65.109.51.37/udp/3002/quic-v1/p2p/12D3KooWQXJavMDTRscjauFSgVAB1VLB6Rzpy2uY5SU9Tk7927tb + - /ip4/65.109.51.37/udp/3003/quic-v1/p2p/12D3KooWSQc7CcGtvWDPF1yCbBthFnQjprfCVHmfmNDUrSmqQsU1 +blend: + non_ephemeral_signing_key_id: 741d3c4be7d2c0d4f87ce582a2da38368739a621987b6cd003a807768b34115d + core: + backend: + listening_address: /ip4/0.0.0.0/udp/3400/quic-v1 + core_peering_degree: + start: 2 + end: 3 + edge_node_connection_timeout: '1.000000000' + max_edge_node_incoming_connections: 300 + max_dial_attempts_per_peer: 3 + zk: + secret_key_kms_id: 8a81da6155a8c2af8d6589f343f309a29b93eec45d2ecbf9236e55eb0a6d7205 + edge: + backend: + max_dial_attempts_per_peer_per_message: 1 + replication_factor: 1 +cryptarchia: + service: + bootstrap: + prolonged_bootstrap_period: '300.000000000' + force_bootstrap: false + offline_grace_period: + grace_period: '1200.000000000' + state_recording_interval: '60.000000000' + network: + bootstrap: + ibd: + peers: + - 12D3KooW9wycYQTk8HPKHHyVzF2tUEpVSu4WHu8ySAbTmXGreuV5 + delay_before_new_download: + secs: 10 + nanos: 0 + sync: + orphan: + max_orphan_cache_size: 1000 + network: + max_connected_peers_to_try_download: 16 + max_discovered_peers_to_try_download: 16 + leader: + wallet: + max_tx_fee: 18446744073709551615 + funding_pk: 479bc98b3494dade3d50b2110e96ca46ac5d6db32e98371ca8c399d2cbf2d805 +time: + backend: + server: pool.ntp.org:123 + client: + timeout: '5.000000000' + listening_interface: 0.0.0.0 + update_interval: '15.000000000' +sdp: + declaration_id: null + wallet: + max_tx_fee: 18446744073709551615 + funding_pk: 479bc98b3494dade3d50b2110e96ca46ac5d6db32e98371ca8c399d2cbf2d805 +api: + backend: + listen_address: 0.0.0.0:8080 + cors_origins: [] + timeout: 30 + max_body_size: 10485760 + max_concurrent_requests: 500 +storage: + backend: + folder_name: ./db + read_only: false + column_family: blocks +kms: + backend: + keys: + 3c0999d8b5c32c36d2d49918cb09e69429a50de71776ade8ffdeeebcf9c4312a: !Zk f84adcef2416d7f414af14163f81ebe9290d146a7a0afbe7214a67220e399c09 + 479bc98b3494dade3d50b2110e96ca46ac5d6db32e98371ca8c399d2cbf2d805: !Zk bd6b46f655db596f7c5aa52a5c8129bf03c8f9b9d498a222f544ecd1aae01b1c + 8a81da6155a8c2af8d6589f343f309a29b93eec45d2ecbf9236e55eb0a6d7205: !Zk 731d3c5b53ddde90670c2c095af2040e2ae124a0e1351c18da07d69418e6ac2c + 741d3c4be7d2c0d4f87ce582a2da38368739a621987b6cd003a807768b34115d: !Ed25519 611760acd0ddc6cbe68f7759132699c8dc478faec43e167e281cc5a1b2a7dd50 +wallet: + known_keys: + 479bc98b3494dade3d50b2110e96ca46ac5d6db32e98371ca8c399d2cbf2d805: 479bc98b3494dade3d50b2110e96ca46ac5d6db32e98371ca8c399d2cbf2d805 + 3c0999d8b5c32c36d2d49918cb09e69429a50de71776ade8ffdeeebcf9c4312a: 3c0999d8b5c32c36d2d49918cb09e69429a50de71776ade8ffdeeebcf9c4312a + voucher_master_key_id: 3c0999d8b5c32c36d2d49918cb09e69429a50de71776ade8ffdeeebcf9c4312a +tracing: + logger: + file: + directory: . + prefix: '1776126665' + loki: null + gelf: null + otlp: null + stdout: true + stderr: false + tracing: None + filter: None + metrics: None + console: None + level: DEBUG +state: + base_folder: ./state diff --git a/logos_chain/conf.nim b/logos_chain/conf.nim index d4d2c7d..cb3ebc5 100644 --- a/logos_chain/conf.nim +++ b/logos_chain/conf.nim @@ -45,6 +45,8 @@ const defaultAdminListenAddressDesc* = $defaultAdminListenAddress ## Default ``--deployment-settings`` path (canonical cfgsync layout; run from repo root or override). defaultDeploymentSettingsPath* = "config/deployment-settings.yaml" + ## Default ``--user-config`` path (cfgsync user config; bootstrap peers from ``initial_peers``). + defaultUserConfigPath* = "config/user_config.yaml" when defined(windows): {.pragma: windowsOnly.} @@ -194,15 +196,10 @@ type desc: "Run as a Windows service" name: "run-as-service" .}: bool - bootstrapNodes* {. - desc: "Specifies one or more bootstrap nodes to use when connecting to the network" - abbr: "b" - name: "bootstrap-node" .}: seq[string] - - bootstrapNodesFile* {. - desc: "Specifies a line-delimited file of bootstrap Ethereum network addresses" - defaultValue: "" - name: "bootstrap-file" .}: InputFile + userConfigFile* {. + desc: "cfgsync user-config YAML (bootstrap peers from network.backend.initial_peers)" + defaultValue: InputFile(defaultUserConfigPath) + name: "user-config" .}: InputFile listenAddress* {. desc: "Listening address for Logos Chain libp2p and Discovery v5 traffic" diff --git a/logos_chain/deployment/user_config.nim b/logos_chain/deployment/user_config.nim new file mode 100644 index 0000000..d3df401 --- /dev/null +++ b/logos_chain/deployment/user_config.nim @@ -0,0 +1,50 @@ +# nimbos +# Copyright (c) 2026 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + std/[options, strutils], + results, + stew/io2, + yaml/dom, + ./helpers + +export dom + +const initialPeersPath* = ["network", "backend", "initial_peers"] + +proc parseUserConfigYaml*(text: string): Result[YamlNode, string] = + let root = ? parseDeploymentSettingsYaml(text) + if root.kind != yMapping: + return err("user-config: expected top-level mapping") + ok(root) + +proc initialPeersFromYaml*(root: YamlNode): Result[seq[string], string] = + let node = yamlGetPathNode(root, initialPeersPath) + if node.isNone: + return ok(newSeq[string]()) + let peersNode = node.get + if peersNode.kind != ySequence: + return err("user-config: network.backend.initial_peers must be a sequence") + var peers: seq[string] + for i in 0 ..< peersNode.len: + let item = peersNode[i] + if item.kind != yScalar: + return err("user-config: network.backend.initial_peers[" & $i & "] must be a string") + let peerAddr = item.content.strip() + if peerAddr.len > 0: + peers.add(peerAddr) + ok(peers) + +proc loadUserConfigInitialPeers*(path: string): Result[seq[string], string] = + let text = readAllChars(path).valueOr: + return err("user-config: cannot read " & path & ": " & ioErrorMsg(error)) + let root = ? parseUserConfigYaml(text) + initialPeersFromYaml(root) + +{.pop.} diff --git a/logos_chain/networking/discovery.nim b/logos_chain/networking/discovery.nim index 3201a98..5f9cacc 100644 --- a/logos_chain/networking/discovery.nim +++ b/logos_chain/networking/discovery.nim @@ -13,11 +13,12 @@ import libp2p/[peerinfo, multiaddress, multicodec], eth/common/keys, eth/p2p/discoveryv5/[protocol, node, random2], + results, ssz_serialization, - ../conf + ../conf, + ../deployment/user_config -from std/os import splitFile -from std/strutils import cmpIgnoreCase, split, startsWith, strip +from std/strutils import split, startsWith, strip export protocol, node @@ -53,19 +54,8 @@ func parseBootstrapAddress*(address: string): ok((peerId, baseAddr)) -iterator strippedLines(filename: string): string {.raises: [ref IOError].} = - ## Yields non-empty, trimmed, non-comment lines from ``filename``. - for line in lines(filename): - let stripped = strip(line) - if stripped.startsWith('#'): - continue - - if stripped.len > 0: - yield stripped - -proc addBootstrapNode*(bootstrapAddr: string, +proc addBootstrapPeer*(bootstrapAddr: string, bootstrapPeers: var seq[(PeerId, MultiAddress)]) = - # Ignore empty lines or lines starting with # if bootstrapAddr.len == 0 or bootstrapAddr[0] == '#': return @@ -76,27 +66,15 @@ proc addBootstrapNode*(bootstrapAddr: string, warn "Ignoring invalid bootstrap address", bootstrapAddr, reason = addrRes.error -proc loadBootstrapFile*(bootstrapFile: string, - bootstrapPeers: var seq[(PeerId, MultiAddress)]) = - if bootstrapFile.len == 0: return - let ext = splitFile(bootstrapFile).ext - if cmpIgnoreCase(ext, ".txt") == 0: - try: - for ln in strippedLines(bootstrapFile): - addBootstrapNode(ln, bootstrapPeers) - except IOError as e: - error "Could not read bootstrap file", msg = e.msg - quit 1 - else: - error "Unknown bootstrap file format", ext - quit 1 - -proc loadBootstrapNodes*(config: LBNodeConf): seq[(PeerId, MultiAddress)] = +proc loadBootstrapNodes*(config: LBNodeConf): Result[seq[(PeerId, MultiAddress)], string] = + ## YAML load is not statically GC-safe; safe here (sync init, no shared refs). + var initialPeers: seq[string] + {.cast(gcsafe).}: + initialPeers = ? loadUserConfigInitialPeers(string config.userConfigFile) var bootstrapPeers: seq[(PeerId, MultiAddress)] - for node in config.bootstrapNodes: - addBootstrapNode(node, bootstrapPeers) - loadBootstrapFile(string config.bootstrapNodesFile, bootstrapPeers) - bootstrapPeers + for peerAddr in initialPeers: + addBootstrapPeer(peerAddr, bootstrapPeers) + ok(bootstrapPeers) proc new*(T: type Eth2DiscoveryProtocol, config: LBNodeConf, diff --git a/logos_chain/networking/network.nim b/logos_chain/networking/network.nim index 57360b5..908d24b 100644 --- a/logos_chain/networking/network.nim +++ b/logos_chain/networking/network.nim @@ -2030,9 +2030,11 @@ func quicEndPoint(address: IpAddress, port: Port): Result[MultiAddress, string] except MaError as exc: err(exc.msg) -proc loadBootstrapPeers(config: LBNodeConf): seq[PeerAddr] = - for (peerId, maddr) in loadBootstrapNodes(config): - result.add(PeerAddr(peerId: peerId, addrs: @[maddr])) +proc loadBootstrapPeers(config: LBNodeConf): Result[seq[PeerAddr], string] = + var peers: seq[PeerAddr] + for (peerId, maddr) in ? loadBootstrapNodes(config): + peers.add(PeerAddr(peerId: peerId, addrs: @[maddr])) + ok(peers) func initNetKeys(privKey: PrivateKey): NetKeyPair = let pubKey = privKey.getPublicKey().expect("working public key from random") @@ -2128,7 +2130,7 @@ proc createLBNode*( err(ValidationResult.Reject) let - bootstrapPeers = loadBootstrapPeers(config) + bootstrapPeers = ? loadBootstrapPeers(config) params = GossipSubParams.init( pruneBackoff = chronos.minutes(1), unsubscribeBackoff = chronos.seconds(10), From 61182bab66506a2be7fa88c4ffc55f582a808143 Mon Sep 17 00:00:00 2001 From: aimendj Date: Fri, 22 May 2026 01:43:49 +0100 Subject: [PATCH 2/3] test: add user-config initial_peers parsing and update P2P bootstrap tests --- tests/all_tests.nim | 1 + tests/fixtures/user_config-empty-peers.yaml | 3 + tests/fixtures/user_config-initial-peers.yaml | 5 ++ tests/test_logos_p2p.nim | 9 ++- tests/test_user_config.nim | 61 +++++++++++++++++++ tests/testutil.nim | 22 ++++++- 6 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/user_config-empty-peers.yaml create mode 100644 tests/fixtures/user_config-initial-peers.yaml create mode 100644 tests/test_user_config.nim diff --git a/tests/all_tests.nim b/tests/all_tests.nim index a38ca4a..5755648 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -16,6 +16,7 @@ import # Unit test ./test_logos_p2p, ./test_api_handlers, ./test_deployment_settings, + ./test_user_config, ./test_poseidon_hasher summarizeLongTests("AllTests") diff --git a/tests/fixtures/user_config-empty-peers.yaml b/tests/fixtures/user_config-empty-peers.yaml new file mode 100644 index 0000000..23b9edd --- /dev/null +++ b/tests/fixtures/user_config-empty-peers.yaml @@ -0,0 +1,3 @@ +network: + backend: + initial_peers: [] diff --git a/tests/fixtures/user_config-initial-peers.yaml b/tests/fixtures/user_config-initial-peers.yaml new file mode 100644 index 0000000..38fcc5d --- /dev/null +++ b/tests/fixtures/user_config-initial-peers.yaml @@ -0,0 +1,5 @@ +network: + backend: + initial_peers: + - /ip4/209.38.241.182/udp/3000/quic-v1/p2p/12D3KooW9wycYQTk8HPKHHyVzF2tUEpVSu4WHu8ySAbTmXGreuV5 + - /ip4/65.109.51.37/udp/3000/quic-v1/p2p/12D3KooWFrouXfmrR4nsLMtE7wu15DoMJ6VtoUtHinREZCvbWHar diff --git a/tests/test_logos_p2p.nim b/tests/test_logos_p2p.nim index 458ea50..8e55076 100644 --- a/tests/test_logos_p2p.nim +++ b/tests/test_logos_p2p.nim @@ -12,6 +12,7 @@ import std/[net, strutils], chronos, chronos/unittest2/asynctests, + confutils, ./testutil import @@ -37,6 +38,7 @@ suite "P2P stack — transport and reachability (Logos Chain / libp2p spec)": conf: LBNodeConf conf2: LBNodeConf + conf.userConfigFile = InputFile(emptyUserConfigFixture) conf.listenAddress = some(listenIp) conf.nat = natCfg conf.quicPort = 5001.Port @@ -45,6 +47,7 @@ suite "P2P stack — transport and reachability (Logos Chain / libp2p spec)": conf.hardMaxPeers = some(4) conf.agentString = "p2p-test-node1" + conf2.userConfigFile = InputFile(emptyUserConfigFixture) conf2.listenAddress = some(listenIp) conf2.nat = natCfg # `conf2` is only used for non-listen settings (agent/maxPeers) in this test; @@ -120,6 +123,7 @@ suite "P2P stack — transport and reachability (Logos Chain / libp2p spec)": rng = HmacDrbgContext.new() conf: LBNodeConf + conf.userConfigFile = InputFile(emptyUserConfigFixture) conf.listenAddress = some(listenIp) conf.nat = natCfg conf.quicPort = 5001.Port @@ -166,6 +170,7 @@ suite "P2P stack — transport and reachability (Logos Chain / libp2p spec)": rng = HmacDrbgContext.new() conf: LBNodeConf + conf.userConfigFile = InputFile(emptyUserConfigFixture) conf.listenAddress = some(listenIp) conf.nat = natCfg conf.quicPort = 5001.Port @@ -206,7 +211,7 @@ suite "P2P stack — bootstrap and discovery": "/quic-v1/p2p/" & $listenerPeerId var confDial = confD - confDial.bootstrapNodes = @[bootstrapAddr] + confDial.userConfigFile = writeTestUserConfig(@[bootstrapAddr]) let dialerRes = createLBNode(rngD, confDial, rngD[].getRandomNetKeys()) check dialerRes.isOk @@ -261,7 +266,7 @@ suite "P2P stack — bootstrap and discovery": "/quic-v1/p2p/" & $listenerPeerId var confDial = confD - confDial.bootstrapNodes = @[bootstrapAddr] + confDial.userConfigFile = writeTestUserConfig(@[bootstrapAddr]) let dialerRes = createLBNode(rngD, confDial, rngD[].getRandomNetKeys()) check dialerRes.isOk diff --git a/tests/test_user_config.nim b/tests/test_user_config.nim new file mode 100644 index 0000000..0b084cf --- /dev/null +++ b/tests/test_user_config.nim @@ -0,0 +1,61 @@ +# nimbos +# Copyright (c) 2026 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} +{.used.} + +import std/[os, strutils] +import unittest2 +import stew/io2 +import ../logos_chain/deployment/user_config + +const testsDir = currentSourcePath.rsplit({os.DirSep, os.AltSep}, 1)[0] + +const initialPeersFixturePath = + testsDir / "fixtures/user_config-initial-peers.yaml" + +const userConfigPath = testsDir / "../config/user_config.yaml" + +suite "user-config initial_peers": + test "parse initial_peers from fixture": + let peers = loadUserConfigInitialPeers(initialPeersFixturePath).valueOr: + raise newException(CatchableError, error) + check peers.len == 2 + check peers[0].startsWith("/ip4/") + check "/quic-v1/" in peers[0] + check "/p2p/" in peers[0] + + test "missing initial_peers yields empty list": + let peers = initialPeersFromYaml(parseUserConfigYaml(""" +network: + backend: + swarm: + host: 0.0.0.0 +""").get).valueOr: + raise newException(CatchableError, error) + check peers.len == 0 + + test "non-sequence initial_peers is rejected": + let r = initialPeersFromYaml(parseUserConfigYaml(""" +network: + backend: + initial_peers: /ip4/1.2.3.4/udp/3000/quic-v1/p2p/12D3KooW9wycYQTk8HPKHHyVzF2tUEpVSu4WHu8ySAbTmXGreuV5 +""").get) + check r.isErr + check "initial_peers" in r.error + + test "parse canonical config/user_config.yaml when present": + if not fileExists(userConfigPath): + echo "skip: ", userConfigPath, " not found" + return + let peers = loadUserConfigInitialPeers(userConfigPath).valueOr: + raise newException(CatchableError, error) + check peers.len >= 1 + for p in peers: + check p.startsWith("/") + +{.pop.} diff --git a/tests/testutil.nim b/tests/testutil.nim index 805dd77..ccf1ac8 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -9,8 +9,9 @@ import testutils/markdown_reports, unittest2 import - std/[net, times], - chronos + std/[net, os, strutils, times], + chronos, + confutils import ../logos_chain/conf, ../logos_chain/networking/network, @@ -67,8 +68,23 @@ proc summarizeLongTests*(name: string) = except CatchableError as exc: raiseAssert exc.msg +const testsDir = currentSourcePath.rsplit({DirSep, AltSep}, 1)[0] + +const emptyUserConfigFixture* = + testsDir / "fixtures/user_config-empty-peers.yaml" + const TestLoopbackIp* = parseIpAddress("127.0.0.1") +proc writeTestUserConfig*(initialPeers: openArray[string]): InputFile {.raises: [IOError].} = + var yaml = "network:\n backend:\n initial_peers:\n" + for peer in initialPeers: + yaml &= " - " & peer & "\n" + let path = getTempDir() / ("nimbos-user-config-" & $getTime().toUnix() & ".yaml") + writeFile(path, yaml) + InputFile(path) + +export emptyUserConfigFixture, writeTestUserConfig + proc waitLibp2pConnected*(sw: Switch, remote: PeerId): Future[bool] {.async.} = for i in 0 ..< 150: if sw.isConnected(remote): @@ -87,6 +103,7 @@ proc makeBootstrapConfs*(listenerPort, dialerPort: Port): tuple[ ( confL: LBNodeConf( cmd: BNStartUpCmd.lbNode, + userConfigFile: InputFile(emptyUserConfigFixture), listenAddress: some(TestLoopbackIp), nat: natCfg, quicPort: listenerPort, @@ -97,6 +114,7 @@ proc makeBootstrapConfs*(listenerPort, dialerPort: Port): tuple[ ), confD: LBNodeConf( cmd: BNStartUpCmd.lbNode, + userConfigFile: InputFile(emptyUserConfigFixture), listenAddress: some(TestLoopbackIp), nat: natCfg, quicPort: dialerPort, From 6f232298fa34ede068321ef43159cfbf959da34c Mon Sep 17 00:00:00 2001 From: aimendj Date: Fri, 22 May 2026 02:28:59 +0100 Subject: [PATCH 3/3] ci: exclude .yaml files from copyright year check --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50721d2..44f916a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,8 +230,8 @@ jobs: - name: Check copyright year if: ${{ !cancelled() }} && github.event_name == 'pull_request' run: | - excluded_files="config.yaml|config.nims|\\.gitmodules|config/deployment-settings\\.yaml|tests/fixtures/deployment-settings-empty-scalars\\.yaml|tests/fixtures/deployment-settings-incomplete\\.yaml|tests/fixtures/deployment-settings-malformed\\.yaml|tests/fixtures/deployment-settings-no-leading-slash\\.yaml|tests/fixtures/deployment-settings-wrong-types\\.yaml" - excluded_extensions="ans|bin|cfg|yml|json|json\\.template|md|png|service|ssz|tpl|txt|lock|nix|gitignore|envrc|sh" + excluded_files="config.nims|\\.gitmodules" + excluded_extensions="ans|bin|cfg|yml|yaml|json|json\\.template|md|png|service|ssz|tpl|txt|lock|nix|gitignore|envrc|sh" current_year=$(date +"%Y") problematic_files=()