feat(deploy): add shared check-published-deploy-constants script - #238
feat(deploy): add shared check-published-deploy-constants script#238thedavidmeister wants to merge 3 commits into
Conversation
Parameterizes the deploy-constants completeness check that raindex
currently hardcodes in script/check-published-deploy-constants.sh.
Exposes check-published-deploy-constants on sol-shell PATH so any
consumer repo can run it via:
nix develop github:rainlanguage/rainix#sol-shell \
-c check-published-deploy-constants <pkg> <lib.sol> <PREFIX1> ...
Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe change adds a parameterized Bash script that checks published Soldeer versions against versioned deployment constants in a Solidity file. It exposes the script as a Nix task and adds Bats coverage for validation outcomes and shell availability. ChangesDeploy Constants Completeness Check
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Validator
participant SoldeerAPI
participant SolidityFile
Caller->>Validator: Provide package, file, and prefixes
Validator->>SoldeerAPI: Fetch published versions
SoldeerAPI-->>Validator: Return registry response
Validator->>SolidityFile: Check versioned address and codehash constants
SolidityFile-->>Validator: Return matching declarations
Validator-->>Caller: Print SKIP, MISSING, or OK
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1⚔️ Resolve merge conflicts 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
…dInputs list Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
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 `@lib/check-published-deploy-constants.sh`:
- Around line 26-29: The argument validation in check-published-deploy-constants
should follow the same success-only CLI contract as the rest of the script, so
replace the early failure exit with a zero-status path that emits one of the
allowed statuses instead of aborting. Update the main guard around the usage
check and any caller-facing output so the script never returns a nonzero code
for this case, keeping the observable results limited to OK, MISSING, or SKIP.
- Around line 35-42: The version lookup in check-published-deploy-constants.sh
is treating parse failures the same as fetch failures because the `versions`
pipeline ends with `|| true`, so `grep`/`cut` empties fall through to the `SKIP`
branch. Update the shell logic around the `curl`/`grep`/`cut` pipeline so only
real connectivity/request failures are ignored, while malformed or unexpected
API responses are detected separately and reported as a parse/API drift issue
instead of `SKIP`; use the existing `versions` assignment and the `if [ -z
"$versions" ]` check to split these cases clearly.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b2d7aea4-4d8e-440f-81a9-ac59b36215bc
📒 Files selected for processing (3)
flake.nixlib/check-published-deploy-constants.shtest/bats/devshell/sol-shell/sol-tasks.test.bats
|
🤖 ai:vetter |
|
Human reject (adversarial sweep, David-authorized 2026-07-09). The script deliverable is present, but the sole added test asserts only |
…from parse CodeRabbit flagged that the `|| true` on the whole version pipeline collapsed a successful fetch that yielded no parseable versions into the connectivity `SKIP: could not fetch published soldeer versions`, masking parser/API drift as an unreachable registry. Split the two. The curl invocation is now guarded on its own, so only a real request failure reports the connectivity SKIP. A reachable registry whose response yields no versions gets its own `SKIP: no versions parsed from registry response`, which is still a zero-exit SKIP (nothing was verified) but names a cause an operator can act on. Also fixes the tracked file mode. The flake task execs the script directly from its nix store path, and the store canonicalizes the git mode, so a 644 file becomes 0444 and the task dies with EACCES. Marking it 755 makes the store copy 0555. A bats case asserts the exec bit so this cannot silently regress. `cut`, `sort` and `tr` in the version pipeline came from the ambient PATH, which mkTask only prefixes rather than replaces; coreutils is now a declared build input of the task. Documents why a malformed invocation keeps its nonzero exit. The OK/MISSING/SKIP success-only contract describes REGISTRY state, which must never red a consumer pipeline. Fewer than three arguments is a caller bug, not a registry state, and a miswired CI step must fail loud rather than skip forever. New bats suite covers the exec bit, the usage exit, both SKIP branches, OK, and MISSING across multiple prefixes, with curl stubbed so no test touches the network. Wired into the default-shell-test task alongside the existing suites. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/check-published-deploy-constants.sh (1)
61-67: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReject an unreadable deploy-library path.
If
libis missing or unreadable, everygrepat Line 67 fails. The|| missing=...branch converts that file error intoMISSINGwith exit status 0. Validatelibbefore the registry request and return a caller error instead.Suggested fix
shift 2 + +if [[ ! -f "$lib" || ! -r "$lib" ]]; then + printf 'Error: deploy library is not a readable file: %s\n' "$lib" >&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 `@lib/check-published-deploy-constants.sh` around lines 61 - 67, Validate that the deploy-library path in the surrounding script is an existing, readable file before issuing the registry request or entering the version/constant checks. If validation fails, report a caller-facing error and exit nonzero; keep the existing missing-constant handling for readable libraries unchanged.
🧹 Nitpick comments (2)
test/bats/task/check-published-deploy-constants.test.bats (1)
1-17: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winAssert the registry request in the curl stub.
The stub at Lines 7-12 ignores all curl arguments. The tests can pass if the script uses the wrong package, endpoint, or pagination parameters. Record
"$@"and assert the expected request in at least one test.🤖 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 `@test/bats/task/check-published-deploy-constants.test.bats` around lines 1 - 17, Update the setup curl stub to record its received arguments, then add an assertion in at least one test verifying the expected package, endpoint, and pagination parameters used by the script. Keep the existing failure and payload behavior unchanged.lib/check-published-deploy-constants.sh (1)
64-67: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winValidate prefixes before using them as regular expressions.
Line 67 interpolates each caller-supplied prefix into
grep -E. A prefix such asDEPLOYED|OTHERchanges the expression and can match an unintended constant. Enforce Solidity-identifier syntax for prefixes, or escape the generated name before matching.🤖 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 `@lib/check-published-deploy-constants.sh` around lines 64 - 67, Validate each caller-supplied prefix in the outer loop before constructing name and passing it to grep -E, restricting it to valid Solidity-identifier syntax; reject invalid prefixes and preserve the existing missing-name behavior for valid inputs.
🤖 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 `@lib/check-published-deploy-constants.sh`:
- Around line 42-45: Update the curl invocation in the published-version check
to include both connection and total-request time limits, using appropriate
finite timeout values before the existing failure handling skips the check.
Preserve the current response capture, silent error behavior, and SKIP path.
- Around line 51-59: The version extraction in the registry-response parsing
block must use an API-compatible JSON parser to read data[].version instead of
the restrictive grep pattern. Distinguish fetch failure, JSON parse failure, an
empty version list, and unsupported version formats, while preserving all valid
registry version strings including SemVer metadata and non-numeric values.
---
Outside diff comments:
In `@lib/check-published-deploy-constants.sh`:
- Around line 61-67: Validate that the deploy-library path in the surrounding
script is an existing, readable file before issuing the registry request or
entering the version/constant checks. If validation fails, report a
caller-facing error and exit nonzero; keep the existing missing-constant
handling for readable libraries unchanged.
---
Nitpick comments:
In `@lib/check-published-deploy-constants.sh`:
- Around line 64-67: Validate each caller-supplied prefix in the outer loop
before constructing name and passing it to grep -E, restricting it to valid
Solidity-identifier syntax; reject invalid prefixes and preserve the existing
missing-name behavior for valid inputs.
In `@test/bats/task/check-published-deploy-constants.test.bats`:
- Around line 1-17: Update the setup curl stub to record its received arguments,
then add an assertion in at least one test verifying the expected package,
endpoint, and pagination parameters used by the script. Keep the existing
failure and payload behavior unchanged.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 96fa4bd1-fd4a-46b6-b723-261f6853fd31
📒 Files selected for processing (3)
flake.nixlib/check-published-deploy-constants.shtest/bats/task/check-published-deploy-constants.test.bats
🚧 Files skipped from review as they are similar to previous changes (1)
- flake.nix
| 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 |
There was a problem hiding this comment.
🩺 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.
curl can wait indefinitely for DNS, connection establishment, or data transfer. Add --connect-timeout and --max-time before switching to SKIP if the registry request fails.
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
‼️ 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.
| 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 | |
| if ! response=$(curl -fsS --connect-timeout 10 --max-time 30 \ | |
| "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 |
🤖 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 `@lib/check-published-deploy-constants.sh` around lines 42 - 45, Update the
curl invocation in the published-version check to include both connection and
total-request time limits, using appropriate finite timeout values before the
existing failure handling skips the check. Preserve the current response
capture, silent error behavior, and SKIP path.
| 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 | ||
| fi |
There was a problem hiding this comment.
🗄️ 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:
Soldeer API v1 revision version field data version string examples non-semver version strings registry
💡 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]. - 1.2.3: Allows only patch version increases [1]. - >=1.2.3: Matches any version greater than or equal to 1.2.3 [1]. - 1: Matches any version >=1.0.0 and <2.0.0 (compatible with SemVer range logic) [1]. - >1.2.3,<1.4.0: Matches a specific range [1]. Non-SemVer Handling For non-SemVer scenarios, such as tracking specific git-based dependencies, Soldeer uses revision identifiers (hashes, tags, or branches) rather than version strings [4][5]. When installing or managing these, you use distinct flags: - --rev <COMMIT_HASH>: Pins a dependency to a specific git commit [4][5]. - --tag : Pins a dependency to a specific git tag [4][5]. - --branch : Tracks a specific git branch [4][5]. These non-SemVer identifiers are distinct from the registry-based "version" field used in the package metadata (which should generally remain SemVer-compliant for registry publishing) [6]. When using git, the dependency is typically specified in the format library_nameversion (or alias) followed by the relevant git metadata flags [4][5].
Citations:
- 1: https://github.com/mario-eth/soldeer/blob/main/USAGE.md
- 2: feat!: v0.4.0 rewrite mario-eth/soldeer#202
- 3: bug(
forge soldeer):forge soldeer updatecrashes foundry-rs/foundry#9937 - 4: https://paritytech.github.io/foundry-book-polkadot/projects/soldeer.html
- 5: https://www.getfoundry.sh/reference/forge/soldeer/install
- 6: https://www.getfoundry.sh/projects/soldeer
🌐 Web query:
Soldeer api/v1/revision response version field "version" string examples
💡 Result:
The Soldeer API endpoint /api/v1/revision is used by the Soldeer CLI (and via the forge soldeer integration in Foundry) to fetch dependency information from the central registry [1]. In the context of the Soldeer registry and its API responses, the version field is typically represented as a string following Semantic Versioning (SemVer) conventions [2][3]. Examples of version strings commonly encountered in Soldeer configurations, registry requests, and lockfiles include: Standard Semantic Versions: "1.0.0" "1.8.1" "5.0.2" "6.7.0" In the Soldeer CLI and dependency definitions (e.g., in foundry.toml or soldeer.toml), version strings are often associated with the package name using a tilde () separator, such as forge-std1.9.2 or @openzeppelin-contracts~5.0.2 [2][3]. When interacting with the registry API directly—for instance, when querying revisions for a project—the registry returns these version strings to identify specific releases of a package [1]. As an authoritative reference, the soldeer-core Rust crate defines the data structures for these API interactions, where registry responses map version identifiers to the corresponding dependency metadata [4][5]. If you are working with the API programmatically, expect the version field to be a standard JSON string adhering to the format defined by your specific project's releases on the registry [1].
Citations:
- 1: bug(
forge soldeer):forge soldeer updatecrashes foundry-rs/foundry#9937 - 2: https://paritytech.github.io/foundry-book-polkadot/projects/soldeer.html
- 3: https://www.getfoundry.sh/projects/soldeer
- 4: https://docs.rs/soldeer-core/latest/soldeer_core/all.html
- 5: https://docs.rs/soldeer-core/latest/soldeer_core/
🌐 Web query:
Soldeer registry non-semver published version string
💡 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 (*) and range operators (^, ~, >, >=), these mechanisms are fundamentally built to operate on SemVer-compliant version identifiers [2]. There is no explicit support or official documentation indicating that the Soldeer registry supports or validates non-SemVer version strings. In practice, Soldeer expects registry packages to be published with valid SemVer versions to ensure that its dependency resolution, version locking, and range-matching features function correctly [2][1]. If a package does not follow SemVer, it may cause issues with automated dependency resolution or prevent the registry from correctly identifying and serving the requested versions. For developers needing to manage non-SemVer dependencies, the Soldeer CLI provides alternative installation methods, such as using direct Git URLs (with support for specific branches, tags, or commit hashes) or custom ZIP URLs [3]. These methods bypass the registry's versioning requirements and allow for arbitrary version identifiers that do not need to adhere to SemVer [2][3].
Citations:
- 1: https://www.getfoundry.sh/projects/soldeer
- 2: https://github.com/mario-eth/soldeer/blob/main/USAGE.md
- 3: https://www.getfoundry.sh/reference/forge/soldeer/install
Use an API-compatible JSON parser for registry versions.
The current grep -oE '"version":"[0-9][0-9.]*"' pattern rejects valid JSON spacing, SemVer pre-release/build metadata, and any non-numeric registry version strings. If the response is reachable, an unsupported JSON shape should be treated as parsing drift, not “no parseable versions,” and known supported formats should not be dropped. Use a JSON parser for the data[].version field, with separate outcomes for fetch failure, parse failure, empty version list, and unsupported version format.
🤖 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 `@lib/check-published-deploy-constants.sh` around lines 51 - 59, The version
extraction in the registry-response parsing block must use an API-compatible
JSON parser to read data[].version instead of the restrictive grep pattern.
Distinguish fetch failure, JSON parse failure, an empty version list, and
unsupported version formats, while preserving all valid registry version strings
including SemVer metadata and non-numeric values.
Closes #236
Adds a parameterized
check-published-deploy-constantsscript tolib/and exposes it onsol-shellPATH. Consumers (raindex, rain.math.float, etc.) can drop their bespoke copies and call the shared version via:The script queries the soldeer registry for all published versions of the named package, then asserts
<PREFIX>_{ADDRESS,CODEHASH}_<ver>constants exist in the given Solidity file. Exits 0 in all cases; printsOK,MISSING: <names>, orSKIP: <reason>(if the registry is unreachable).Co-Authored-By: Claude noreply@anthropic.com
Summary by CodeRabbit