Feature/builds - #58
Conversation
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (35)
📝 WalkthroughWalkthroughThe change adds configurable build numbers, Docker image promotion, scheduler execution, CLI and UI management, persisted publish results, and pipeline image handling. ChangesBuild numbers and management
Docker publishing
Pipeline integration
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Pipeline
participant BuildImage
participant TestSteps
participant DockerPublish
participant Registry
Pipeline->>BuildImage: build numbered test image
BuildImage->>TestSteps: provide FORGE_IMAGE
TestSteps->>BuildImage: pull test image
Pipeline->>DockerPublish: submit promotion job
DockerPublish->>Registry: fetch and promote manifest
DockerPublish->>Registry: delete source tag
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 20
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.forge/main.yml:
- Line 18: Update the secrets flow-style list in the YAML configuration to
remove the spaces immediately inside its brackets, preserving the existing
REGISTRY_USERNAME and REGISTRY_PASSWORD entries.
In @.forge/pipeline.yml:
- Around line 81-83: Update the Docker promotion configuration around the source
and tags entries to use a Docker-tag-safe normalized form of env.FORGE_BRANCH,
replacing the raw branch value while preserving the existing build-number
source.
In @.forge/templates/docker-build.yml:
- Line 4: Remove the inner spaces from all affected flow-style YAML sequences:
update .forge/templates/docker-build.yml lines 4-4, and .forge/pipeline.yml
lines 32-32, 43-43, 56-56, 76-76, and 77-77. Preserve the existing sequence
values while formatting each list without spaces immediately inside its
brackets.
In `@cmd/forge/remote.go`:
- Around line 310-318: Update the Docker publish output around
DockerPublishResult to always display both SourceDigest and SourceDeleted,
alongside the existing tags-applied information. Remove the conditional omission
so the false deletion state is explicitly shown, while preserving the warning
output.
- Around line 316-317: Sanitize each warning in the r.Warnings loop before
passing it to fmt.Printf, removing or escaping embedded control characters and
newlines while preserving readable text. Update the warning-output logic in the
DeleteTag response handling without changing warning collection or other output
behavior.
In `@docs/Pipeline-Reference.md`:
- Line 515: Update the Authentication section’s condition for omitting
REGISTRY_USERNAME and REGISTRY_PASSWORD: credentials are optional only when the
registry permits all required docker_publish operations, including image push
and any optional deletion, not merely anonymous pulls.
In `@internal/compiler/compiler.go`:
- Around line 522-527: Deep-copy cloned.DockerPublish.Tags before the matrix
interpolation loop so each matrix combination operates on an independent slice
rather than mutating the shared js.DockerPublish.Tags backing array. Update the
compiler flow around the DockerPublish cloning block and add a regression test
covering a target tag containing a ${{ matrix.* }} expression, verifying every
matrix combination receives its own interpolated tag.
In `@internal/registryutil/registry.go`:
- Around line 168-188: Update Client.DeleteTag in
internal/registryutil/registry.go to delete the source tag by name using the
registry’s tag-specific endpoint, rather than deleting by manifest digest;
return ErrDeletionUnsupported when tag deletion is unavailable so callers retain
the source tag and record a warning. Update the tag-to-digest alias behavior in
internal/registryutil/registry_test.go lines 105-110. Remove delete_source: true
from .forge/main.yml line 26 and docs/Pipeline-Reference.md lines 499-517 until
safe cleanup is supported.
- Around line 63-70: Require HTTPS for all credential-bearing requests in
fetchToken and the client created by NewClient: reject non-HTTPS parsed realms
before sending Basic credentials, and configure the shared HTTP client to reject
redirects that are non-HTTPS (including HTTPS-to-HTTP transitions). Add
regression tests covering both a non-HTTPS realm and a redirect to HTTP.
In `@internal/scheduler/buildnumber_handlers.go`:
- Around line 66-69: Update the handler containing the SetBuildFormat call to
validate req.Format before attempting persistence, returning 400 for invalid
format values; then map SetBuildFormat failures to HTTP 500, matching
handleSetVersion and handleSetVersionTagFilter. Keep SetBuildFormat’s internal
Parse validation unchanged so direct callers remain protected.
In `@internal/scheduler/server.go`:
- Around line 1011-1018: Update the docker_publish drain loop around
LeaseDockerPublishJob and executeDockerPublish to bound concurrent workers with
a semaphore, stop leasing when ctx is canceled, and track all launched
goroutines with a sync.WaitGroup. Ensure shutdown waits for tracked workers
before Start returns, and propagate ctx through executeDockerPublish into the
registryutil operations so in-flight promotions are canceled.
- Around line 1118-1133: Replace the destructive `client.DeleteTag(repository,
manifest.Digest)` call in the `DeleteSource` cleanup block with the interim
unsupported behavior: do not issue manifest deletion, append a warning
explaining that source-tag deletion is unsupported because deleting the digest
would remove promoted tags, and log that warning without failing promotion.
Remove any now-unused `errors` or `registryutil.ErrDeletionUnsupported` imports.
In `@internal/scheduler/store.go`:
- Around line 306-318: The build-format read path drops the persisted version
tag filter. In internal/scheduler/store.go:306-318, update loadBuildFormat,
getBuildFormat, GetBuildFormat, and the assignBuildNumber call site around line
246 to select, return, and propagate tagFilter, returning an empty value in
no-row and error branches; in internal/scheduler/buildnumber_handlers.go:35-44,
receive the value from GetBuildFormat and assign it to
api.BuildFormatInfo.VersionTagFilter.
- Around line 280-294: Correct the misleading locking comment near
incrementBuildCounter/assignBuildNumber to state that the counter upsert
acquires the scope row lock and holds it until transaction commit, covering the
remainder of SubmitRun. Do not change the counter behavior or transaction
boundaries; document that this introduces contention across concurrent
submissions for the same project, pipeline, and version scope.
In `@ui/src/lib/buildNumberPreview.ts`:
- Around line 24-25: Update the counter-token parsing near pad and the format
handling at line 44 to consume the complete width token, rejecting malformed
values such as “8junk” or “8:9”. Validate the parsed width against the server’s
bounded width range before passing it to pad, so oversized values cannot trigger
enormous padding.
In `@ui/src/lib/components/BuildSettings.svelte`:
- Around line 26-45: Update the BuildSettings load/state flow around load() to
capture the trimmed requested pipeline and a load generation, invalidating
loaded editor state whenever the input changes. Apply responses only when both
the generation and requested pipeline still match the current input; ignore
stale responses and keep loaded false for null results so save actions at the
affected handlers cannot submit another pipeline’s values.
In `@ui/src/lib/components/DAG.svelte`:
- Around line 144-149: The run list currently omits build_number outside
DAG.svelte. Extend the /api/v1/runs query and RunSummary/list response, add
build_number to the UI Run type, and render it in Sidebar.svelte alongside the
existing run metadata; use the list value directly and do not substitute
RunStatus.BuildNumber, which belongs to the separate polling endpoint.
In `@ui/src/lib/components/DetailsPanel.svelte`:
- Around line 240-243: Update the Publish tab in DetailsPanel and the
DockerPublishCard component to accept and render the selected job status
alongside config and result. Pass $selectedJob.status from the publish-tab call
site, and ensure queued, running, and early-failed jobs display that status even
when docker_publish_result is absent.
- Around line 153-158: Update the selected-job tab state in DetailsPanel so
activeTab resets to logs whenever the job has neither docker_publish_result nor
docker_publish. Keep the Publish button visibility condition and existing
publish behavior unchanged, and ensure the reset occurs when selection changes
so the Publish view cannot render for unavailable jobs.
In `@ui/src/lib/components/DockerPublishCard.svelte`:
- Around line 13-22: Update DockerPublishCard’s displayed registry, repository,
and source values so they are not presented as effective publish values when
they still contain unexpanded build-variable tokens. Prefer using resolved
values persisted in DockerPublishResult; if only configured values are
available, explicitly label the fields as configured values rather than changing
scheduler interpolation behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d3e3db07-60e8-42de-824d-e775f153d9f4
⛔ Files ignored due to path filters (1)
ui/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (34)
.forge/main.yml.forge/pipeline.yml.forge/scripts/integration-tests.sh.forge/scripts/unit-tests.sh.forge/templates/docker-build.ymlcmd/forge/helpers.gocmd/forge/local.gocmd/forge/management.gocmd/forge/remote.godocs/Pipeline-Reference.mdinternal/api/types.gointernal/buildnumber/format.gointernal/buildnumber/format_test.gointernal/compiler/compiler.gointernal/compiler/lint.gointernal/pipeline/types.gointernal/registryutil/registry.gointernal/registryutil/registry_test.gointernal/scheduler/buildnumber_handlers.gointernal/scheduler/server.gointernal/scheduler/store.gointernal/store/db.gointernal/store/models.gotests/integration/suite_test.goui/src/lib/api.tsui/src/lib/buildNumberPreview.tsui/src/lib/components/BuildSettings.svelteui/src/lib/components/DAG.svelteui/src/lib/components/DAGNodes.svelteui/src/lib/components/DetailsPanel.svelteui/src/lib/components/DockerPublishCard.svelteui/src/lib/components/EditorDAG.svelteui/src/lib/components/PipelineEditor.svelteui/src/lib/components/ProjectsView.svelte
| {#if config} | ||
| <span class="pc-target">{config.registry}/{config.repository}</span> | ||
| {/if} | ||
| </div> | ||
|
|
||
| {#if config} | ||
| <div class="pc-source"> | ||
| <span class="pc-label">Source</span> | ||
| <code>{config.source}</code> | ||
| </div> |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Do not label unexpanded templates as effective Docker publish values.
The component displays config.registry, config.repository, and config.source directly. internal/scheduler/server.go Lines 1034-1145 interpolates these fields before execution. With build-variable tokens, the card can show ${FORGE_IMAGE} while source_digest and tags_applied describe the resolved tag. Persist resolved values in DockerPublishResult, or label these fields as configured values.
Minimal safe fix
- <span class="pc-label">Source</span>
+ <span class="pc-label">Configured source</span>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ui/src/lib/components/DockerPublishCard.svelte` around lines 13 - 22, Update
DockerPublishCard’s displayed registry, repository, and source values so they
are not presented as effective publish values when they still contain unexpanded
build-variable tokens. Prefer using resolved values persisted in
DockerPublishResult; if only configured values are available, explicitly label
the fields as configured values rather than changing scheduler interpolation
behavior.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/scheduler/webhook.go`:
- Around line 372-376: Add regression coverage around SubmitRun and the webhook
step conversion to verify both build variables are injected after expansion and
before job insertion. Cover webhook, rerun, child-pipeline, and matrix run
paths, and assert the resulting variables on each generated step while
preserving the existing ToAPIStep(nil) behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e2e7be54-7ae1-4acb-a56a-da6d5773d735
📒 Files selected for processing (1)
internal/scheduler/webhook.go
| steps := make([]api.StepDef, len(pipeline.Steps)) | ||
| for i, s := range pipeline.Steps { | ||
| steps[i] = s.ToAPIStep(nil) | ||
| injectSCMMetadata(steps[i].Env, meta) | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
fd -e go -e ts -e svelte . -x rg -n -C 8 \
'FORGE_BUILD_(NUMBER|COUNTER)|buildNumber|buildCounter|ToAPIStep\(|SubmitRun\(' {}Repository: JBraunsmaJr/Forge
Length of output: 28273
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- candidate files ---'
fd -e go . | rg '(internal/(scheduler|api|compiler)|webhook|store|run)' | head -80
echo '--- ToAPIStep implementation and callers ---'
rg -n -C 18 'func \(s \*Step\) ToAPIStep|ToAPIStep\(' --glob '*.go' .
echo '--- SubmitRun stamping and expansion ---'
rg -n -C 28 'func \(s \*Store\) SubmitRun|FORGE_BUILD_NUMBER|FORGE_BUILD_COUNTER|expand|matrix' --glob '*.go' internal
echo '--- webhook submission path ---'
sed -n '330,455p' internal/scheduler/webhook.go
echo '--- rerun and child submission parameters ---'
rg -n -C 24 'func rerunParams|ParentRunID|ParentJobID|SubmitRun\(' --glob '*.go' internalRepository: JBraunsmaJr/Forge
Length of output: 50374
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
files = list(Path(".").rglob("*.go"))
needles = ("FORGE_BUILD_NUMBER", "FORGE_BUILD_COUNTER", "func (s *Store) SubmitRun",
"func rerunParams", "ParentRunID", "ParentJobID", "ToAPIStep(")
for path in files:
text = path.read_text(errors="replace")
if any(n in text for n in needles):
lines = text.splitlines()
print(f"--- {path} ---")
for i, line in enumerate(lines):
if any(n in line for n in needles):
lo, hi = max(0, i-3), min(len(lines), i+4)
print(f"{lo+1}-{hi}")
print("\n".join(f"{j+1}: {lines[j]}" for j in range(lo, hi)))
PYRepository: JBraunsmaJr/Forge
Length of output: 16730
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- build-number and environment tests ---'
rg -n -C 12 \
'FORGE_BUILD_(NUMBER|COUNTER)|BuildNumber|BuildCounterValue|ParentRunID|ParentJobID|matrix|webhook' \
internal/scheduler/*_test.go internal/agent/*_test.go internal/pipeline/*_test.go
echo '--- webhook submission tests ---'
sed -n '1,260p' internal/scheduler/webhook_submission_test.go
echo '--- webhook handler submission call ---'
sed -n '405,455p' internal/scheduler/webhook.go
echo '--- rerun parameter construction ---'
sed -n '2280,2320p' internal/scheduler/server.go
echo '--- child-pipeline submission call ---'
sed -n '2570,2620p' internal/agent/agent.goRepository: JBraunsmaJr/Forge
Length of output: 9355
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
checks = {
"submit_stamps_number": ("internal/scheduler/store.go", 'step.Env["FORGE_BUILD_NUMBER"] = buildNumber'),
"submit_stamps_counter": ("internal/scheduler/store.go", 'step.Env["FORGE_BUILD_COUNTER"] = strconv.FormatInt(buildCounterValue, 10)'),
"submit_expands_before_stamping": ("internal/scheduler/store.go", "steps = expandedSteps"),
"webhook_submits_steps": ("internal/scheduler/webhook.go", "Steps: steps"),
"rerun_sets_parent": ("internal/scheduler/server.go", "ParentRunID: parentRunID"),
"child_sets_parent_run": ("internal/agent/agent.go", "ParentRunID: spec.RunID"),
"child_sets_parent_job": ("internal/agent/agent.go", "ParentJobID: spec.JobID"),
}
for name, (filename, needle) in checks.items():
text = Path(filename).read_text()
print(f"{name}: {'present' if needle in text else 'MISSING'}")
store = Path("internal/scheduler/store.go").read_text()
expand_pos = store.find("steps = expandedSteps")
stamp_pos = store.find('step.Env["FORGE_BUILD_NUMBER"] = buildNumber')
print("expansion_precedes_stamping:", expand_pos >= 0 and stamp_pos > expand_pos)
test_text = "\n".join(p.read_text(errors="replace") for p in Path("internal").rglob("*_test.go"))
for term in ("FORGE_BUILD_NUMBER", "FORGE_BUILD_COUNTER"):
print(f"tests_mention_{term}: {term in test_text}")
PYRepository: JBraunsmaJr/Forge
Length of output: 491
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- webhook SubmitRun call ---'
sed -n '405,445p' internal/scheduler/webhook.go
echo '--- SubmitRun job serialization ---'
sed -n '107,165p' internal/scheduler/store.go
echo '--- ToAPIStep environment merge ---'
sed -n '130,205p' internal/pipeline/types.go
echo '--- all scheduler test names ---'
rg -n '^func Test' internal/scheduler/*_test.go
echo '--- build-variable assertions in tests ---'
rg -n -i 'forge[_-]?build|build[_-]?counter|build[_-]?number' --glob '*_test.go' . || trueRepository: JBraunsmaJr/Forge
Length of output: 7982
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
webhook = Path("internal/scheduler/webhook.go").read_text()
store = Path("internal/scheduler/store.go").read_text()
submit_start = webhook.find("s.store.SubmitRun(")
submit_end = webhook.find("\n\t})", submit_start)
print("webhook_submit_call_found:", submit_start >= 0)
print("webhook_passes_steps:", submit_start >= 0 and "steps" in webhook[submit_start:submit_end])
stamp = store.find('step.Env["FORGE_BUILD_NUMBER"] = buildNumber')
job_insert = store.find("INSERT INTO jobs")
expand = store.find("steps = expandedSteps")
print("expansion_before_stamp:", 0 <= expand < stamp)
print("stamp_before_job_insert:", 0 <= stamp < job_insert)
tests = "\n".join(p.read_text(errors="replace") for p in Path(".").rglob("*_test.go"))
for path, term in [
("webhook_tests", "SubmitWebhookRun"),
("rerun_tests", "rerun"),
("child_pipeline_tests", "ParentJobID"),
("matrix_tests", "Matrix"),
]:
print(f"{path}:", term in tests)
print("build_env_assertions:", "FORGE_BUILD_NUMBER" in tests or "FORGE_BUILD_COUNTER" in tests)
PYRepository: JBraunsmaJr/Forge
Length of output: 386
Add regression coverage for build-variable injection. SubmitRun stamps both variables after expansion and before job insertion, so ToAPIStep(nil) is safe. Assert the variables for webhook, rerun, child-pipeline, and matrix runs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/scheduler/webhook.go` around lines 372 - 376, Add regression
coverage around SubmitRun and the webhook step conversion to verify both build
variables are injected after expansion and before job insertion. Cover webhook,
rerun, child-pipeline, and matrix run paths, and assert the resulting variables
on each generated step while preserving the existing ToAPIStep(nil) behavior.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.forge/pipeline.yml (1)
68-74: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winSecurity Misconfiguration (CWE-732): Incorrect Permission Assignment for Critical Resource
Reachability: External · Exploitability: Moderate
Restrict registry promotion to trusted refs.
The GitHub webhook submits pull-request commits for execution.
!branch(main)allows those refs to reach credentialeddocker_publish, which can promote the image and delete its source tag. Gate promotion on trusted events or refs, or withhold registry secrets from untrusted refs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.forge/pipeline.yml around lines 68 - 74, Update the promote-on-branch docker_publish step so credentialed registry promotion cannot run for pull-request or otherwise untrusted refs. Gate the step using the pipeline’s trusted event/ref condition, or ensure REGISTRY_USERNAME and REGISTRY_PASSWORD are withheld on untrusted executions, while preserving promotion for approved trusted refs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.forge/pipeline.yml:
- Line 32: Update the depends_on declaration in the pipeline configuration to
use YAMLlint-compliant flow-sequence spacing by removing the spaces inside the
brackets around build-ui, while preserving the dependency value.
- Line 35: Update the unit-tests and integration-tests steps to set FORGE_IMAGE
to the resolved image reference
ghcr.io/jbraunsmajr/forge/forge:test-${FORGE_BUILD_NUMBER}, matching the image
used by the build and push commands and preventing either step from building a
fallback image.
- Line 35: Validate every rendered Docker tag, including the test- prefixed tag,
against Docker tag constraints before build-number assignment and promotion; do
not rely solely on buildnumber.Parse token validation. Reject slash-containing
formats such as release/%counter% and renders exceeding 128 bytes, while
preserving valid Calendar and SemVer formats and the existing requirement that
normal configured renders include %counter%.
---
Outside diff comments:
In @.forge/pipeline.yml:
- Around line 68-74: Update the promote-on-branch docker_publish step so
credentialed registry promotion cannot run for pull-request or otherwise
untrusted refs. Gate the step using the pipeline’s trusted event/ref condition,
or ensure REGISTRY_USERNAME and REGISTRY_PASSWORD are withheld on untrusted
executions, while preserving promotion for approved trusted refs.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f550ea57-460a-47d6-a52a-64b425080efd
📒 Files selected for processing (1)
.forge/pipeline.yml
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.forge/scripts/integration-tests.sh:
- Around line 8-13: The FORGE_IMAGE derivation currently overrides externally
supplied images and mishandles an absent FORGE_BUILD_NUMBER. In
.forge/scripts/integration-tests.sh lines 8-13 and .forge/scripts/unit-tests.sh
lines 6-8, update the conditional export to use safe defaults for both
variables, derive the image only when FORGE_IMAGE is unset and
FORGE_BUILD_NUMBER is available, and otherwise leave FORGE_IMAGE unset.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4ad6a56e-7eeb-4f37-9aea-8fded8755978
📒 Files selected for processing (3)
.forge/scripts/integration-tests.sh.forge/scripts/unit-tests.shtests/integration/suite_test.go
Closes #57
Summary by CodeRabbit