-
Notifications
You must be signed in to change notification settings - Fork 125
feat: add DST setup #879
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?
feat: add DST setup #879
Conversation
Signed-off-by: Clément Salaün <[email protected]>
Signed-off-by: Clément Salaün <[email protected]>
WalkthroughCreateLedger was made fully transactional (RunInTx) covering system-store insert, bucket init/migrate/add, and ledger-store creation; many Antithesis Earthfiles, workload binaries, helper scripts, and Justfiles were added; a minor import reorder occurred in a generator tool. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller as API/Service
participant Driver as Driver.CreateLedger
participant DB as DB (RunInTx)
participant Sys as SystemStore
participant BF as BucketFactory
participant B as Bucket
participant LSF as LedgerStoreFactory
Caller->>Driver: CreateLedger(ctx, ledger)
Driver->>DB: RunInTx(ctx, fn)
alt transaction
DB->>Sys: CreateLedger(record)
Sys-->>DB: success / constraint violation
DB->>BF: Create(bucketName)
BF-->>DB: bucket instance
DB->>B: IsInitialized?
alt initialized
DB->>B: IsUpToDate?
alt outdated
note right of B: assert.AlwaysOrUnreachable -> ErrBucketOutdated
DB-->>Driver: rollback + error
else up-to-date
DB->>B: AddLedger(l)
end
else not initialized
DB->>B: Migrate()
end
DB->>LSF: CreateStore(bucket, ledger)
LSF-->>DB: LedgerStore
DB-->>Driver: commit with store
else error
DB-->>Driver: rollback with error
end
Driver-->>Caller: store or resolved error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks (3 warnings)❌ Failed checks (3 warnings)
Poem
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal). Please share your feedback with us on this Discord post. 📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
✨ Finishing Touches
🧪 Generate unit tests
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 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #879 +/- ##
==========================================
- Coverage 80.62% 80.59% -0.03%
==========================================
Files 186 186
Lines 10207 10324 +117
==========================================
+ Hits 8229 8321 +92
- Misses 1559 1580 +21
- Partials 419 423 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Nitpick comments (11)
test/antithesis/workload/bin/init/main.go (1)
28-34
: Consider adding a log message for setup completion and shutdown.Adding log messages would make it easier to understand the program flow, especially when running in containerized environments where logs are a primary debugging tool.
lifecycle.SetupComplete(map[string]any{}) + fmt.Println("Setup complete, waiting for termination signal") sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) <-sigs + fmt.Println("Received termination signal, shutting down") }test/antithesis/image/entrypoint.sh (1)
11-11
: Add proper signal handling for container graceful shutdown.The script should properly handle termination signals to ensure clean shutdown of the ledger service.
echo "Postgres is ready; serving ledger!" +# Handle termination signals +trap 'echo "Received termination signal. Shutting down..."; kill -TERM $child_pid 2>/dev/null; exit 0' SIGTERM SIGINT + ledger serve +child_pid=$! +wait $child_pidtest/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go (3)
69-71
: Improve error handling consistency.The error handling here doesn't provide specific error details in the assertion, unlike other error checks in the code.
- if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'", nil) { + if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'", internal.Details{ + "error": err, + "ledger": ledger, + }) { return }
19-31
: Consider adding ledger cleanup after test completion.The code creates a new ledger for each test run but doesn't clean it up afterward, which could lead to resource accumulation over time.
Add a defer statement after the ledger creation:
ledger := fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()) + // Ensure ledger cleanup after test + defer func() { + cleanupErr := internal.DeleteLedger(ctx, client, ledger) + if cleanupErr != nil { + fmt.Printf("Warning: Failed to clean up ledger %s: %v\n", ledger, cleanupErr) + } + }() + err := internal.CreateLedger(Note: This assumes there's a
DeleteLedger
function in the internal package. If not, you would need to implement it.
58-61
: Simplify conditional check.The
cond
variable is only used once, making it unnecessary.- cond := !hasError.Load() - if assert.Always(cond, "all transactions should have been written", internal.Details{}); !cond { + if assert.Always(!hasError.Load(), "all transactions should have been written", internal.Details{}); hasError.Load() { return }test/antithesis/workload/Earthfile (3)
43-45
: Add filtering for Go files in the build loop.The current loop builds all directories in bin/cmds without filtering. If there are non-Go files or directories without main packages, this could cause build failures.
- FOR file IN $(ls bin/cmds) - RUN go build -o /out/cmds/$file ./bin/cmds/$file + FOR file IN $(find bin/cmds -type d -not -path "bin/cmds" | xargs -n1 basename) + # Check if the directory contains a main.go file before building + RUN if [ -f ./bin/cmds/$file/main.go ]; then \ + go build -o /out/cmds/$file ./bin/cmds/$file; \ + fi END
56-56
: Consider providing documentation for the required ANTITHESIS_REPOSITORY argument.The ANTITHESIS_REPOSITORY argument is required but has no documentation or validation on format.
- ARG --required ANTITHESIS_REPOSITORY + # ANTITHESIS_REPOSITORY should be in the format of "registry.example.com/project" + ARG --required ANTITHESIS_REPOSITORY + # Validate repository format + RUN if ! echo "${ANTITHESIS_REPOSITORY}" | grep -q "^[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-zA-Z0-9][a-zA-Z0-9.-]*/[a-zA-Z0-9_/-]*$"; then \ + echo "Invalid repository format: ${ANTITHESIS_REPOSITORY}"; \ + echo "Expected format: registry.example.com/project"; \ + exit 1; \ + fi
15-26
: Consider uncommenting the 'tidy' section or add a comment explaining why it's commented out.The 'tidy' section is commented out but might be useful for maintaining clean go.mod files.
Either uncomment the section if it's meant to be used, or add a comment explaining why it's disabled:
-# tidy: -# FROM +sources -# -# CACHE --id go-mod-cache /go/pkg/mod -# CACHE --id go-cache /root/.cache/go-build -# -# WORKDIR /src/test/antithesis/workload -# RUN go mod tidy -# -# SAVE ARTIFACT go.mod AS LOCAL go.mod -# SAVE ARTIFACT go.sum AS LOCAL go.sum +# The 'tidy' target is currently disabled because module maintenance is handled in the main repository. +# Uncomment and use this section when updates to go.mod/go.sum are needed: +# tidy: +# FROM +sources +# +# CACHE --id go-mod-cache /go/pkg/mod +# CACHE --id go-cache /root/.cache/go-build +# +# WORKDIR /src/test/antithesis/workload +# RUN go mod tidy +# +# SAVE ARTIFACT go.mod AS LOCAL go.mod +# SAVE ARTIFACT go.sum AS LOCAL go.sumtest/antithesis/Earthfile (1)
7-26
: Review experiment parametersThe experiment duration is set to
0.1
, which might be very short for meaningful testing. Consider whether this is intended as a minimum value for quick tests or if a longer duration would be more appropriate for thorough testing.Also verify that the fixed image names (
antithesis-config:latest
,ledger:latest
,workload:latest
) match your intended tagging strategy.test/antithesis/workload/internal/utils.go (2)
40-56
: Hardcoded service endpointThe client is configured with a hardcoded URL
http://gateway:8080
. Consider making this configurable via environment variables for better flexibility across different environments.+func NewClientWithURL(serverURL string) *client.Formance { + if serverURL == "" { + serverURL = "http://gateway:8080" // Default URL + } + return client.New( + client.WithServerURL(serverURL), + client.WithClient(&http.Client{ + Timeout: time.Minute, + }), + client.WithRetryConfig(retry.Config{ + Strategy: "backoff", + Backoff: &retry.BackoffStrategy{ + InitialInterval: 200, + Exponent: 1.5, + MaxElapsedTime: 4000, + }, + RetryConnectionErrors: true, + }), + ) +} + func NewClient() *client.Formance { - return client.New( - client.WithServerURL("http://gateway:8080"), - client.WithClient(&http.Client{ - Timeout: time.Minute, - }), - client.WithRetryConfig(retry.Config{ - Strategy: "backoff", - Backoff: &retry.BackoffStrategy{ - InitialInterval: 200, - Exponent: 1.5, - MaxElapsedTime: 4000, - }, - RetryConnectionErrors: true, - }), - ) + return NewClientWithURL("") }
66-82
: Transaction function with hardcoded valuesThe
RunTx
function uses hardcoded values for asset ("USD/2"
) and source account ("world"
). Consider making these configurable parameters to support testing different asset types and account structures.-func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { +func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string, asset string, source string) error { + if asset == "" { + asset = "USD/2" // Default asset + } + if source == "" { + source = "world" // Default source + } orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ V2PostTransaction: components.V2PostTransaction{ Postings: []components.V2Posting{{ Amount: amount, - Asset: "USD/2", + Asset: asset, Destination: dest, - Source: "world", + Source: source, }}, }, Ledger: ledger, }) return err }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
go.mod
is excluded by!**/*.mod
go.sum
is excluded by!**/*.sum
,!**/*.sum
test/antithesis/config/docker-compose.yml
is excluded by!**/*.yml
test/antithesis/workload/go.mod
is excluded by!**/*.mod
test/antithesis/workload/go.sum
is excluded by!**/*.sum
,!**/*.sum
📒 Files selected for processing (13)
internal/controller/system/controller.go
(1 hunks)internal/storage/driver/driver.go
(4 hunks)pkg/client/Earthfile
(1 hunks)test/antithesis/Earthfile
(1 hunks)test/antithesis/config/Earthfile
(1 hunks)test/antithesis/config/gateway/Caddyfile
(1 hunks)test/antithesis/image/Earthfile
(1 hunks)test/antithesis/image/entrypoint.sh
(1 hunks)test/antithesis/workload/Earthfile
(1 hunks)test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
(1 hunks)test/antithesis/workload/bin/init/main.go
(1 hunks)test/antithesis/workload/internal/utils.go
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/antithesis/workload/bin/init/main.go (2)
test/antithesis/workload/internal/utils.go (1)
NewClient
(40-56)internal/api/v1/controllers_config.go (1)
GetInfo
(36-66)
test/antithesis/workload/internal/utils.go (5)
pkg/client/formance.go (3)
Formance
(70-74)WithClient
(108-112)WithRetryConfig
(130-134)pkg/client/models/operations/v2createledger.go (1)
V2CreateLedgerRequest
(9-13)pkg/client/models/operations/v2createtransaction.go (1)
V2CreateTransactionRequest
(9-23)pkg/client/models/components/v2posttransaction.go (1)
V2PostTransaction
(29-36)pkg/client/models/components/v2posting.go (1)
V2Posting
(10-15)
🪛 GitHub Check: codecov/patch
internal/storage/driver/driver.go
[warning] 84-95: internal/storage/driver/driver.go#L84-L95
Added lines #L84 - L95 were not covered by tests
🔇 Additional comments (15)
internal/controller/system/controller.go (1)
4-7
: Import reordering looks good.The standard library packages
reflect
andtime
have been moved to the top of the import block, following common Go style conventions where standard library imports are grouped together at the top.pkg/client/Earthfile (1)
1-8
: Clean Earthfile setup for the client component.This is a good minimal Earthfile that creates a client artifact from the current directory. Using a scratch image keeps the build artifact lightweight. The golang version (1.22.2) is appropriately recent.
test/antithesis/config/gateway/Caddyfile (1)
1-12
: Appropriate reverse proxy configuration for local development.The Caddy configuration correctly sets up a reverse proxy to ledger services. The
auto_https off
anddebug
options are suitable for a development environment. The load balancing policy of "first" will try the first available backend before attempting the second one.Just note that this configuration is explicitly for development and would need security enhancements (enabling HTTPS, etc.) for any production deployment.
test/antithesis/config/Earthfile (1)
1-11
: Straightforward config build setup.The Earthfile correctly configures a build process to create a config image containing the docker-compose file and gateway directory. The use of
--no-manifest-list
is appropriate when targeting a specific platform.test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go (1)
35-43
: 🛠️ Refactor suggestionFix potential race condition with totalAmount.
There's a potential race condition in how you're calculating the total amount. While the code is adding to totalAmount before submitting the tasks to the pool, this pattern is prone to bugs if the code is modified later.
hasError := atomic.NewBool(false) - totalAmount := big.NewInt(0) + // Track individual amounts for safer aggregation + amounts := make([]*big.Int, count) pool := pond.New(10, 10e3) for i := 0; i < count; i++ { amount := internal.RandomBigInt() - totalAmount = totalAmount.Add(totalAmount, amount) + amounts[i] = amount pool.Submit(func() {Then after line 56 (after pool.StopAndWait()):
pool.StopAndWait() + // Calculate total after all tasks are submitted + totalAmount := big.NewInt(0) + for _, amount := range amounts { + totalAmount = totalAmount.Add(totalAmount, amount) + } + cond := !hasError.Load()Likely an incorrect or invalid review comment.
internal/storage/driver/driver.go (3)
10-10
: Great addition of the Antithesis SDKThe import of the Antithesis assert package is appropriate for the new assertion functionality added in this file.
40-53
: Excellent documentation improvementAdding this comprehensive doc comment significantly improves code clarity. The step-by-step explanation of the ledger creation process and transaction handling makes the complex functionality much easier to understand for developers.
57-59
: Good inline commentsThese explanatory comments help track the progress through the ledger creation process and align with the high-level documentation. This makes the code much more maintainable.
Also applies to: 62-63, 108-109, 114-115, 119-120
test/antithesis/Earthfile (3)
1-6
: LGTM - Base configuration setupThe Earthfile version and imports look correct. Using a tagged version of the core Earthly configuration is a good practice for stability.
27-52
: Good debugging setupThe debugging target properly handles session parameters and shows them for verification before submission. The approach of creating a temporary JSON file for the parameters is clean and maintainable.
53-58
: LGTM - Build dependencies handled correctlyThe requirements-build target properly passes arguments to the component build targets and enforces the required ANTITHESIS_REPOSITORY argument.
test/antithesis/image/Earthfile (1)
7-9
: Good cache configurationUsing shared caching for Go modules and build artifacts is an excellent practice that will speed up builds.
test/antithesis/workload/internal/utils.go (3)
19-26
: Good utility type and random functionThe
Details
type andRandomBigInt
function are well-implemented. The random function correctly converts the random value to a big integer for use in financial transactions.
28-38
: Helpful assertion wrappersThese wrapper functions around the Antithesis assertion library provide a consistent interface for making assertions throughout the workload code. The return values allow for fluent usage in conditional blocks.
58-64
: Simple, focused ledger creation functionThis function provides a clean wrapper around the client API for creating ledgers, making the workload code more readable.
func main() { | ||
ctx := context.Background() | ||
client := internal.NewClient() | ||
|
||
for { | ||
time.Sleep(time.Second) | ||
|
||
_, err := client.Ledger.GetInfo(ctx) | ||
if err != nil { | ||
continue | ||
} | ||
break | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding error logging and timeout to service readiness loop.
The polling mechanism to check for service readiness is a good approach, but it currently lacks error logging and a timeout mechanism. Without these, it could poll indefinitely if the service never becomes available, and debugging could be difficult if there are connection issues.
func main() {
ctx := context.Background()
client := internal.NewClient()
+
+ maxAttempts := 60 // 1 minute timeout with 1-second intervals
+ attempt := 0
for {
+ attempt++
time.Sleep(time.Second)
_, err := client.Ledger.GetInfo(ctx)
if err != nil {
+ if attempt >= maxAttempts {
+ panic("Timed out waiting for ledger service to be ready")
+ }
+ fmt.Printf("Waiting for ledger service to be ready (attempt %d/%d): %v\n", attempt, maxAttempts, err)
continue
}
+ fmt.Println("Ledger service is ready")
break
}
Don't forget to add the fmt import:
import (
"context"
+ "fmt"
"os"
"os/signal"
"syscall"
"time"
📝 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.
func main() { | |
ctx := context.Background() | |
client := internal.NewClient() | |
for { | |
time.Sleep(time.Second) | |
_, err := client.Ledger.GetInfo(ctx) | |
if err != nil { | |
continue | |
} | |
break | |
} | |
import ( | |
"context" | |
"fmt" | |
"os" | |
"os/signal" | |
"syscall" | |
"time" | |
) | |
func main() { | |
ctx := context.Background() | |
client := internal.NewClient() | |
maxAttempts := 60 // 1 minute timeout with 1-second intervals | |
attempt := 0 | |
for { | |
attempt++ | |
time.Sleep(time.Second) | |
_, err := client.Ledger.GetInfo(ctx) | |
if err != nil { | |
if attempt >= maxAttempts { | |
panic("Timed out waiting for ledger service to be ready") | |
} | |
fmt.Printf("Waiting for ledger service to be ready (attempt %d/%d): %v\n", attempt, maxAttempts, err) | |
continue | |
} | |
fmt.Println("Ledger service is ready") | |
break | |
} | |
// rest of your shutdown or signal handling logic… | |
} |
test/antithesis/image/entrypoint.sh
Outdated
until pg_isready -d ledger -h 10.0.29.16 -U ledger | ||
do | ||
echo "Waiting for postgres at: $POSTGRES_URI" | ||
sleep 2; | ||
done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make database connection parameters configurable via environment variables.
The script uses hardcoded database host, name, and user values. This reduces portability and makes configuration changes difficult.
-until pg_isready -d ledger -h 10.0.29.16 -U ledger
+# Extract parameters from POSTGRES_URI or use default values
+PG_HOST=${PG_HOST:-10.0.29.16}
+PG_DB=${PG_DB:-ledger}
+PG_USER=${PG_USER:-ledger}
+
+until pg_isready -d "$PG_DB" -h "$PG_HOST" -U "$PG_USER"
📝 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.
until pg_isready -d ledger -h 10.0.29.16 -U ledger | |
do | |
echo "Waiting for postgres at: $POSTGRES_URI" | |
sleep 2; | |
done | |
# Extract parameters from environment or fall back to existing defaults | |
PG_HOST=${PG_HOST:-10.0.29.16} | |
PG_DB=${PG_DB:-ledger} | |
PG_USER=${PG_USER:-ledger} | |
until pg_isready -d "$PG_DB" -h "$PG_HOST" -U "$PG_USER" | |
do | |
echo "Waiting for postgres at: $POSTGRES_URI" | |
sleep 2; | |
done |
🛠️ Refactor suggestion
Add a timeout to prevent infinite waiting.
The current loop will wait indefinitely if PostgreSQL never becomes available.
+MAX_RETRIES=30
+retry_count=0
+
until pg_isready -d ledger -h 10.0.29.16 -U ledger
do
+ retry_count=$((retry_count+1))
+ if [ $retry_count -ge $MAX_RETRIES ]; then
+ echo "ERROR: PostgreSQL not available after $MAX_RETRIES attempts. Exiting."
+ exit 1
+ fi
echo "Waiting for postgres at: $POSTGRES_URI"
sleep 2;
done
📝 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.
until pg_isready -d ledger -h 10.0.29.16 -U ledger | |
do | |
echo "Waiting for postgres at: $POSTGRES_URI" | |
sleep 2; | |
done | |
MAX_RETRIES=30 | |
retry_count=0 | |
until pg_isready -d ledger -h 10.0.29.16 -U ledger | |
do | |
retry_count=$((retry_count+1)) | |
if [ $retry_count -ge $MAX_RETRIES ]; then | |
echo "ERROR: PostgreSQL not available after $MAX_RETRIES attempts. Exiting." | |
exit 1 | |
fi | |
echo "Waiting for postgres at: $POSTGRES_URI" | |
sleep 2; | |
done |
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { | ||
assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{ | ||
"error": err, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix incorrect error reference in assertion details.
In the assertion for each asset's volume, you're referencing the err
variable that has already been checked to be nil earlier in the code. This is misleading and could cause confusion.
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data {
- assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{
- "error": err,
- })
+ assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{
+ "asset": asset,
+ "value": volumes.String(),
+ })
}
📝 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.
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { | |
assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{ | |
"error": err, | |
}) | |
} | |
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { | |
assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{ | |
"asset": asset, | |
"value": volumes.String(), | |
}) | |
} |
func main() { | ||
ctx := context.Background() | ||
client := internal.NewClient() | ||
|
||
aggregated, err := client.Ledger.V2.GetBalancesAggregated(ctx, operations.V2GetBalancesAggregatedRequest{ | ||
Ledger: "default", | ||
}) | ||
if err != nil { | ||
assert.Always(err == nil, "error getting aggregated balances", internal.Details{ | ||
"error": err, | ||
}) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Implement retry mechanism for eventual consistency check.
The filename includes "eventually_" which suggests this check should be retried until it succeeds or times out. Currently, it only checks once without any retry logic.
func main() {
ctx := context.Background()
client := internal.NewClient()
+
+ // Add retry with timeout for eventual consistency
+ const maxRetries = 30
+ const retryDelayMs = 500
+
+ var lastErr error
+ for i := 0; i < maxRetries; i++ {
+ success := tryCheck(ctx, client)
+ if success {
+ return // Success case exits cleanly
+ }
+
+ // Wait before retry
+ time.Sleep(time.Duration(retryDelayMs) * time.Millisecond)
+ }
+
+ // If we get here, we've exceeded our retry attempts
+ assert.Always(false, "aggregated volumes not zeroed after maximum retries", internal.Details{})
+}
+
+func tryCheck(ctx context.Context, client *internal.Client) bool {
Further down, you would need to modify the end of the function to return a boolean success value instead of just returning:
if err != nil {
assert.Always(err == nil, "error getting aggregated balances", internal.Details{
"error": err,
})
- return
+ return false
}
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data {
- assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{
- "error": err,
- })
+ if volumes.Cmp(new(big.Int)) != 0 {
+ return false
+ }
}
+ return true
}
Committable suggestion skipped: line range outside the PR's diff.
CACHE --id go-mod-cache /go/pkg/mod | ||
CACHE --id go-cache /root/.cache/go-build | ||
|
||
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Pin the version of antithesis-go-instrumentor tool.
Using @latest
for tools can lead to inconsistent builds and unexpected breaking changes. Consider pinning to a specific version.
- RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest
+ RUN go install github.com/antithesishq/antithesis-sdk-go/tools/[email protected] # Use appropriate version
📝 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.
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest | |
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@v0.5.2 # Use appropriate version |
internal/storage/driver/driver.go
Outdated
assert.AlwaysOrUnreachable( | ||
// @todo: replace this with a proper flag detailing wether we're | ||
// operating a new version of the binary or not. | ||
// if we are, we are definitely expecting this to happen. | ||
// if we're not, this should be unreachable. | ||
false, | ||
"Bucket is outdated", | ||
map[string]any{ | ||
"bucket": l.Bucket, | ||
}, | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Todo indicates temporary assertion pattern
The assertion is using false
as the condition, which means it will always trigger as "unreachable". The TODO comments indicate this is a temporary solution, but this code path isn't covered by tests.
Consider:
- Adding a proper flag parameter as mentioned in the TODO
- Adding tests to cover this code path
🏁 Script executed:
#!/bin/bash
# Check if there are any tests covering this assertion in the driver code
rg -A 5 -B 5 "test.*Bucket.*Outdated" --type go
Length of output: 49
To be certain this assertion path is untested, let’s list any driver test files and search them for AlwaysOrUnreachable
:
🏁 Script executed:
#!/bin/bash
# List Go test files in internal/storage/driver
fd -e go --glob '*_test.go' internal/storage/driver
# Search those test files for AlwaysOrUnreachable
rg "AlwaysOrUnreachable" -n --glob "internal/storage/driver/*_test.go"
Length of output: 348
Ensure proper flag control and add tests for the unreachable assertion
The assert.AlwaysOrUnreachable(false, …)
at internal/storage/driver/driver.go:84–95 is built to always fire, and our search shows no tests reference AlwaysOrUnreachable
to cover this path. To address:
• Introduce the boolean flag referenced in the TODO (e.g. isNewBinaryVersion
) instead of hard‑coding false
.
• Add unit tests in internal/storage/driver/driver_test.go (or a new test) that cover both cases:
- Flag =
true
(assertion bypassed) - Flag =
false
(assertion triggers)
This will satisfy the TODO and ensure the code path is exercised.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 84-95: internal/storage/driver/driver.go#L84-L95
Added lines #L84 - L95 were not covered by tests
test/antithesis/image/Earthfile
Outdated
compile: | ||
FROM --platform=linux/amd64 golang:1.23 | ||
CACHE --sharing=shared --id go-mod-cache /go/pkg/mod | ||
CACHE --sharing=shared --id go-cache /root/.cache/go-build | ||
|
||
COPY ../../..+sources/src /src | ||
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest | ||
WORKDIR /src | ||
|
||
RUN go mod download | ||
RUN mkdir -p /ledger_instrumented | ||
RUN /go/bin/antithesis-go-instrumentor . /ledger_instrumented | ||
|
||
WORKDIR /ledger_instrumented/customer | ||
RUN go build -race -o ledger | ||
|
||
SAVE ARTIFACT /ledger_instrumented/customer/ledger | ||
SAVE ARTIFACT /ledger_instrumented/symbols | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Check Go version
The compile stage uses golang:1.23
, but the latest stable Go version is 1.22.x. This appears to be a non-existent future version.
- FROM --platform=linux/amd64 golang:1.23
+ FROM --platform=linux/amd64 golang:1.22
🌐 Web query:
What is the latest stable version of Go?
💡 Result:
The latest stable version of Go as of April 2025 is Go 1.24.2, released on April 1, 2025[1][2]. This release includes security fixes to the net/http
package as well as various bug fixes to the compiler, runtime, go
command, and several libraries such as crypto/tls
, go/types
, net/http
, and testing
[2].
Citations:
- 1: https://go.dev/dl/
- 2: https://go.dev/doc/devel/release
- 3: https://tip.golang.org/doc/go1.24
- 4: https://github.com/golang/tools/releases
- 5: https://antonz.org/which-go/
- 6: https://tip.golang.org/doc/go1.23
- 7: https://discussion.fedoraproject.org/t/fedora-doesnt-provide-latest-version-of-go/146930
- 8: https://endoflife.date/go
Bump Go base image to latest stable (1.24)
The compile stage currently uses an outdated Go image (golang:1.23
), but the latest stable release as of April 2025 is Go 1.24.2. To include the latest security and bug fixes, please update the Dockerfile:
File: test/antithesis/image/Earthfile
Lines: 10–28
- FROM --platform=linux/amd64 golang:1.23
+ FROM --platform=linux/amd64 golang:1.24
If you prefer explicit patch‑level pinning, you can use:
FROM --platform=linux/amd64 golang:1.24.2
test/antithesis/image/Earthfile
Outdated
build: | ||
FROM --platform=linux/amd64 ubuntu:latest | ||
RUN apt-get update -y && apt-get install -y postgresql-client curl | ||
|
||
COPY (+compile/ledger) /bin/ledger | ||
COPY (+compile/symbols) /symbols | ||
COPY entrypoint.sh /bin/entrypoint.sh | ||
|
||
RUN chmod 777 /bin/entrypoint.sh | ||
|
||
ENTRYPOINT ["/bin/entrypoint.sh"] | ||
EXPOSE 8080 | ||
|
||
ARG --required ANTITHESIS_REPOSITORY | ||
|
||
SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:latest" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider version tagging strategy
The image is currently saved with the tag ledger:latest
. While this works for simple workflows, consider adding a versioning strategy (like using git tags, commits, or timestamps) for better traceability in production environments.
Also verify that the entrypoint script has appropriate error handling for graceful failures.
🏁 Script executed:
#!/bin/bash
# Check entrypoint script for error handling patterns
cat test/antithesis/image/entrypoint.sh | grep -E 'set -e|exit [1-9]||| exit [1-9]'
Length of output: 316
Implement image version tagging and enhance entrypoint error handling
To improve traceability and robustness, please make the following updates:
• In test/antithesis/image/Earthfile
– Replace the hard‑coded ledger:latest
tag with a parameterized/versioned tag (e.g. from a Git tag or commit SHA).
– Example diff:
ARG --required ANTITHESIS_REPOSITORY
- SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:latest"
+ ARG IMAGE_TAG?=$(git describe --tags --always)
+ SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:${IMAGE_TAG}"
• In test/antithesis/image/entrypoint.sh
– Add strict error handling so failures inside the script halt the container startup.
– Example diff at top of the file:
#!/bin/sh
+ set -euo pipefail
+ trap 'echo "⛔ Entrypoint failed on line $LINENO"; exit 1' ERR
# make sure pg is ready to accept connections
until pg_isready -d ledger -h 10.0.29.16 -U ledger; do
echo "Waiting for postgres at: $POSTGRES_URI"
– Ensure any commands (including ledger serve
) propagate non‑zero exit codes.
These changes will give you deterministic image tags and guarantee the container fails fast on errors.
📝 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.
build: | |
FROM --platform=linux/amd64 ubuntu:latest | |
RUN apt-get update -y && apt-get install -y postgresql-client curl | |
COPY (+compile/ledger) /bin/ledger | |
COPY (+compile/symbols) /symbols | |
COPY entrypoint.sh /bin/entrypoint.sh | |
RUN chmod 777 /bin/entrypoint.sh | |
ENTRYPOINT ["/bin/entrypoint.sh"] | |
EXPOSE 8080 | |
ARG --required ANTITHESIS_REPOSITORY | |
SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:latest" | |
# test/antithesis/image/Earthfile | |
build: | |
FROM --platform=linux/amd64 ubuntu:latest | |
RUN apt-get update -y && apt-get install -y postgresql-client curl | |
COPY (+compile/ledger) /bin/ledger | |
COPY (+compile/symbols) /symbols | |
COPY entrypoint.sh /bin/entrypoint.sh | |
RUN chmod 777 /bin/entrypoint.sh | |
ENTRYPOINT ["/bin/entrypoint.sh"] | |
EXPOSE 8080 | |
ARG --required ANTITHESIS_REPOSITORY | |
ARG IMAGE_TAG?=$(git describe --tags --always) | |
SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:${IMAGE_TAG}" |
build: | |
FROM --platform=linux/amd64 ubuntu:latest | |
RUN apt-get update -y && apt-get install -y postgresql-client curl | |
COPY (+compile/ledger) /bin/ledger | |
COPY (+compile/symbols) /symbols | |
COPY entrypoint.sh /bin/entrypoint.sh | |
RUN chmod 777 /bin/entrypoint.sh | |
ENTRYPOINT ["/bin/entrypoint.sh"] | |
EXPOSE 8080 | |
ARG --required ANTITHESIS_REPOSITORY | |
SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:latest" | |
# test/antithesis/image/entrypoint.sh | |
#!/bin/sh | |
set -euo pipefail | |
trap 'echo "⛔ Entrypoint failed on line $LINENO"; exit 1' ERR | |
# make sure pg is ready to accept connections | |
until pg_isready -d ledger -h 10.0.29.16 -U ledger; do | |
echo "Waiting for postgres at: $POSTGRES_URI" | |
done | |
# ... rest of your startup logic (e.g. ledger serve) |
Signed-off-by: Clément Salaün <[email protected]>
Signed-off-by: Clément Salaün <[email protected]>
Signed-off-by: Clément Salaün <[email protected]>
if err := systemStore.CreateLedger(ctx, l); err != nil { | ||
// Handle the case where the ledger already exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know comments are useful, but this kind of comment just rephrase the code ^^
@@ -0,0 +1,8 @@ | |||
VERSION 0.7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stop using Earthfile, there is no Earthfile anymore in the repsoitory ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (7)
test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go (2)
12-28
: The ledger creation appears correct, but consider adding confirmation logging.The code properly creates a ledger with a randomized name, but it would be helpful to add a success log message to confirm when the ledger has been created successfully. This would make troubleshooting easier when reviewing test logs.
if err != nil { assert.Always(err == nil, "ledger should have been created properly", internal.Details{ "error": err, }) return } + // Print confirmation that ledger was created successfully + fmt.Printf("Ledger '%s' created successfully\n", ledger) }
15-16
: Consider checking for overflow when converting to int64.Using the absolute value of a randomly generated big integer and directly converting to int64 could potentially lead to overflow issues if the value exceeds the maximum int64 value.
- id := big.NewInt(0).Abs(internal.RandomBigInt()).Int64() + // Ensure the ID fits within int64 bounds + bigInt := big.NewInt(0).Abs(internal.RandomBigInt()) + // Use Mod to ensure it's within int64 range + maxInt64 := big.NewInt(math.MaxInt64) + id := big.NewInt(0).Mod(bigInt, maxInt64).Int64() ledger := fmt.Sprintf("ledger-%d", id)test/antithesis/workload/bin/cmds/first_default_ledger/main.go (1)
10-25
: Consider adding confirmation logging.The code properly creates the default ledger, but lacks any success message that would be helpful for logging and debugging purposes.
if err != nil { assert.Always(err == nil, "ledger should have been created properly", internal.Details{ "error": err, }) return } + fmt.Println("Default ledger created successfully") }
Don't forget to add the fmt import if you implement this change.
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (1)
14-24
: Add error handling for the edge case of no ledgers.The program should handle the case where no ledgers are returned, which is possible especially during initial setup.
ledgers, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) if err != nil { assert.Always(err == nil, "error listing ledgers", internal.Details{ "error": err, }) return } + // Handle the case of no ledgers found + if len(ledgers.V2LedgerListResponse.Cursor.Data) == 0 { + fmt.Println("No ledgers found to check volumes") + return + }test/antithesis/workload/internal/utils.go (3)
22-27
: Add more context and validation to RandomBigInt function.The function relies on an external random number generator without validation or documentation about what it returns. Consider adding more context to make the function more robust.
func RandomBigInt() *big.Int { + // random.GetRandom() returns a 64-bit random integer v := random.GetRandom() ret := big.NewInt(0) ret.SetString(fmt.Sprintf("%d", v), 10) + // Ensure the returned value is non-negative as a safeguard + if ret.Sign() < 0 { + ret.Neg(ret) + } return ret }
81-96
: Seed the random generator for better randomization.The
rand.Intn()
function is used without seeding the random generator, which can lead to predictable sequences if called in quick succession. Consider seeding the random generator for better randomization.func GetRandomLedger(ctx context.Context, client *client.Formance) (string, error) { ledgers, err := ListLedgers(ctx, client) if err != nil { return "", err } if len(ledgers) == 0 { return "", fmt.Errorf("no ledgers found") } // Get a random index within the ledgers slice + // Seed the random generator with current time to ensure randomness + rand.Seed(time.Now().UnixNano()) randomIndex := rand.Intn(len(ledgers)) // Return the ledger at the random index return ledgers[randomIndex], nil }Note: If you're using Go 1.20+, you should use the newer
rand.New(rand.NewSource(time.Now().UnixNano()))
approach instead, asrand.Seed
is deprecated.
98-114
: Hardcoded asset type in RunTx function.The function hardcodes "USD/2" as the asset, which may not be flexible enough for all test scenarios. Consider making the asset type configurable or adding documentation explaining why this specific asset is used.
-func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { +// RunTx creates a transaction on the specified ledger with the given amount of the default asset (USD/2) +// If you need to use a different asset, use the RunTxWithAsset function instead +func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { + return RunTxWithAsset(ctx, client, amount, "USD/2", ledger) +} + +// RunTxWithAsset creates a transaction on the specified ledger with the given amount and asset +func RunTxWithAsset(ctx context.Context, client *client.Formance, amount *big.Int, asset string, ledger string) error { orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ V2PostTransaction: components.V2PostTransaction{ Postings: []components.V2Posting{{ Amount: amount, - Asset: "USD/2", + Asset: asset, Destination: dest, Source: "world", }}, }, Ledger: ledger, }) return err }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
test/antithesis/workload/go.mod
is excluded by!**/*.mod
test/antithesis/workload/go.sum
is excluded by!**/*.sum
,!**/*.sum
📒 Files selected for processing (6)
test/antithesis/workload/bin/cmds/first_default_ledger/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go
(1 hunks)test/antithesis/workload/internal/utils.go
(1 hunks)tools/generator/cmd/root.go
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- tools/generator/cmd/root.go
🚧 Files skipped from review as they are similar to previous changes (1)
- test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
🧰 Additional context used
🧬 Code Graph Analysis (3)
test/antithesis/workload/bin/cmds/first_default_ledger/main.go (1)
test/antithesis/workload/internal/utils.go (3)
NewClient
(41-57)CreateLedger
(59-65)Details
(20-20)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (4)
test/antithesis/workload/internal/utils.go (2)
NewClient
(41-57)ListLedgers
(67-79)pkg/client/models/operations/v2listledgers.go (1)
V2ListLedgersRequest
(9-20)pkg/client/models/operations/v2getbalancesaggregated.go (1)
V2GetBalancesAggregatedRequest
(11-18)pkg/client/models/components/v2aggregatebalancesresponse.go (1)
V2AggregateBalancesResponse
(10-12)
test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go (1)
test/antithesis/workload/internal/utils.go (4)
NewClient
(41-57)RandomBigInt
(22-27)CreateLedger
(59-65)Details
(20-20)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Tests
- GitHub Check: Dirty
- GitHub Check: Push Images to Antithesis
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { | ||
assert.Always( | ||
volumes.Cmp(new(big.Int)) == 0, | ||
fmt.Sprintf("aggregated volumes for asset %s should be 0", | ||
asset, | ||
), internal.Details{ | ||
"error": err, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect error variable in assertion details.
The err
variable in the assertion details is from the GetBalancesAggregated call, which would be nil at this point. The details should contain relevant information about the volumes instead.
for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data {
assert.Always(
volumes.Cmp(new(big.Int)) == 0,
fmt.Sprintf("aggregated volumes for asset %s should be 0",
asset,
), internal.Details{
- "error": err,
+ "asset": asset,
+ "volume": volumes.String(),
})
}
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go around lines 42 to 50, the assertion details incorrectly include the variable 'err', which is nil here. Replace 'err' with relevant information about the 'volumes' variable to provide meaningful context in the assertion failure details.
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go (2)
20-30
: Error handling could be more descriptive.The error handling is functional but could benefit from a more specific error message that includes the ledger name.
if err != nil { - assert.Always(err == nil, "ledger should have been created properly", internal.Details{ + assert.Always(err == nil, fmt.Sprintf("Failed to create ledger %s", ledger), internal.Details{ "error": err, + "ledger": ledger, }) return }
32-33
: Consider adding more detailed logging.The completion message could include the ledger name to make logs more traceable in a parallel environment.
- log.Println("composer: parallel_driver_ledger_create: done") + log.Printf("composer: parallel_driver_ledger_create: done (created ledger: %s)", ledger)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
test/antithesis/Earthfile
(1 hunks)test/antithesis/workload/Earthfile
(1 hunks)test/antithesis/workload/bin/cmds/first_default_ledger/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
- test/antithesis/workload/bin/cmds/first_default_ledger/main.go
- test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go
- test/antithesis/Earthfile
- test/antithesis/workload/Earthfile
🧰 Additional context used
🧬 Code Graph Analysis (1)
test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go (1)
test/antithesis/workload/internal/utils.go (4)
NewClient
(41-57)RandomBigInt
(22-27)CreateLedger
(59-65)Details
(20-20)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Dirty
- GitHub Check: Tests
- GitHub Check: Push Images to Antithesis
🔇 Additional comments (3)
test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go (3)
1-12
: Good package structure and imports.The package structure and imports are well-organized. The code correctly imports the necessary libraries for context, formatting, logging, and big integer operations, as well as the Antithesis assertion library and internal utilities.
13-19
: Solid initialization with unique ledger naming.The initialization logic is sound:
- Properly sets up a background context
- Initializes a client using the internal utility
- Generates a unique ledger name using a random positive ID
Good use of the
Abs()
method to ensure the randomly generated ID is positive before formatting it into a ledger name.
1-34
:❓ Verification inconclusive
Add cleanup or documentation for created resources.
The program creates a ledger but doesn't have a mechanism to clean it up. While this might be handled elsewhere, it would be beneficial to either:
- Add a cleanup step, or
- Add documentation explaining why cleanup isn't needed or how it's handled
This helps prevent resource leakage in testing environments.
🏁 Script executed:
#!/bin/bash # Check if there are any existing cleanup mechanisms for ledgers in the codebase echo "Searching for ledger cleanup mechanisms..." rg -i "delete\s+ledger|cleanup\s+ledger|remove\s+ledger" --type goLength of output: 313
Add cleanup or document resource handling
I searched the repo for ledger‐cleanup routines and found only:
- internal/storage/system/migrations.go (“Remove ledger state column”)
- pkg/client/v2.go (
DeleteLedgerMetadata
) – only deletes metadata, not the ledger itselfThere’s currently no API call in this test CLI to delete the created ledger. To avoid resource leakage in your test environment, please either:
- Invoke or implement a proper
DeleteLedger
(or similar) helper after creation, or- Add documentation explaining why ledger cleanup isn’t needed here (e.g. handled by a global teardown or another process)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (1)
53-61
: Fix incorrect error variable in assertion details.The
err
variable in the assertion details is from the GetBalancesAggregated call, which would be nil at this point. The details should contain relevant information about the volumes instead.for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { assert.Always( volumes.Cmp(new(big.Int)) == 0, fmt.Sprintf("aggregated volumes for asset %s should be 0", asset, ), internal.Details{ - "error": err, + "asset": asset, + "volume": volumes.String(), }) }
🧹 Nitpick comments (2)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (2)
39-51
: Logging improvement suggestion.Consider adding more detailed logging before making the API call to help with debugging and monitoring the workflow.
func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { + log.Printf("composer: parallel_driver_volumes: checking volumes for ledger %s", ledger) aggregated, err := client.Ledger.V2.GetBalancesAggregated(ctx, operations.V2GetBalancesAggregatedRequest{ Ledger: ledger, })
17-22
: Consider adding a timeout to the context.For better resource management, consider using a context with timeout to prevent indefinite hanging if an operation gets stuck.
func main() { log.Println("composer: parallel_driver_volumes") - ctx := context.Background() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() client := internal.NewClient()Don't forget to add the time import:
import ( "context" "fmt" "log" "math/big" "os" "sync" + "time"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (4)
test/antithesis/workload/internal/utils.go (3)
NewClient
(41-57)ListLedgers
(67-79)Details
(20-20)pkg/client/models/operations/v2listledgers.go (1)
V2ListLedgersRequest
(9-20)pkg/client/models/operations/v2getbalancesaggregated.go (1)
V2GetBalancesAggregatedRequest
(11-18)pkg/client/models/components/v2aggregatebalancesresponse.go (1)
V2AggregateBalancesResponse
(10-12)
🔇 Additional comments (1)
test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go (1)
17-37
: LGTM: Good concurrency implementation with WaitGroup.The main function correctly implements the WaitGroup pattern for concurrency, ensuring all goroutines complete before the program exits. This addresses the synchronization issue that was mentioned in past reviews.
Signed-off-by: Clément Salaün <[email protected]>
Signed-off-by: Clément Salaün <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
test/antithesis/workload/bin/cmds/eventually_correct/main.go (1)
45-57
:⚠️ Potential issueFix error handling to avoid terminating all goroutines.
Using
log.Fatalf
in a goroutine will terminate the entire program, not just the current goroutine. This means if one ledger check fails, the others won't be completed.if err != nil { if internal.IsServerError(aggregated.GetHTTPMeta()) { assert.Always( false, fmt.Sprintf("error getting aggregated balances for ledger %s: %s", ledger, err), internal.Details{ "error": err, }, ) } else { - log.Fatalf("error getting aggregated balances for ledger %s: %s", ledger, err) + log.Printf("error getting aggregated balances for ledger %s: %s", ledger, err) + return } }
🧹 Nitpick comments (2)
test/antithesis/workload/bin/cmds/eventually_correct/main.go (2)
18-39
: Consider limiting concurrency for large numbers of ledgers.The current implementation creates a goroutine for each ledger, which could potentially launch too many concurrent HTTP requests if there are many ledgers. Consider implementing a worker pool pattern to limit concurrency.
Here's a potential implementation using a worker pool:
func main() { log.Println("composer: eventually_correct") ctx := context.Background() client := internal.NewClient() ledgers, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) if err != nil { log.Printf("error listing ledgers: %s", err) os.Exit(1) } + // Limit concurrency to a reasonable number + maxConcurrency := 10 + semaphore := make(chan struct{}, maxConcurrency) wg := sync.WaitGroup{} for _, ledger := range ledgers.V2LedgerListResponse.Cursor.Data { wg.Add(1) + // Acquire a slot from the semaphore + semaphore <- struct{}{} go func(ledger string) { defer wg.Done() + defer func() { + // Release the slot back to the semaphore + <-semaphore + }() checkVolumes(ctx, client, ledger) }(ledger.Name) } wg.Wait() }
41-42
: Add function documentation.Add documentation comments to describe the purpose of the function and its parameters to improve code maintainability.
+// checkVolumes fetches aggregated balances for the specified ledger and asserts +// that all asset volumes are zero. It uses Antithesis assert.Always to record +// any violations while allowing the program to continue checking other assets. func checkVolumes(ctx context.Context, client *client.Formance, ledger string) {
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
internal/storage/driver/driver.go
(4 hunks)test/antithesis/workload/bin/cmds/eventually_correct/main.go
(1 hunks)test/antithesis/workload/internal/utils.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- test/antithesis/workload/internal/utils.go
- internal/storage/driver/driver.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
test/antithesis/workload/bin/cmds/eventually_correct/main.go (6)
test/antithesis/workload/internal/utils.go (3)
NewClient
(41-57)ListLedgers
(74-86)IsServerError
(59-61)pkg/client/v2.go (1)
V2
(19-21)pkg/client/models/operations/v2listledgers.go (1)
V2ListLedgersRequest
(9-20)pkg/client/formance.go (1)
Formance
(70-74)pkg/client/models/operations/v2getbalancesaggregated.go (1)
V2GetBalancesAggregatedRequest
(11-18)pkg/client/models/components/v2aggregatebalancesresponse.go (1)
V2AggregateBalancesResponse
(10-12)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Dirty
func IsServerError(httpMeta components.HTTPMetadata) bool { | ||
return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove duplicate IsServerError function.
This function duplicates the functionality already available in internal.IsServerError
which is correctly used at line 46. Remove this duplicate implementation to avoid potential inconsistencies.
-func IsServerError(httpMeta components.HTTPMetadata) bool {
- return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600
-}
📝 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.
func IsServerError(httpMeta components.HTTPMetadata) bool { | |
return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600 | |
} |
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/eventually_correct/main.go around lines 72 to 74, there is a duplicate implementation of the IsServerError function which duplicates the existing internal.IsServerError function used at line 46. Remove this duplicate IsServerError function entirely to avoid inconsistencies and rely on the internal.IsServerError function instead.
"error": err, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect error variable in assert details.
The err
variable may be nil at this point since this code executes after the error check. Include the actual volume value instead to provide more meaningful assertion details.
assert.Always(
volumes.Cmp(new(big.Int)) == 0,
fmt.Sprintf("aggregated volumes for asset %s should be 0",
asset,
), internal.Details{
- "error": err,
+ "actual_volume": volumes.String(),
+ "asset": asset,
})
📝 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.
"error": err, | |
}) | |
assert.Always( | |
volumes.Cmp(new(big.Int)) == 0, | |
fmt.Sprintf("aggregated volumes for asset %s should be 0", | |
asset, | |
), internal.Details{ | |
"actual_volume": volumes.String(), | |
"asset": asset, | |
}) |
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/eventually_correct/main.go at lines 65-66, the assertion details incorrectly include the variable 'err', which may be nil since this code runs after the error check. Replace 'err' with the actual volume value in the assertion details to provide more meaningful and accurate information.
Signed-off-by: Clément Salaün <[email protected]>
Signed-off-by: Clément Salaün <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (5)
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go (1)
5-8
: Consider enhancing the placeholder with more context about the planned functionality.This is currently just a placeholder implementation, which is fine for initial setup. However, consider adding more detailed comments about the intended functionality of this command, particularly around how it will handle version upgrades within the Antithesis testing framework.
According to the PR context, this appears to be part of a suite of workload orchestration tools. It would be helpful to document:
- The purpose of this specific command
- How it will interact with other components
- Expected inputs/outputs when fully implemented
func main() { - // TODO: implement + // TODO: implement version upgrade functionality + // This command will handle dynamic version upgrades during Antithesis testing. + // It should: + // - Coordinate with the test orchestrator + // - Manage the upgrade process for specific components + // - Validate system stability after upgrades log.Println("placeholder command for anytime_version_upgrade") }test/antithesis/workload/datagen/main.go (2)
1-7
: Good starting point for the package, but consider improving imports.The imports look good, but note that
math/rand
is deprecated in favor ofmath/rand/v2
in Go 1.23+. Consider using the newer version for improved randomness and future compatibility.import ( "fmt" - "math/rand" + "math/rand/v2" )
15-17
: Add documentation to explain the program's purpose.The main function works correctly but lacks documentation explaining the program's purpose within the testing framework.
+// main generates a random account number and prints it to stdout +// This is used for data generation in Antithesis testing workloads func main() { fmt.Println(Account()) }test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go (2)
72-83
: Transaction function always uses the same fixed values.The
Transaction()
function always returns a posting with the same fixed values, which may not thoroughly test the system under different scenarios.func Transaction() []components.V2Posting { postings := []components.V2Posting{} postings = append(postings, components.V2Posting{ - Amount: big.NewInt(100), + Amount: internal.RandomBigInt(), // Use random amounts for better coverage Asset: "USD/2", - Destination: "orders:1234", + Destination: fmt.Sprintf("orders:%d", rand.Intn(10000)), // Randomize order IDs Source: "world", }) return postings }
85-93
: Unused function in the main flow.The
Sequence()
function is defined but never used in the program. Consider either removing it or documenting why it's defined for future use.-func Sequence() []Postings { - postings := []Postings{} - - for i := 0; i < 10; i++ { - postings = append(postings, Transaction()) - } - - return postings -}If you need to keep this function for future use, add appropriate documentation:
+// Sequence returns a sequence of 10 transactions +// Note: Currently not used in the main flow but kept for future expansion func Sequence() []Postings { postings := []Postings{} for i := 0; i < 10; i++ { postings = append(postings, Transaction()) } return postings }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
test/antithesis/workload/datagen/example.json
is excluded by!**/*.json
📒 Files selected for processing (6)
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go
(1 hunks)test/antithesis/workload/bin/cmds/first_default_ledger/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go
(1 hunks)test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go
(1 hunks)test/antithesis/workload/datagen/main.go
(1 hunks)test/antithesis/workload/internal/utils.go
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- test/antithesis/workload/bin/cmds/first_default_ledger/main.go
- test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go
- test/antithesis/workload/internal/utils.go
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Dirty
- GitHub Check: Tests
- GitHub Check: Push Images to Antithesis
🔇 Additional comments (2)
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go (1)
1-4
: LGTM: Package declaration and imports look good.The package declaration and import statement follow Go conventions. Using the standard library's "log" package is appropriate for basic logging functionality.
test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go (1)
3-14
: LGTM: Well-organized imports with clear separation.The import organization is good, with standard library packages first, followed by third-party packages.
type Sequence struct { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove or properly implement the unused struct.
The Sequence
struct is defined but never used in this file. Either remove it or document its purpose and implement its intended functionality.
-type Sequence struct {
-}
📝 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.
type Sequence struct { | |
} |
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/datagen/main.go at lines 8 to 9, the Sequence struct
is defined but not used or implemented. Either remove the Sequence struct
entirely if it is unnecessary, or provide a proper implementation and
documentation explaining its purpose and how it fits into the codebase.
func Account() string { | ||
return fmt.Sprintf("%d", rand.Intn(10e9)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Account generation is not seeded, which will produce predictable results.
The random number generator is not seeded, which means it will produce the same sequence of "random" numbers on each program run. This could lead to predictable account numbers, which may be problematic for testing.
+func init() {
+ // Seed the random number generator to ensure different account numbers on each run
+ rand.Seed(time.Now().UnixNano())
+}
func Account() string {
return fmt.Sprintf("%d", rand.Intn(10e9))
}
You'll also need to add "time"
to your imports.
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/datagen/main.go around lines 11 to 13, the Account
function uses rand.Intn without seeding the random number generator, causing
predictable outputs. To fix this, seed the random number generator once at
program startup using rand.Seed with the current time in nanoseconds from
time.Now().UnixNano(). Also, add "time" to the import statements to enable this.
This ensures Account generates different values on each run.
res, err := RunTx(ctx, client, Transaction(), ledger) | ||
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ | ||
"ledger": ledger, | ||
}) | ||
assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{ | ||
"ledger": ledger, | ||
"error": err, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve error handling in transaction assertions.
The code uses assertions but doesn't properly handle the case where res
could be nil if err
is not nil.
res, err := RunTx(ctx, client, Transaction(), ledger)
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{
"ledger": ledger,
})
- assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{
+ assert.Always(err == nil || !internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{
"ledger": ledger,
"error": err,
})
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go around
lines 38 to 45, the code asserts conditions on res without checking if res is
nil when err is not nil, which can cause a nil pointer dereference. Add a check
to ensure res is not nil before calling res.GetHTTPMeta(), and handle the case
where err is not nil by skipping or adjusting the assertions accordingly to
avoid runtime panics.
totalAmount := big.NewInt(0) | ||
|
||
pool := pond.New(10, 10e3) | ||
|
||
for i := 0; i < count; i++ { | ||
amount := internal.RandomBigInt() | ||
totalAmount = totalAmount.Add(totalAmount, amount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Unused variable tracking.
The totalAmount
variable is incremented with random values that are never used in transactions. The amount
generated in each loop iteration is also never used for the transaction since Transaction()
uses a fixed amount of 100.
- totalAmount := big.NewInt(0)
-
pool := pond.New(10, 10e3)
for i := 0; i < count; i++ {
- amount := internal.RandomBigInt()
- totalAmount = totalAmount.Add(totalAmount, amount)
pool.Submit(func() {
📝 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.
totalAmount := big.NewInt(0) | |
pool := pond.New(10, 10e3) | |
for i := 0; i < count; i++ { | |
amount := internal.RandomBigInt() | |
totalAmount = totalAmount.Add(totalAmount, amount) | |
pool := pond.New(10, 10e3) | |
for i := 0; i < count; i++ { | |
pool.Submit(func() { | |
// ... | |
}) | |
} |
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go around
lines 30 to 36, the variable totalAmount is updated with random amounts that are
never used, and the generated amount is not passed to the Transaction function
which uses a fixed value of 100. To fix this, remove the totalAmount variable
and the addition logic since it is unused, and modify the Transaction calls to
use the generated amount instead of the fixed 100 value so that the random
amounts are actually used in the transactions.
pool.Submit(func() { | ||
res, err := RunTx(ctx, client, Transaction(), ledger) | ||
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ | ||
"ledger": ledger, | ||
}) | ||
assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{ | ||
"ledger": ledger, | ||
"error": err, | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential race condition in anonymous function.
The anonymous function is accessing variables from the outer scope (ctx
, client
, ledger
), which could lead to race conditions, especially if these variables change during execution.
pool.Submit(func() {
- res, err := RunTx(ctx, client, Transaction(), ledger)
+ // Capture values to prevent race conditions
+ localCtx := ctx
+ localClient := client
+ localLedger := ledger
+ res, err := RunTx(localCtx, localClient, Transaction(), localLedger)
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{
- "ledger": ledger,
+ "ledger": localLedger,
})
assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{
- "ledger": ledger,
+ "ledger": localLedger,
"error": err,
})
})
📝 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.
pool.Submit(func() { | |
res, err := RunTx(ctx, client, Transaction(), ledger) | |
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ | |
"ledger": ledger, | |
}) | |
assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{ | |
"ledger": ledger, | |
"error": err, | |
}) | |
}) | |
pool.Submit(func() { | |
// Capture values to prevent race conditions | |
localCtx := ctx | |
localClient := client | |
localLedger := ledger | |
res, err := RunTx(localCtx, localClient, Transaction(), localLedger) | |
assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ | |
"ledger": localLedger, | |
}) | |
assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{ | |
"ledger": localLedger, | |
"error": err, | |
}) | |
}) |
🤖 Prompt for AI Agents (early access)
In test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go around
lines 37 to 46, the anonymous function passed to pool.Submit captures outer
variables ctx, client, and ledger directly, which may cause race conditions if
these variables change concurrently. To fix this, pass these variables as
parameters to the anonymous function or create local copies inside the loop
before submitting the function, ensuring each goroutine uses its own independent
copy of the variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
internal/storage/driver/driver.go (2)
58-60
: Trim comments that restate the code.Several inline comments repeat what the code already expresses (prior reviewer noted this too). Consider removing or tightening to keep the function compact.
Also applies to: 63-63, 108-108, 114-114, 119-119
85-95
: Hard-coded assertion always flags “unreachable”; parameterize and fix typo.This reproduces a prior concern: using
false
guarantees the Unreachable path when a bucket is outdated, which isn’t aligned with the TODO. Make it configurable and correct the “wether” typo. Also add coverage for both expected/unexpected cases.- assert.AlwaysOrUnreachable( - // @todo: replace this with a proper flag detailing wether we're + assert.AlwaysOrUnreachable( + // @todo: replace this with a proper flag detailing whether we're // operating a new version of the binary or not. // if we are, we are definitely expecting this to happen. // if we're not, this should be unreachable. - false, + d.expectOutdatedBuckets, "Bucket is outdated", map[string]any{ "bucket": l.Bucket, }, )Support code outside this hunk (example):
// in type Driver expectOutdatedBuckets bool // option func WithExpectOutdatedBuckets(v bool) Option { return func(d *Driver) { d.expectOutdatedBuckets = v } }Would you like me to add a focused test that stubs Bucket.IsUpToDate to false and asserts the returned error and the assertion path under both flag values?
🧹 Nitpick comments (2)
internal/storage/driver/driver.go (2)
10-10
: Decouple Antithesis SDK from production builds.Importing
github.com/antithesishq/antithesis-sdk-go/assert
directly couples all builds to the SDK. Consider a thin internal wrapper with build tags to no-op outside Antithesis runs.Example:
// internal/assertx/assert_antithesis.go //go:build antithesis package assertx import "github.com/antithesishq/antithesis-sdk-go/assert" func AlwaysOrUnreachable(cond bool, msg string, kv map[string]any) { assert.AlwaysOrUnreachable(cond, msg, kv) } // internal/assertx/assert_stub.go //go:build !antithesis package assertx func AlwaysOrUnreachable(bool, string, map[string]any) {}Then replace calls to
assert.AlwaysOrUnreachable
withassertx.AlwaysOrUnreachable
.
63-70
: Avoid resolving the same error twice.Resolve once and branch on that value. This also makes the intent crisper.
- if err := systemStore.CreateLedger(ctx, l); err != nil { - // Handle the case where the ledger already exists - if errors.Is(postgres.ResolveError(err), postgres.ErrConstraintsFailed{}) { - return systemstore.ErrLedgerAlreadyExists - } - return postgres.ResolveError(err) - } + if err := systemStore.CreateLedger(ctx, l); err != nil { + rerr := postgres.ResolveError(err) + if errors.Is(rerr, postgres.ErrConstraintsFailed{}) { + return systemstore.ErrLedgerAlreadyExists + } + return rerr + }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (3)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
go.mod
is excluded by!**/*.mod
go.sum
is excluded by!**/*.sum
,!**/*.sum
📒 Files selected for processing (1)
internal/storage/driver/driver.go
(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/storage/driver/driver.go (3)
internal/ledger.go (1)
Ledger
(18-26)internal/storage/system/store.go (1)
Store
(20-31)internal/storage/bucket/bucket.go (1)
Bucket
(13-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Tests
- GitHub Check: Dirty
- GitHub Check: Push Images to Antithesis
🔇 Additional comments (1)
internal/storage/driver/driver.go (1)
41-55
: Good, clear GoDoc for CreateLedger.Accurately documents the transactional flow and failure semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
♻️ Duplicate comments (1)
test/antithesis/workload/Earthfile (1)
19-19
: Pin instrumentor version for reproducible builds.Using @latest risks non-determinism and breakage. Pin a known-good version.
-RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest +RUN go install github.com/antithesishq/antithesis-sdk-go/tools/[email protected]
🧹 Nitpick comments (10)
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go (3)
58-65
: Consider surfacing richer context on failure and success.
- Include namespace/name/version in error logs.
- Optionally log the observed Generation/ResourceVersion on success.
No diff required; informational.
67-67
: Nit: Replace placeholder log with actionable message.E.g., “upgraded Ledger stack0-ledger to version $tag in namespace formance-systems”.
58-58
: Parameterize name/namespace.Hardcoding “stack0-ledger” and “formance-systems” makes reuse harder; read from env vars with sane defaults.
test/antithesis/workload/Earthfile (2)
42-42
: Reduce image size and CVE surface after apt-get.Clean apt lists in the same layer.
-RUN apt-get update && apt-get install -y curl +RUN apt-get update && apt-get install -y curl \ + && rm -rf /var/lib/apt/lists/*
31-33
: Make the loop robust to spaces and non-files.If any file names contain spaces or if bin/cmds has non-entries, the ls-based expansion can misbehave. Prefer Earthly’s globbing:
-FOR file IN $(ls bin/cmds) - RUN go build -o /out/cmds/$file ./bin/cmds/$file +FOR file IN bin/cmds/* + RUN go build -o /out/cmds/$(basename ${file}) ./bin/cmds/$(basename ${file}) ENDtest/antithesis/config/Justfile (1)
17-19
: Guard env and use strict mode in push.push: build-manifest - docker build -f Dockerfile.config -t $ANTITHESIS_REPOSITORY/antithesis-config:k8s_test . - docker push $ANTITHESIS_REPOSITORY/antithesis-config:k8s_test + set -euo pipefail + : "${ANTITHESIS_REPOSITORY:?ANTITHESIS_REPOSITORY is required}" + docker build --pull -f Dockerfile.config -t "$ANTITHESIS_REPOSITORY/antithesis-config:k8s_test" . + docker push "$ANTITHESIS_REPOSITORY/antithesis-config:k8s_test"test/antithesis/Justfile (4)
5-11
: Safer JSON construction (optional).If
$ANTITHESIS_SLACK_REPORT_RECIPIENT
can contain quotes or special chars, prefer generating the payload with a JSON tool to avoid malformed JSON.Example without changing external deps (uses Python, commonly available):
payload="$(python3 - <<'PY' import json, os print(json.dumps({ "params": { "custom.duration": "0.1", "antithesis.report.recipients": os.environ["ANTITHESIS_SLACK_REPORT_RECIPIENT"], "antithesis.config_image": "antithesis-config:k8s_test", "antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" } })) PY )" curl ... --data "$payload"
9-9
: Pin images for reproducibility; avoid latest/test tags in CI-triggered experiments.
workload:latest
andantithesis-config:k8s_test
are mutable; runs won’t be reproducible.Consider parameterizing and/or digest-pinning, e.g.:
- "antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ + "antithesis.images": "workload:${LEDGER_LATEST_TAG};docker.io/library/postgres:15-alpine@${POSTGRES_DIGEST};ghcr.io/formancehq/operator:v2.10.1@${OPERATOR_DIGEST};ghcr.io/formancehq/operator-utils:v2.0.14@${OPERATOR_UTILS_DIGEST};ghcr.io/formancehq/gateway:v2.0.24@${GATEWAY_DIGEST};ghcr.io/formancehq/ledger-instrumented:k8s_test@${LEDGER_INSTRUMENTED_DIGEST}" \If digests aren’t practical, at least replace
latest
/k8s_test
with immutable versioned tags produced by your pipeline.Also applies to: 21-21
1-11
: DRY the two nearly-identical recipes.Reduce duplication and the chance of drift by introducing a parameterized recipe.
Example:
run duration: # shared preconditions/auth here... # build payload using $duration # curl ... run-6min: requirements-build just run 0.1 run-1h: requirements-build just run 1Also applies to: 13-23
25-28
: Add env prechecks to avoid surprising no-op pushes.Fail fast if required vars are missing before building/pushing.
requirements-build: - just config/push + : "${ANTITHESIS_REPOSITORY:?ANTITHESIS_REPOSITORY is required}" + : "${LEDGER_LATEST_TAG:?LEDGER_LATEST_TAG is required}" + just config/push # earthly --push ./image+build --ANTITHESIS_REPOSITORY="$ANTITHESIS_REPOSITORY" earthly --push ./workload+build --ANTITHESIS_REPOSITORY="$ANTITHESIS_REPOSITORY" --LEDGER_LATEST_TAG="$LEDGER_LATEST_TAG"Also verify your environment supports
just
subdirectory invocation (just config/push
). If not, usejust --justfile ./config/Justfile push
.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (5)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
test/antithesis/config/manifests/ledger.yaml
is excluded by!**/*.yaml
test/antithesis/config/manifests/stack.yaml
is excluded by!**/*.yaml
test/antithesis/workload/go.mod
is excluded by!**/*.mod
test/antithesis/workload/go.sum
is excluded by!**/*.sum
,!**/*.sum
📒 Files selected for processing (4)
test/antithesis/Justfile
(1 hunks)test/antithesis/config/Justfile
(1 hunks)test/antithesis/workload/Earthfile
(1 hunks)test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go (2)
cmd/root.go (1)
Version
(23-23)test/antithesis/workload/internal/utils.go (1)
Details
(20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Dirty
- GitHub Check: Tests
🔇 Additional comments (1)
test/antithesis/config/Justfile (1)
8-9
: Double-check CRD availability vs. Ledger CR usage.If operator CRDs aren’t applied via regions chart, the Ledger manifest may fail. Ensure regions chart version includes the Ledger CRD matching manifests/ledger.yaml.
If uncertain, keep the operator-crds line enabled for safety.
Also applies to: 13-13
build-manifest: | ||
rm -f -- tmp/resources.yaml | ||
mkdir -p tmp | ||
cat manifests/namespace.yaml >> tmp/resources.yaml | ||
echo "---" >> tmp/resources.yaml | ||
cat manifests/postgres.yaml >> tmp/resources.yaml | ||
echo "---" >> tmp/resources.yaml | ||
helm template regions oci://ghcr.io/formancehq/helm/regions --version 2.15.2 --namespace formance-systems >> tmp/resources.yaml | ||
# helm template operator oci://ghcr.io/formancehq/helm/operator-crds --version v2.8.0 --namespace formance-systems >> tmp/resources.yaml | ||
echo "---" >> tmp/resources.yaml | ||
cat manifests/stack.yaml >> tmp/resources.yaml | ||
echo "---" >> tmp/resources.yaml | ||
yq '.spec.version = strenv(LEDGER_PREVIOUS_TAG)' manifests/ledger.yaml >> tmp/resources.yaml | ||
echo "---" >> tmp/resources.yaml | ||
cat manifests/workload.yaml >> tmp/resources.yaml | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Harden recipes: fail fast and guard required env.
Add strict shell flags and verify LEDGER_PREVIOUS_TAG is set before templating.
build-manifest:
- rm -f -- tmp/resources.yaml
+ set -euo pipefail
+ : "${LEDGER_PREVIOUS_TAG:?LEDGER_PREVIOUS_TAG is required}"
+ rm -f -- tmp/resources.yaml
mkdir -p tmp
cat manifests/namespace.yaml >> tmp/resources.yaml
echo "---" >> tmp/resources.yaml
cat manifests/postgres.yaml >> tmp/resources.yaml
echo "---" >> tmp/resources.yaml
helm template regions oci://ghcr.io/formancehq/helm/regions --version 2.15.2 --namespace formance-systems >> tmp/resources.yaml
# helm template operator oci://ghcr.io/formancehq/helm/operator-crds --version v2.8.0 --namespace formance-systems >> tmp/resources.yaml
echo "---" >> tmp/resources.yaml
cat manifests/stack.yaml >> tmp/resources.yaml
echo "---" >> tmp/resources.yaml
yq '.spec.version = strenv(LEDGER_PREVIOUS_TAG)' manifests/ledger.yaml >> tmp/resources.yaml
echo "---" >> tmp/resources.yaml
cat manifests/workload.yaml >> tmp/resources.yaml
📝 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.
build-manifest: | |
rm -f -- tmp/resources.yaml | |
mkdir -p tmp | |
cat manifests/namespace.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/postgres.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
helm template regions oci://ghcr.io/formancehq/helm/regions --version 2.15.2 --namespace formance-systems >> tmp/resources.yaml | |
# helm template operator oci://ghcr.io/formancehq/helm/operator-crds --version v2.8.0 --namespace formance-systems >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/stack.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
yq '.spec.version = strenv(LEDGER_PREVIOUS_TAG)' manifests/ledger.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/workload.yaml >> tmp/resources.yaml | |
build-manifest: | |
set -euo pipefail | |
: "${LEDGER_PREVIOUS_TAG:?LEDGER_PREVIOUS_TAG is required}" | |
rm -f -- tmp/resources.yaml | |
mkdir -p tmp | |
cat manifests/namespace.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/postgres.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
helm template regions oci://ghcr.io/formancehq/helm/regions --version 2.15.2 --namespace formance-systems >> tmp/resources.yaml | |
# helm template operator oci://ghcr.io/formancehq/helm/operator-crds --version v2.8.0 --namespace formance-systems >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/stack.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
yq '.spec.version = strenv(LEDGER_PREVIOUS_TAG)' manifests/ledger.yaml >> tmp/resources.yaml | |
echo "---" >> tmp/resources.yaml | |
cat manifests/workload.yaml >> tmp/resources.yaml |
🤖 Prompt for AI Agents
In test/antithesis/config/Justfile around lines 1 to 16, the build-manifest
recipe runs multiple shell commands without strict failure handling or checking
required environment variables; update the recipe to enable strict shell flags
(set -euo pipefail) at the start of the recipe’s shell invocation and add an
explicit guard that verifies LEDGER_PREVIOUS_TAG is set (exit with a clear error
if not) before running the yq templating step so the recipe fails fast and does
not proceed with an unset variable.
curl --fail \ | ||
--user "formance:$ANTITHESIS_PASSWORD" \ | ||
-X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \ | ||
"params": { \ | ||
"custom.duration": "0.1", \ | ||
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | ||
"antithesis.config_image": "antithesis-config:k8s_test", \ | ||
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | ||
} \ | ||
}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Stop leaking credentials; switch to netrc, add JSON header, and harden curl.
Passing $ANTITHESIS_PASSWORD
via --user
exposes it in process listings. Also, set the proper JSON content-type and add basic resiliency.
Apply this diff:
- curl --fail \
- --user "formance:$ANTITHESIS_PASSWORD" \
- -X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \
+ # Preconditions & secure auth (avoid exposing secrets in process list)
+ : "${ANTITHESIS_PASSWORD:?ANTITHESIS_PASSWORD is required}"
+ : "${ANTITHESIS_SLACK_REPORT_RECIPIENT:?ANTITHESIS_SLACK_REPORT_RECIPIENT is required}"
+ tmp_netrc="$(mktemp)"; trap 'rm -f "$tmp_netrc"' EXIT
+ printf 'machine formance.antithesis.com login formance password %s\n' "$ANTITHESIS_PASSWORD" > "$tmp_netrc"
+ chmod 600 "$tmp_netrc"
+ curl --fail --silent --show-error --retry 3 --retry-all-errors \
+ --netrc-file "$tmp_netrc" \
+ -H 'Content-Type: application/json' \
+ -X POST 'https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s' -d '{ \
📝 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.
curl --fail \ | |
--user "formance:$ANTITHESIS_PASSWORD" \ | |
-X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \ | |
"params": { \ | |
"custom.duration": "0.1", \ | |
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | |
"antithesis.config_image": "antithesis-config:k8s_test", \ | |
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | |
} \ | |
}' | |
# Preconditions & secure auth (avoid exposing secrets in process list) | |
: "${ANTITHESIS_PASSWORD:?ANTITHESIS_PASSWORD is required}" | |
: "${ANTITHESIS_SLACK_REPORT_RECIPIENT:?ANTITHESIS_SLACK_REPORT_RECIPIENT is required}" | |
tmp_netrc="$(mktemp)"; trap 'rm -f "$tmp_netrc"' EXIT | |
printf 'machine formance.antithesis.com login formance password %s\n' "$ANTITHESIS_PASSWORD" > "$tmp_netrc" | |
chmod 600 "$tmp_netrc" | |
curl --fail --silent --show-error --retry 3 --retry-all-errors \ | |
--netrc-file "$tmp_netrc" \ | |
-H 'Content-Type: application/json' \ | |
-X POST 'https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s' -d '{ \ | |
"params": { \ | |
"custom.duration": "0.1", \ | |
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | |
"antithesis.config_image": "antithesis-config:k8s_test", \ | |
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | |
} \ | |
}' |
🤖 Prompt for AI Agents
In test/antithesis/Justfile around lines 2 to 11, the curl invocation leaks the
ANTITHESIS_PASSWORD via --user, lacks a JSON content-type header, and has no
retry/resilience flags; remove the --user usage and instead rely on netrc by
instructing the environment or CI to create a .netrc entry for the host with the
Formance credentials and pass curl the netrc file option, add a Content-Type:
application/json header, and harden curl by adding --silent --show-error --fail
--location plus retry flags (e.g., --retry and --retry-delay) to improve
resiliency; ensure data remains JSON-encoded and that secret handling is
documented so the .netrc is created with correct permissions before running this
command.
curl --fail \ | ||
--user "formance:$ANTITHESIS_PASSWORD" \ | ||
-X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \ | ||
"params": { \ | ||
"custom.duration": "1", \ | ||
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | ||
"antithesis.config_image": "antithesis-config:k8s_test", \ | ||
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | ||
} \ | ||
}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Mirror the security and resiliency fixes in run-1h.
Apply the same netrc, JSON header, and curl hardening here.
- curl --fail \
- --user "formance:$ANTITHESIS_PASSWORD" \
- -X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \
+ : "${ANTITHESIS_PASSWORD:?ANTITHESIS_PASSWORD is required}"
+ : "${ANTITHESIS_SLACK_REPORT_RECIPIENT:?ANTITHESIS_SLACK_REPORT_RECIPIENT is required}"
+ tmp_netrc="$(mktemp)"; trap 'rm -f "$tmp_netrc"' EXIT
+ printf 'machine formance.antithesis.com login formance password %s\n' "$ANTITHESIS_PASSWORD" > "$tmp_netrc"
+ chmod 600 "$tmp_netrc"
+ curl --fail --silent --show-error --retry 3 --retry-all-errors \
+ --netrc-file "$tmp_netrc" \
+ -H 'Content-Type: application/json' \
+ -X POST 'https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s' -d '{ \
📝 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.
curl --fail \ | |
--user "formance:$ANTITHESIS_PASSWORD" \ | |
-X POST https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s -d '{ \ | |
"params": { \ | |
"custom.duration": "1", \ | |
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | |
"antithesis.config_image": "antithesis-config:k8s_test", \ | |
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | |
} \ | |
}' | |
: "${ANTITHESIS_PASSWORD:?ANTITHESIS_PASSWORD is required}" | |
: "${ANTITHESIS_SLACK_REPORT_RECIPIENT:?ANTITHESIS_SLACK_REPORT_RECIPIENT is required}" | |
tmp_netrc="$(mktemp)"; trap 'rm -f "$tmp_netrc"' EXIT | |
printf 'machine formance.antithesis.com login formance password %s\n' "$ANTITHESIS_PASSWORD" > "$tmp_netrc" | |
chmod 600 "$tmp_netrc" | |
curl --fail --silent --show-error --retry 3 --retry-all-errors \ | |
--netrc-file "$tmp_netrc" \ | |
-H 'Content-Type: application/json' \ | |
-X POST 'https://formance.antithesis.com/api/v1/launch_experiment/formance-k8s' -d '{ \ | |
"params": { \ | |
"custom.duration": "1", \ | |
"antithesis.report.recipients": "'"$ANTITHESIS_SLACK_REPORT_RECIPIENT"'", \ | |
"antithesis.config_image": "antithesis-config:k8s_test", \ | |
"antithesis.images": "workload:latest;docker.io/library/postgres:15-alpine;ghcr.io/formancehq/operator:v2.10.1;ghcr.io/formancehq/operator-utils:v2.0.14;ghcr.io/formancehq/gateway:v2.0.24;ghcr.io/formancehq/ledger-instrumented:k8s_test" \ | |
} \ | |
}' |
🤖 Prompt for AI Agents
In test/antithesis/Justfile around lines 14 to 23, the curl call lacks the same
security and resiliency flags used in run-1h; update the invocation to use a
netrc file for credentials (e.g. --netrc-file "$ANTITHESIS_NETRC" or --netrc as
appropriate), add an explicit JSON content-type header (-H "Content-Type:
application/json"), and harden curl by adding standard options such as --silent
--show-error --location --fail --retry N --retry-delay M --connect-timeout S
--max-time T (choose sensible values) so the request uses the netrc credentials,
sends proper JSON headers, follows redirects, surfaces errors, and
retries/timeouts for resilience.
import ( | ||
"context" | ||
"log" | ||
"os" | ||
|
||
"github.com/antithesishq/antithesis-sdk-go/assert" | ||
"github.com/formancehq/ledger/test/antithesis/internal" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/client-go/dynamic" | ||
|
||
"k8s.io/client-go/tools/clientcmd" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add required imports for patching, trimming, and timeouts.
Needed for the Patch and other fixes.
@@
import (
"context"
+ "encoding/json"
"log"
"os"
+ "strings"
+ "time"
@@
"k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
@@
+ "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
📝 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.
import ( | |
"context" | |
"log" | |
"os" | |
"github.com/antithesishq/antithesis-sdk-go/assert" | |
"github.com/formancehq/ledger/test/antithesis/internal" | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | |
"k8s.io/apimachinery/pkg/runtime/schema" | |
"k8s.io/client-go/dynamic" | |
"k8s.io/client-go/tools/clientcmd" | |
) | |
import ( | |
"context" | |
"encoding/json" | |
"log" | |
"os" | |
"strings" | |
"time" | |
"github.com/antithesishq/antithesis-sdk-go/assert" | |
"github.com/formancehq/ledger/test/antithesis/internal" | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | |
"k8s.io/apimachinery/pkg/runtime/schema" | |
"k8s.io/apimachinery/pkg/types" | |
"k8s.io/client-go/dynamic" | |
"k8s.io/client-go/rest" | |
"k8s.io/client-go/tools/clientcmd" | |
) |
🤖 Prompt for AI Agents
In test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go around
lines 3 to 17, the import block is missing packages required for
creating/patching resources, trimming strings, and handling timeouts; add the
necessary imports (k8s.io/apimachinery/pkg/types for PatchType, strings for
trimming, and time for timeouts) to the import list so the subsequent patch
operations, string trimming calls, and timeout logic compile and work as
intended.
latest_tag, err := os.ReadFile("/ledger_latest_tag") | ||
if err != nil { | ||
log.Fatal(err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Trim newline from LEDGER_LATEST_TAG and validate non-empty.
echo writes a trailing newline; passing it verbatim can break version parsing.
@@
- latest_tag, err := os.ReadFile("/ledger_latest_tag")
+ b, err := os.ReadFile("/ledger_latest_tag")
if err != nil {
log.Fatal(err)
}
+ tag := strings.TrimSpace(string(b))
+ if tag == "" {
+ log.Fatal("empty LEDGER_LATEST_TAG")
+ }
@@
- "version": string(latest_tag),
+ "version": tag,
Also applies to: 50-53
#!/bin/bash
# Locate the main.go file for anytime_version_upgrade command
find . -type f -path "*/anytime_version_upgrade/main.go"
#!/bin/bash
# Locate the main.go for the anytime_version_upgrade command
file=$(find . -type f -path "*/anytime_version_upgrade/main.go")
echo "Found: $file"
# Display imports and code around lines 1-60 (to inspect whether strings is imported and the ReadFile usage)
sed -n '1,60p' "$file"
echo "----"
# Display code around lines 45-80 (to see the assignment at 50-53)
sed -n '45,80p' "$file"
#!/bin/bash
# Locate the file under test
filepath=$(find . -type f -path "*/anytime_version_upgrade/main.go")
echo "Found file: $filepath"
# Show the first 60 lines to inspect imports and initial ReadFile usage
sed -n '1,60p' "$filepath"
# Show lines 45–80 to cover the later ReadFile handling (lines 50–53)
sed -n '45,80p' "$filepath"
Trim and validate LEDGER_LATEST_TAG
Ensure the value read from /ledger_latest_tag
has no trailing newline and isn’t empty:
@@ lines 21–24
- latest_tag, err := os.ReadFile("/ledger_latest_tag")
+ b, err := os.ReadFile("/ledger_latest_tag")
if err != nil {
log.Fatal(err)
}
+ tag := strings.TrimSpace(string(b))
+ if tag == "" {
+ log.Fatal("empty LEDGER_LATEST_TAG")
+ }
@@ lines 50–53
- "version": string(latest_tag),
+ "version": tag,
Apply the same change around lines 50–53.
🤖 Prompt for AI Agents
In test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go around
lines 21–24, the code reads /ledger_latest_tag without trimming or validating
the contents; trim whitespace/newlines from the read bytes, convert to a string,
and error if the resulting tag is empty; apply the same trimming and non-empty
validation to the similar read at lines 50–53 so neither location uses a raw
file value with trailing newlines or empty content.
test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,51 @@ | |||
VERSION 0.7 | |||
|
|||
FROM --platform=linux/amd64 golang:1.24.6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Pin base images to stable tags (ideally digests).
golang:1.24.6 may not exist; ubuntu:latest drifts and can break builds or introduce CVEs. Pin to a known minor and/or digest.
-FROM --platform=linux/amd64 golang:1.24.6
+FROM --platform=linux/amd64 golang:1.22
@@
- FROM --platform=linux/amd64 ubuntu:latest
+ FROM --platform=linux/amd64 ubuntu:22.04
If you have approved versions, use those or image digests.
Also applies to: 38-38
🌐 Web query:
Does the Docker image tag "golang:1.24.6" exist, and what is the latest stable Go minor release?
💡 Result:
Yes — the golang:1.24.6 tag exists (including variants like 1.24.6-alpine). [1][2]
The latest stable minor release is Go 1.25 (released August 12, 2025). [3]
Sources:
- Go release dashboard (go1.24.6 entry). [1]
- Docker golang images (1.24.6-alpine shown in registries/scans). [2]
- Official Go release notes / download (Go 1.25 release, Aug 12, 2025). [3]
Pin base images to immutable digests
golang:1.24.6
does exist, but relying on unpinned tags risks drift. Upgrade to the current minor release (Go 1.25, released August 12, 2025) and reference its digest—for example:
FROM --platform=linux/amd64 golang:1.25@sha256:<digest>
Likewise, replace ubuntu:latest
with a specific LTS version and its digest, e.g.:
FROM --platform=linux/amd64 ubuntu:22.04@sha256:<digest>
This ensures reproducible, stable builds.
🤖 Prompt for AI Agents
In test/antithesis/workload/Earthfile around line 3, the base image is
referenced by an unpinned tag ("golang:1.24.6"), which risks drift; update the
Go base to the current minor release (Go 1.25) and replace the tag with the
immutable image digest (e.g., golang:1.25@sha256:<digest>) and likewise replace
any ubuntu:latest usage with a specific LTS version and its digest (e.g.,
ubuntu:22.04@sha256:<digest>) so builds are reproducible; obtain the correct
sha256 digests from the official image registries and substitute them in the
FROM lines.
COPY +sources/src /src | ||
|
||
WORKDIR /src/test/antithesis/workload | ||
COPY --dir ../../../pkg/client+client/client ../../../pkg/client |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify COPY --dir rename semantics; simplify if not required.
The “+client/client” rename is easy to misread and may be unnecessary if the original layout is already pkg/client/client.
If not required, prefer:
-COPY --dir ../../../pkg/client+client/client ../../../pkg/client
+COPY --dir ../../../pkg/client ../../../pkg/client
If the rename is intentional, add a short comment explaining why.
🌐 Web query:
In Earthly, is "COPY --dir <src>+<newname> <dst>" the correct syntax to rename the root folder during copy?
💡 Result:
No. The correct forms put the artifact/dir as the source and the new name as the destination. For local dirs:
- COPY --dir test newname
For artifact form: - COPY --dir +target/path newname
Earthly's docs show COPY --dir and artifact refs as +target/artifact-path. [1][2]
Sources:
[1] Earthfile COPY docs (options & examples). [2] Importing / artifact reference examples.
Fix COPY --dir syntax
The current line
COPY --dir ../../../pkg/client+client/client ../../../pkg/client
misuses the +
operator—Earthly’s syntax is COPY --dir <src> <dest>
, with a leading +
only on artifact refs. For a local directory, use for example:
COPY --dir ../../../pkg/client pkg/client
If you meant to rename the root folder, use:
COPY --dir ../../../pkg/client client
Or, for an artifact import:
COPY --dir +target/path newname
Add a comment if any ref or rename is non-obvious.
🤖 Prompt for AI Agents
In test/antithesis/workload/Earthfile around line 24, the COPY --dir invocation
incorrectly uses a '+' inside the source path
("../../../pkg/client+client/client"), violating Earthly syntax; fix by changing
the line to use a plain local source and desired destination (for example COPY
--dir ../../../pkg/client pkg/client or COPY --dir ../../..//pkg/client client
if you intended to rename the root), or if you intended to import an artifact
use the leading plus form (COPY --dir +target/path newname); also add a brief
comment explaining any non-obvious ref or rename.
ARG --required ANTITHESIS_REPOSITORY | ||
ARG --required LEDGER_LATEST_TAG | ||
|
||
RUN echo ${LEDGER_LATEST_TAG} > /ledger_latest_tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid trailing newline in /ledger_latest_tag.
echo appends “\n”; use printf for exact content.
-RUN echo ${LEDGER_LATEST_TAG} > /ledger_latest_tag
+RUN printf %s "${LEDGER_LATEST_TAG}" > /ledger_latest_tag
📝 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.
RUN echo ${LEDGER_LATEST_TAG} > /ledger_latest_tag | |
RUN printf %s "${LEDGER_LATEST_TAG}" > /ledger_latest_tag |
🤖 Prompt for AI Agents
In test/antithesis/workload/Earthfile around line 49, the current RUN uses echo
which appends a trailing newline to /ledger_latest_tag; replace the echo with a
printf invocation that writes the LEDGER_LATEST_TAG value without adding a
newline (use printf with a %s format and the variable, redirecting output to
/ledger_latest_tag) to ensure the file contains the exact tag and no trailing
newline.
|
||
RUN echo ${LEDGER_LATEST_TAG} > /ledger_latest_tag | ||
|
||
SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Also push a content-addressable tag (e.g., the version).
latest is mutable; add an immutable tag for traceability.
-SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest
+SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest
+SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:${LEDGER_LATEST_TAG}
📝 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.
SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest | |
SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest | |
SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:${LEDGER_LATEST_TAG} |
🤖 Prompt for AI Agents
In test/antithesis/workload/Earthfile around line 51, the image is only pushed
with the mutable tag "latest"; add an additional push of an immutable,
content-addressable tag (for example a version or commit SHA) so the image is
traceable. Modify the Earthfile to produce and push a second tag such as
${ANTITHESIS_REPOSITORY}/workload:${ANTITHESIS_VERSION} (or derive from git
commit SHA) alongside the existing latest push — ensure the image is tagged with
that immutable tag and pushed (or saved) as well so both latest and the
content-addressable tag exist in the registry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
test/antithesis/image/Earthfile (1)
42-42
: Version the image tag instead of pushing only :latestParameterize the tag for traceability (commit SHA, tag, or build number).
-build: +build: + ARG IMAGE_TAG?=latest ... - SAVE IMAGE --push ghcr.io/formancehq/ledger-instrumented:latest + SAVE IMAGE --push ghcr.io/formancehq/ledger-instrumented:${IMAGE_TAG}
🧹 Nitpick comments (3)
test/antithesis/image/Earthfile (3)
24-24
: Make build output more deterministicAdd -trimpath and -buildvcs=false; keeps debug info for symbols while removing host paths/VCS metadata.
- RUN go build -race -o ledger + RUN go build -race -trimpath -buildvcs=false -o ledger
29-41
: Consider running as non-root in the runtime imageDrop privileges for better isolation.
COPY (+compile/ledger) /bin/ledger COPY (+compile/symbols) /symbols COPY entrypoint.sh /bin/entrypoint.sh - RUN chmod 777 /bin/entrypoint.sh + RUN chmod 0755 /bin/entrypoint.sh \ + && useradd --system --no-create-home --shell /usr/sbin/nologin ledger + USER ledger
7-8
: Deduplicate cache directivesYou define go caches globally and again in compile; keep one to reduce noise.
- CACHE --sharing=shared --id go-mod-cache /go/pkg/mod - CACHE --sharing=shared --id go-cache /root/.cache/go-buildAlso applies to: 12-13
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
📒 Files selected for processing (1)
test/antithesis/image/Earthfile
(1 hunks)
🔇 Additional comments (3)
test/antithesis/image/Earthfile (3)
19-28
: LGTM: instrumentation + artifact handoff look coherentThe instrument → build → symbols flow is consistent with Antithesis usage.
15-15
: No changes required
The Earthfile at../../..
defines asources
target that exports/src
.
39-41
: Ensureledger serve
binds to port 8080
In test/antithesis/image/entrypoint.sh, invokeledger serve --addr :8080
to matchEXPOSE 8080
, or update the EXPOSE directive to the actual default listen port.
CACHE --sharing=shared --id go-cache /root/.cache/go-build | ||
|
||
compile: | ||
FROM --platform=linux/amd64 golang:1.24.6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Confirm and pin Go toolchain version
1.24.6 may be behind the latest patch/minor. Please confirm current stable and pin accordingly for reproducibility.
🌐 Web query:
What is the latest stable Go release (minor and patch) as of today?
💡 Result:
The latest stable Go release as of today (September 10, 2025) is Go 1.25.1. [1][2]
Sources:
- Official Go VERSION file (go1.25.1). [1]
- Go announcement: "Go 1.25.1 and Go 1.24.7 are released" (Sep 3, 2025). [2]
Pin Go toolchain to latest stable version (1.25.1)
In test/antithesis/image/Earthfile line 11, update:
- FROM --platform=linux/amd64 golang:1.24.6
+ FROM --platform=linux/amd64 golang:1.25.1
📝 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.
FROM --platform=linux/amd64 golang:1.24.6 | |
FROM --platform=linux/amd64 golang:1.25.1 |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around line 11, the Docker base image is
pinned to golang:1.24.6; update the FROM line to use the latest stable Go
toolchain by replacing golang:1.24.6 with golang:1.25.1 (preserve the
--platform=linux/amd64 flag if needed) so the image builds with Go 1.25.1.
CACHE --sharing=shared --id go-cache /root/.cache/go-build | ||
|
||
COPY ../../..+sources/src /src | ||
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid @latest for the instrumentor; pin the version
Use an ARG and pin to a known tag/commit to keep builds reproducible.
compile:
+ ARG ANTITHESIS_GO_INSTRUMENTOR_VERSION?=v0.0.0
- RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest
+ RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@${ANTITHESIS_GO_INSTRUMENTOR_VERSION}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around line 16, the RUN uses @latest for
installing the instrumentor which makes builds non-reproducible; add an ARG
(e.g., INSTRUMENTOR_VERSION) with a pinned tag or commit hash (set a sensible
default), then change the RUN line to reference that ARG (e.g.,
github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@${INSTRUMENTOR_VERSION});
commit the Dockerfile/Earthfile change so builds can be reproduced by overriding
the ARG if needed.
FROM --platform=linux/amd64 ubuntu:latest | ||
RUN apt-get update -y && apt-get install -y postgresql-client curl | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Pin runtime base and reduce image size
Avoid ubuntu:latest; pin LTS and clean apt cache. Also prefer no-install-recommends.
- FROM --platform=linux/amd64 ubuntu:latest
- RUN apt-get update -y && apt-get install -y postgresql-client curl
+ FROM --platform=linux/amd64 ubuntu:24.04
+ RUN apt-get update -y \
+ && apt-get install -y --no-install-recommends postgresql-client curl ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
📝 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.
FROM --platform=linux/amd64 ubuntu:latest | |
RUN apt-get update -y && apt-get install -y postgresql-client curl | |
FROM --platform=linux/amd64 ubuntu:24.04 | |
RUN apt-get update -y \ | |
&& apt-get install -y --no-install-recommends postgresql-client curl ca-certificates \ | |
&& rm -rf /var/lib/apt/lists/* |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around lines 30–32, the Dockerfile uses
ubuntu:latest and installs packages without cleaning caches; change the base to
a pinned LTS (e.g., ubuntu:22.04) and install packages with
--no-install-recommends, combine commands, and remove apt lists to reduce image
size: use FROM --platform=linux/amd64 ubuntu:22.04 and replace the RUN with a
single line that runs apt-get update && apt-get install -y
--no-install-recommends postgresql-client curl && apt-get clean && rm -rf
/var/lib/apt/lists/*.
COPY (+compile/symbols) /symbols | ||
COPY entrypoint.sh /bin/entrypoint.sh | ||
|
||
RUN chmod 777 /bin/entrypoint.sh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chmod 777 is over-permissive
Use 0755 to avoid granting write to group/others.
- RUN chmod 777 /bin/entrypoint.sh
+ RUN chmod 0755 /bin/entrypoint.sh
📝 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.
RUN chmod 777 /bin/entrypoint.sh | |
RUN chmod 0755 /bin/entrypoint.sh |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around line 37, the Dockerfile uses an
over-permissive file mode (chmod 777) on /bin/entrypoint.sh; change that command
to set the file mode to 0755 so the owner retains write access while
group/others get read+execute only, and keep the rest of the line and file
unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
test/antithesis/image/Earthfile (1)
42-42
: Version the pushed image tag (avoid :latest)Use a parameterized, immutable tag for traceability (commit SHA, tag, or timestamp). This was raised earlier; repeating here for this file.
Apply:
- SAVE IMAGE --push ghcr.io/formancehq/ledger-instrumented:latest + ARG IMAGE_TAG?=$(git rev-parse --short HEAD) + SAVE IMAGE --push --no-manifest-list ghcr.io/formancehq/ledger-instrumented:${IMAGE_TAG}
🧹 Nitpick comments (2)
test/antithesis/image/Earthfile (2)
7-8
: Deduplicate cache declarationsCaches are declared both at top-level and inside the compile target. Keep the per-target ones and remove the top-level to reduce noise.
Apply:
-CACHE --sharing=shared --id go-mod-cache /go/pkg/mod -CACHE --sharing=shared --id go-cache /root/.cache/go-buildAlso applies to: 12-13
39-40
: Add a container healthcheckExpose a simple readiness probe so orchestrators can detect unhealthy containers.
Apply:
ENTRYPOINT ["/bin/entrypoint.sh"] EXPOSE 8080 + HEALTHCHECK --interval=15s --timeout=3s --retries=5 CMD curl -fsS http://127.0.0.1:8080/_health || exit 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
.github/workflows/antithesis.yml
is excluded by!**/*.yml
📒 Files selected for processing (1)
test/antithesis/image/Earthfile
(1 hunks)
🔇 Additional comments (2)
test/antithesis/image/Earthfile (2)
11-11
: Good upgrade: Go toolchain pinned to 1.24.6Pinning to a concrete patch release fixes the previous concern about using a non-existent/unstable tag. LGTM.
24-25
: Builder/runner libc alignment with -race-race binaries depend on glibc. Mixing a Debian-based builder with an Ubuntu runtime is usually fine if the runtime glibc is newer, but it can bite in some environments. Consider aligning distro families or explicitly pinning both to known-compatible images.
Would you like me to check the current glibc versions for your selected tags and confirm compatibility?
Also applies to: 30-30
CACHE --sharing=shared --id go-cache /root/.cache/go-build | ||
|
||
COPY ../../..+sources/src /src | ||
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Pin the instrumentor version for reproducible builds
Using @latest makes builds non-deterministic and can break unexpectedly. Pin a tag/commit and expose it as an ARG.
Apply:
compile:
FROM --platform=linux/amd64 golang:1.24.6
@@
- RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest
+ ARG INSTRUMENTOR_VERSION=v0.0.0 # set to known-good tag/commit
+ RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@${INSTRUMENTOR_VERSION}
📝 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.
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest | |
compile: | |
FROM --platform=linux/amd64 golang:1.24.6 | |
ARG INSTRUMENTOR_VERSION=v0.0.0 # set to known-good tag/commit | |
RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@${INSTRUMENTOR_VERSION} |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around line 16, the Dockerfile uses "go
install ...@latest" which makes builds non-deterministic; change this to accept
a build ARG for the instrumentor version (e.g., INSTRUMENTOR_VERSION) and
replace @latest with that pinned version (defaulting to a specific tag/commit),
so callers can override the ARG but the image builds reproducibly by default;
update the Earthfile to declare the ARG and use it in the RUN line and document
the new ARG in the file comments or build instructions.
build: | ||
FROM --platform=linux/amd64 ubuntu:latest | ||
RUN apt-get update -y && apt-get install -y postgresql-client curl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid floating base and improve apt hygiene
Pin the runtime base and harden the apt install to reduce image size and supply CA certs.
Apply:
-build:
- FROM --platform=linux/amd64 ubuntu:latest
- RUN apt-get update -y && apt-get install -y postgresql-client curl
+build:
+ FROM --platform=linux/amd64 ubuntu:24.04
+ RUN apt-get update -y \
+ && apt-get install -y --no-install-recommends postgresql-client curl ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
📝 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.
build: | |
FROM --platform=linux/amd64 ubuntu:latest | |
RUN apt-get update -y && apt-get install -y postgresql-client curl | |
build: | |
FROM --platform=linux/amd64 ubuntu:24.04 | |
RUN apt-get update -y \ | |
&& apt-get install -y --no-install-recommends postgresql-client curl ca-certificates \ | |
&& rm -rf /var/lib/apt/lists/* |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around lines 29 to 31, the Dockerfile uses a
floating base image and a basic apt install command; update it to pin a specific
Ubuntu LTS tag (e.g., ubuntu:24.04 or another pinned digest/tag) and harden the
apt invocation by installing ca-certificates and postgresql-client with apt-get
install --no-install-recommends, run apt-get update && apt-get install in one
layer, and then clean up apt caches (apt-get clean and remove
/var/lib/apt/lists/*) to reduce image size and ensure CA certs are present.
RUN chmod 777 /bin/entrypoint.sh | ||
|
||
ENTRYPOINT ["/bin/entrypoint.sh"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Drop 0777 and run as non-root
0777 is unnecessary and weakens container security. Make the script executable (0755) and run the image as a non-root user.
Apply:
- RUN chmod 777 /bin/entrypoint.sh
+ RUN chmod 0755 /bin/entrypoint.sh
+ # create unprivileged user
+ RUN useradd -r -u 65532 -g nogroup -d /nonexistent -s /usr/sbin/nologin ledger
+ USER 65532:65532
📝 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.
RUN chmod 777 /bin/entrypoint.sh | |
ENTRYPOINT ["/bin/entrypoint.sh"] | |
RUN chmod 0755 /bin/entrypoint.sh | |
# create unprivileged user | |
RUN useradd -r -u 65532 -g nogroup -d /nonexistent -s /usr/sbin/nologin ledger | |
USER 65532:65532 | |
ENTRYPOINT ["/bin/entrypoint.sh"] |
🤖 Prompt for AI Agents
In test/antithesis/image/Earthfile around lines 37-39 the Dockerfile currently
sets chmod 777 on /bin/entrypoint.sh and leaves the container running as root;
change the permission to 0755, create a non-root user (e.g., groupadd/useradd or
adduser), chown the entrypoint to that user, and add a USER directive before
ENTRYPOINT so the container runs as that non-root user; ensure the entrypoint
remains executable and any required file ownerships are adjusted for the new
user.
No description provided.