-
Notifications
You must be signed in to change notification settings - Fork 3
feat(deploy): add shared check-published-deploy-constants script #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8eca835
c882a42
8931c98
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,76 @@ | ||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||
| # SPDX-License-Identifier: LicenseRef-DCL-1.0 | ||||||||||||||||||||
| # SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # Checks that every version published to the soldeer registry for a given | ||||||||||||||||||||
| # package has a full suite of pinned deploy constants in the specified Solidity | ||||||||||||||||||||
| # file. For each published version and each constant prefix, asserts that both | ||||||||||||||||||||
| # a DEPLOYED_ADDRESS_<ver> and DEPLOYED_CODEHASH_<ver> constant exist (where | ||||||||||||||||||||
| # <ver> is the version string with dots replaced by underscores). | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # Usage: | ||||||||||||||||||||
| # check-published-deploy-constants <soldeer-package> <deploy-lib-path> <prefix> [<prefix> ...] | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # Arguments: | ||||||||||||||||||||
| # soldeer-package soldeer package name to query (e.g. "raindex") | ||||||||||||||||||||
| # deploy-lib-path path to the Solidity file holding the constants | ||||||||||||||||||||
| # prefix... one or more constant name prefixes | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # Output for a well-formed invocation (always exits 0, so registry state never | ||||||||||||||||||||
| # reds a consumer pipeline): | ||||||||||||||||||||
| # OK every published version has its full constant suite | ||||||||||||||||||||
| # MISSING: <names> one or more expected constants are absent | ||||||||||||||||||||
| # SKIP: <reason> nothing was verified; the reason distinguishes an | ||||||||||||||||||||
| # unreachable registry from a reachable registry whose | ||||||||||||||||||||
| # response yielded no parseable versions | ||||||||||||||||||||
| # | ||||||||||||||||||||
| # A malformed invocation (fewer than 3 arguments) is a caller bug, not a | ||||||||||||||||||||
| # registry state: usage goes to stderr and the exit status is 1, so a miswired | ||||||||||||||||||||
| # CI step fails loud instead of silently skipping forever. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if [ "$#" -lt 3 ]; then | ||||||||||||||||||||
| printf 'Usage: check-published-deploy-constants <soldeer-package> <deploy-lib-path> <prefix> [<prefix>...]\n' >&2 | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
| package="$1" | ||||||||||||||||||||
| lib="$2" | ||||||||||||||||||||
| shift 2 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if ! response=$(curl -fsS "https://api.soldeer.xyz/api/v1/revision?project_name=${package}" 2>/dev/null); then | ||||||||||||||||||||
| printf 'SKIP: could not fetch published soldeer versions' | ||||||||||||||||||||
| exit 0 | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
Comment on lines
+42
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate and inspect the referenced script and nearby content.
if [ -f lib/check-published-deploy-constants.sh ]; then
wc -l lib/check-published-deploy-constants.sh
sed -n '1,90p' lib/check-published-deploy-constants.sh | cat -n
else
echo "Referenced file not found."
fd -i 'check-published-deploy-constants\.sh'
fi
# Check whether other curl invocations in this script use timeout options.
echo
echo "curl timeout option usage in file:"
rg -n 'curl|connect-timeout|max-time|timeout' lib/check-published-deploy-constants.sh || trueRepository: rainlanguage/rainix Length of output: 3609 Bound the registry request.
Suggested fix- if ! response=$(curl -fsS "https://api.soldeer.xyz/api/v1/revision?project_name=${package}" 2>/dev/null); then
+ if ! response=$(curl -fsS --connect-timeout 10 --max-time 30 \
+ "https://api.soldeer.xyz/api/v1/revision?project_name=${package}" 2>/dev/null); then📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| # grep exits non-zero on zero matches; that is the legitimate | ||||||||||||||||||||
| # "registry reachable but no versions parsed" case (e.g. a package with no | ||||||||||||||||||||
| # published releases yet), kept distinct from the connectivity SKIP above so | ||||||||||||||||||||
| # parser/API drift is never masked as an unreachable registry. | ||||||||||||||||||||
| versions=$( | ||||||||||||||||||||
| printf '%s' "$response" \ | ||||||||||||||||||||
| | grep -oE '"version":"[0-9][0-9.]*"' | cut -d'"' -f4 | sort -u | ||||||||||||||||||||
| ) || true | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if [ -z "$versions" ]; then | ||||||||||||||||||||
| printf 'SKIP: no versions parsed from registry response' | ||||||||||||||||||||
| exit 0 | ||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||
| fi | ||||||||||||||||||||
|
Comment on lines
+51
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Files matching check-published-deploy-constants.sh:\n'
fd -a 'check-published-deploy-constants\.sh$' . || true
file="$(fd 'check-published-deploy-constants\.sh$' . | head -n1 || true)"
if [ -n "${file:-}" ]; then
printf '\nLine count:\n'
wc -l "$file"
printf '\nSelected lines:\n'
sed -n '1,140p' "$file" | cat -n
fi
printf '\nSearch references to publish/available versions in repo:\n'
rg -n "check-published-deploy-constants|versions=\(|grep -oE|supported|soldeer|registry" -S . --glob '!target/**' --glob '!node_modules/**' | head -n 200Repository: rainlanguage/rainix Length of output: 10785 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Current test file summary:\n'
wc -l test/bats/task/check-published-deploy-constants.test.bats
sed -n '1,180p' test/bats/task/check-published-deploy-constants.test.bats | cat -n
printf '\nProbe regex behavior for representative registry-format cases:\n'
python3 - <<'PY'
import re, subprocess, textwrap
script = r'''#!/usr/bin/env bash
set -euo pipefail
versions=$(
printf '%s' "$1" \
| grep -oE '"version":"[0-9][0-9.]*"' | cut -d'"' -f4 | sort -u
) || true
: "${versions:=<empty>}"
printf '%s\n' "${versions//$'\n'/|}"
'''
cases = {
"compact_numeric": '{"data":[{"version":"1.0.0"}]}',
"spaced_numeric": '{ "data" : [ { "version" : "1.0.0" } ] }',
"string_around_numbers": '"version":" 1.0.0 "]',
"numeric_version_with_pre": '"version":"1.0.0-alpha.1"',
"nonnumeric": '"version":"main"',
"unsupported_alphanumeric_in_version": '"version":"1.0.0a"',
"missing_version_key": '{"data":[{"name":"1.0.0"}]}',
}
for name, payload in cases.items():
env = {"VERSION_PAYLOAD": payload}
out = subprocess.run(["bash", "-c", script, "script", "${VERSION_PAYLOAD}"], capture_output=True, text=True, env=env)
print(f"{name}: exit={out.returncode}, stdout={out.stdout!r}, stderr={out.stderr!r}")
print("\nProbe bash for loop splitting on common SemVer values:")
for ver in ["1.0.0", "1.0.0-alpha", "1.0.0-alpha.1", "2.0.0-beta+build"]:
out = subprocess.run(["bash", "-c", 'for v in $1; do printf "[%s]\\n" "$v"; done', "name", ver], capture_output=True, text=True)
print(f"for {ver!r}: stdout={out.stdout.rstrip()}")
PYRepository: rainlanguage/rainix Length of output: 4197 🌐 Web query:
💡 Result: In the Soldeer API v1, the registry uses a versioning system that primarily relies on SemVer, but the tool accepts flexible "version requirement" strings for dependency resolution [1][2]. Registry and Versioning Mechanics The Soldeer registry interaction (e.g., via the /api/v1/revision endpoint) manages dependencies indexed by project name and version [3]. While the registry typically expects valid SemVer versions for hosted packages, the Soldeer CLI provides advanced support for version requirement specifiers in configuration files (foundry.toml or soldeer.toml) and command-line inputs [1][2]. Version Requirement String Examples The following examples illustrate how version requirements are parsed by the Soldeer CLI, following the semver::VersionReq specification: - 1.2.3: Matches exactly version 1.2.3 (equivalent to =1.2.3) [1]. - ^1.2.3: Allows patch and minor version increases, but restricts the major version [1]. - Citations:
🌐 Web query:
💡 Result: The Soldeer API endpoint /api/v1/revision is used by the Soldeer CLI (and via the Citations:
🌐 Web query:
💡 Result: The Soldeer registry is designed to work with packages that follow semantic versioning (SemVer) [1]. While Soldeer uses a version requirement string for installing dependencies [2], which allows for flexibility like wildcards ( Citations:
Use an API-compatible JSON parser for registry versions. The current 🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| missing="" | ||||||||||||||||||||
| for v in $versions; do | ||||||||||||||||||||
| suffix=$(printf '%s' "$v" | tr . _) | ||||||||||||||||||||
| for p in "$@"; do | ||||||||||||||||||||
| for kind in ADDRESS CODEHASH; do | ||||||||||||||||||||
| name="${p}_${kind}_${suffix}" | ||||||||||||||||||||
| grep -qE "constant ${name} =" "$lib" || missing="${missing} ${name}" | ||||||||||||||||||||
| done | ||||||||||||||||||||
| done | ||||||||||||||||||||
| done | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if [ -n "$missing" ]; then | ||||||||||||||||||||
| printf 'MISSING:%s' "$missing" | ||||||||||||||||||||
| else | ||||||||||||||||||||
| printf 'OK' | ||||||||||||||||||||
| fi | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| setup() { | ||
| TESTDIR="$(mktemp -d)" | ||
| # Stub curl on PATH so no test touches the network. STUB_CURL_FAIL simulates | ||
| # an unreachable registry; otherwise the stub prints the file named by | ||
| # STUB_CURL_PAYLOAD as the registry response. | ||
| mkdir -p "$TESTDIR/bin" | ||
| cat > "$TESTDIR/bin/curl" << 'EOF' | ||
| #!/usr/bin/env bash | ||
| if [ -n "${STUB_CURL_FAIL:-}" ]; then | ||
| exit 22 | ||
| fi | ||
| cat "$STUB_CURL_PAYLOAD" | ||
| EOF | ||
| chmod +x "$TESTDIR/bin/curl" | ||
| PATH="$TESTDIR/bin:$PATH" | ||
| SCRIPT="./lib/check-published-deploy-constants.sh" | ||
| } | ||
|
|
||
| teardown() { | ||
| rm -rf "$TESTDIR" | ||
| } | ||
|
|
||
| _write_payload() { | ||
| STUB_CURL_PAYLOAD="$TESTDIR/payload.json" | ||
| export STUB_CURL_PAYLOAD | ||
| cat > "$STUB_CURL_PAYLOAD" | ||
| } | ||
|
|
||
| # The flake task execs the script's nix store copy directly, and the store | ||
| # canonicalizes the git file mode (644 -> 0444, 755 -> 0555), so the tracked | ||
| # file must carry the exec bit or the task dies with EACCES. | ||
| @test "script is executable" { | ||
| [ -x "$SCRIPT" ] | ||
| } | ||
|
|
||
| @test "malformed invocation prints usage to stderr and exits 1" { | ||
| run "$SCRIPT" only-two-args "$TESTDIR/lib.sol" | ||
| [ "$status" -eq 1 ] | ||
| [[ "$output" == *"Usage: check-published-deploy-constants"* ]] | ||
| } | ||
|
|
||
| @test "unreachable registry prints connectivity SKIP and exits 0" { | ||
| export STUB_CURL_FAIL=1 | ||
| run "$SCRIPT" somepkg "$TESTDIR/lib.sol" DEPLOYED | ||
| [ "$status" -eq 0 ] | ||
| [ "$output" = "SKIP: could not fetch published soldeer versions" ] | ||
| } | ||
|
|
||
| @test "reachable registry with no parseable versions prints a distinct SKIP and exits 0" { | ||
| _write_payload << 'EOF' | ||
| {"data":[],"status":"success"} | ||
| EOF | ||
| run "$SCRIPT" somepkg "$TESTDIR/lib.sol" DEPLOYED | ||
| [ "$status" -eq 0 ] | ||
| [ "$output" = "SKIP: no versions parsed from registry response" ] | ||
| } | ||
|
|
||
| @test "prints OK when every published version has its full constant suite" { | ||
| _write_payload << 'EOF' | ||
| {"data":[{"version":"1.0.0"},{"version":"1.2.3"}]} | ||
| EOF | ||
| cat > "$TESTDIR/lib.sol" << 'EOF' | ||
| address constant DEPLOYED_ADDRESS_1_0_0 = address(1); | ||
| bytes32 constant DEPLOYED_CODEHASH_1_0_0 = bytes32(0); | ||
| address constant DEPLOYED_ADDRESS_1_2_3 = address(2); | ||
| bytes32 constant DEPLOYED_CODEHASH_1_2_3 = bytes32(0); | ||
| EOF | ||
| run "$SCRIPT" somepkg "$TESTDIR/lib.sol" DEPLOYED | ||
| [ "$status" -eq 0 ] | ||
| [ "$output" = "OK" ] | ||
| } | ||
|
|
||
| @test "prints MISSING with each absent constant name across prefixes and exits 0" { | ||
| _write_payload << 'EOF' | ||
| {"data":[{"version":"1.0.0"}]} | ||
| EOF | ||
| cat > "$TESTDIR/lib.sol" << 'EOF' | ||
| address constant OBV2_ADDRESS_1_0_0 = address(1); | ||
| bytes32 constant OBV2_CODEHASH_1_0_0 = bytes32(0); | ||
| address constant OBV3_ADDRESS_1_0_0 = address(2); | ||
| EOF | ||
| run "$SCRIPT" somepkg "$TESTDIR/lib.sol" OBV2 OBV3 | ||
| [ "$status" -eq 0 ] | ||
| [ "$output" = "MISSING: OBV3_CODEHASH_1_0_0" ] | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.